Управление предпочтительным размером JEditorPane с длинным текстом

У меня есть JEditorPane, который отображается внутри всплывающего окна и запускается с помощью кнопки. Панель содержит длинный текст, поэтому она вложена в JScrollPane, а всплывающее окно ограничено максимальным размером 300 x 100:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            String text = "Potentially looooooong text. " + 
                "Lorem ipsum dolor sit amet, consectetuer" +
                "adipiscing elit, sed diam nonummy nibh euismod " +
                "tincidunt ut laoreet dolore magna aliquam" + 
                "adipiscing elit, sed diam nonummy nibh euismod" + 
                "erat volutpat. Ut wisi enim ad minim veniam, " + 
                "quis nostrud exerci tation.";

            final JEditorPane editorPane = new JEditorPane("text/html", text);
            editorPane.setEditable(false);

            final JButton button = new JButton("Trigger Popup");
            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JPopupMenu popup = new JPopupMenu();
                    popup.setLayout(new BorderLayout());
                    popup.add(new JScrollPane(editorPane));
                    Dimension d = popup.getPreferredSize();
                    int w = Math.min(300, d.width);
                    int h = Math.min(100, d.height);
                    popup.setPopupSize(w, h);
                    Dimension s = button.getSize();
                    popup.show(button, s.width / 2, s.height / 2);
                }
            });

            JFrame f = new JFrame("Layout Demo");
            f.setSize(200, 200);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setLocationRelativeTo(null);
            f.getContentPane().add(button);
            f.setVisible(true);
        }
    });
}

Когда экземпляр JEditorPane отображается в первый раз (т. е. когда кнопка нажимается один раз), он каким-то образом сообщает, что предпочтительная высота слишком мала (1):

первое обращение

После последующих нажатий кнопок макет выглядит именно так, как и следовало ожидать (2):

последующие вызовы

Как я могу обеспечить/установить правильный предпочтительный размер, чтобы он всегда инициализировался как (2)?


person Rahel Lüthy    schedule 08.02.2010    source источник


Ответы (1)


JEditorPane не может одновременно вычислить окончательную предпочтительную ширину и высоту, он должен знать одно, прежде чем сможет вычислить другое.

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

На втором проходе ширина уже была установлена ​​(ограничена размером первого JPopupMenu), и теперь, когда он знает максимальную ширину, он может вычислить, какой высоты он должен быть.

Таким образом, самое простое решение - просто установить максимальную ширину всякий раз, когда вы устанавливаете текст.

String text = "Potentially looooooong text. " + 
    "Lorem ipsum dolor sit amet, consectetuer" +
    "adipiscing elit, sed diam nonummy nibh euismod " +
    "tincidunt ut laoreet dolore magna aliquam" + 
    "adipiscing elit, sed diam nonummy nibh euismod" + 
    "erat volutpat. Ut wisi enim ad minim veniam, " + 
    "quis nostrud exerci tation.";

final JEditorPane editorPane = new JEditorPane("text/html", text);
editorPane.setSize(300, Integer.MAX_VALUE);
editorPane.setEditable(false);

Не беспокойтесь о том, чтобы сделать его слишком большим, он все равно уменьшится, чтобы соответствовать содержимому (как вы увидите, если вы измените текст на "Hello, World!".

person finnw    schedule 08.02.2010
comment
@finnw: Отличное объяснение и обходной путь - большое спасибо! - person Rahel Lüthy; 08.02.2010
comment
Отличное решение, +1! Хотя прошло немного времени, у меня есть еще один хороший вопрос к вам. Я пробовал тот же подход с JTextPane, это не что иное, как подкласс JEditorPane. И это не работает. Я пытаюсь углубиться (BasicTextUI), чтобы понять, в чем разница. Но, может быть, вы уже знаете это? :-) - person AgostinoX; 21.11.2011