Controlling the preferred size of a JEditorPane with long text
Asked Answered
P

1

6

I have a JEditorPane which is displayed inside a popup, triggered through a button. The pane contains long text, therefore it's nested inside a JScrollPane, and the popup is constrained to a maximal size of 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);
        }
    });
}

When the JEditorPane instance is shown for the first time (i.e. when the button is clicked once) it somehow seems to report a preferred height which is too small (1):

first invocation

After subsequent button clicks, the layout is just how one would expect it (2):

subsequent invocations

How can I enforce/impose a proper preferred size so it would always initialize like (2)?

Puli answered 8/2, 2010 at 12:2 Comment(0)
C
11

The JEditorPane cannot compute its final preferred width and height simultaneously, it has to know one before it can compute the other.

On the first pass, the JEditorPane computes its preferred height based on the assumption that its width will be unlimited, so it returns the height of a single line (since the text contains no line breaks.)

On the second pass, the width has already been set (constrained by the size of the first JPopupMenu), and now that it knows the maximum width it can compute how tall it needs to be.

So the simplest solution is just to set the width to the maximum whenever you set the text.

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);

Don't worry about making it too large, it will still shrink to fit the content (as you will see if you change the text to "Hello, World!".

Clew answered 8/2, 2010 at 13:3 Comment(2)
@finnw: Excellent explanation & work-around -- thank you very much!Tussle
Excellent solution, +1! Although it's been a bit of time, i have another good question for you. I tried the same approach with JTextPane, that is nothing but a JEditorPane subclass. And it doesn't work. I am trying to go in deep (BasicTextUI) to understand where the difference is. But maybe you already know it? :-)Feinleib

© 2022 - 2024 — McMap. All rights reserved.