Возвращает фактический размер JComponent, как показано - PullRequest
1 голос
/ 14 августа 2010

Добрый вечер,

Я хотел бы знать, как получить размер JComponent после того, как он был размечен с помощью LayoutManager. Я читал, что это возможно, если вы просто вызываете dolayout (), validate () или setVisible () заранее. Однако я не могу заставить его работать в моем коде.

Причина, по которой я хотел бы знать это, состоит в том, чтобы добавлять столько компонентов, сколько будет соответствовать размеру набора фрейма, не зная заранее размера компонентов. Вызов validate () не устанавливает размер компонентов в этом примере кода. Любые идеи о том, как я могу получить правильный размер?

public class TestFrame extends JFrame {

    public static void main(String args[]) {
        TestFrame frame = new TestFrame();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public TestFrame() {
        super("Test Frame");
        super.setSize(300, 600);
        this.addComponents();
    }

    private void addComponents() {

        int heightLeft = this.getHeight();
        JPanel panel = new JPanel();
        panel.setSize(300, 600);
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        String text = "This is a long String that represents "
            + "the length of strings in my application. "
            + "This will vary in the real application."
            + "<ul><li>It uses html</li><li>not just</li>"
            + "<li>plain text</li></ul>"
            + "I'd like as many as will fit in the fame to be added.\n";

        while (true) {
            JTextPane textPane = createTextPane(text);

            this.invalidate();

            if (heightLeft > 0) {
                panel.add(textPane);
            } else {
                break;
            }
            System.out.println("Before validation:" + textPane.getSize());
            // returns width and height = 0
            this.validate();
            System.out.println("After validation:" + textPane.getSize());
            // Still returns width and height = 0
            heightLeft -= textPane.getPreferredSize().getHeight();
        }

        super.add(panel);
    }

    public JTextPane createTextPane(String text) {
        JTextPane textPane = new JTextPane();

        textPane = new JTextPane();
        textPane.setEditorKit(new StyledEditorKit());
        textPane.setEditable(false);
        textPane.setOpaque(false);

        textPane.setContentType("text/html");
        textPane.setText(text);

        return textPane;
    }
}

Спасибо за ваше время!

Ответы [ 2 ]

3 голосов
/ 14 августа 2010

То, что вы пытаетесь выполнить, кажется удивительно трудным, потому что вы должны полагаться на метод расчета Swing размера ваших различных компонентов, а затем получить правильные значения для выполнения расчетов по ним.Хотя это выглядит довольно тривиально в зависимости от доступных методов API, взгляд на исходный код показывает другую историю.Это дополнительно усложняется тем фактом, что некоторые значения рассчитываются правильно только тогда, когда компонент фактически отображается, а это означает, что значения, которые вы пытаетесь получить ранее, не отражают то, что вы видите на экране (как вы узнали).

С другой стороны, кажется, что можно сделать то, к чему ты стремишься.Имейте в виду, однако, что при добавлении элементов в BoxLayout ожидаемое поведение заключается в том, что все пространство контейнера, которому вы назначили менеджер компоновки, используется для позиционирования дочерних компонентов.Это означает, что при добавлении JTextPane объектов к вашему JPanel они будут растягиваться, чтобы их суммарная высота занимала все указанные вами 600 пикселей.В результате вам нужно определиться, когда вы превысили доступную высоту, немного по-другому, поскольку визуализированная высота каждого компонента может изменяться в процессе.

После того, как вы немного поиграете с этим и проклянетесьКачаясь неоднократно, я хотя и придумал решение, используя getBounds() (который BoxLayout использует при делегировании для его LayoutParameters для определения высоты компонента), но метод, который я оказался не очень надежным,Я собираюсь поиграть с этим, так что, надеюсь, я придумаю какой-нибудь пригодный для использования код, или кто-то еще найдет решение, которое я пропустил.

Редактировать: Для полноты вот пример кода, который вызывает doLayout() для вычисления необходимых размеров перед показом формы (все еще с недостатками BoxLayout).Он не будет работать на моем JRE 1.5 из-за некоторых ArrayIndexOutOfBoundsException в SizeRequirements, но эта ошибка, кажется, была исправлена ​​в 1.6.В 1.5, если ваш список компонентов не был слишком большим, вы могли бы добавить их все, вызвать doLayout() после цикла (как кажется, это работает в 1.5 по любой причине), а затем просто просмотреть массив, возвращенный getComponents()удаление всего, после того, как максимальная высота была превышена.

В качестве последнего замечания, я лично поклонник использования MigLayout для более сложных макетов, так как я нахожу его механизм позиционирования и стилизациинемного легче работать, чем текущие встроенные менеджеры по расположению.Не слишком уместно здесь, но стоит упомянуть в любом случае.

import java.awt.Dimension;
import java.awt.Rectangle;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.text.StyledEditorKit;

public class TestFrame extends JFrame {
    private static final int CONTENT_HEIGHT = 600;
    private static final int CONTENT_WIDTH = 300;

    public static void main(String[] args) {
        TestFrame frame = new TestFrame();

        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public TestFrame() {
        super("Test Frame");
        this.addComponents();
        this.pack();
    }

    private void addComponents() {
        JPanel panel = new JPanel();

        panel.setPreferredSize(new Dimension(CONTENT_WIDTH, CONTENT_HEIGHT));
        panel.setBounds(new Rectangle(CONTENT_WIDTH, CONTENT_HEIGHT));
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

        String text = "This is a long String that represents the length of" +
            " stings in my application. This will vary in the real" + 
            " application.<ul><li>It uses html</li><li>not just</li>" +
            "<li>plain text</li></ul>I'd like only as many as will fit" +
            " in the fame to be added.\n";

        this.setContentPane(panel);

        int height = 0;

        while(height < CONTENT_HEIGHT) {
            JTextPane textPane = createTextPane(text);

            panel.add(textPane);
            panel.doLayout();

            // The height on the preferred size has been set to reflect
            // the rendered size after calling doLayout()
            height += textPane.getPreferredSize().getHeight();

            // If we've exceeded the height, backtrack and remove the
            // last text pane that we added
            if (height > CONTENT_HEIGHT) {
                panel.remove(textPane);
            }
        }
    }

    private JTextPane createTextPane(String text) {
        JTextPane textPane = new JTextPane();

        textPane.setEditorKit(new StyledEditorKit());
        textPane.setEditable(false);
        textPane.setOpaque(false);
        textPane.setContentType("text/html");
        textPane.setText(text);

        return textPane;
    }
}
1 голос
/ 14 августа 2010

Рамка, на которой отображаются компоненты, должна быть видимой, чтобы получить размер (потому что, если рамка не видна, менеджер компоновки устанавливает размер в (0, 0)).Вы должны позвонить frame.setVisible(true) перед добавлением компонентов.Я также рекомендую вам создать свой собственный класс панели (который расширит JPanel), а также создавать компоненты и размещать их на панели оттуда, а не от основного класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...