How can I create a JTextArea with a specified width and the smallest possible height required to display all the text?
Asked Answered
K

4

13

In all the examples that I can find that use a JTextArea, the height & width is known before constructing the JTextArea, and if the JTextArea would require more height, then it is put inside of a JScrollPane. Obviously, the height of JTextArea is dependent on the width and the text contents.

Now, my situation requires that I do not use a JScrollPane, but instead that the JTextArea be just tall enough to display all the text. When I create the JTextArea, I know the text contents and how much width it will have to work with; I don't know the height - I want that to be as small as possible without cutting off any of the text. This seems very difficult to accomplish.

As a side note, the JTextArea will be added to a JPanel that does not have a layout manager - it uses absolute positioning based on the added component's preferred size. This requires that my JTextArea would return the correct dimensions on getPreferredSize(). The correct dimensions should be the width that I provided when I constructed it, and the minimum height that is required to display all the text with the provided width.

I've found some similar threads that discuss the oddities/bugs involved with the JTextArea that are sometimes solved by calling pack() twice on the parent container. This is not an option for me. I'm tempted to basically create my own JTextArea that takes a width and String and computes the necessary minimum height based on the width and font settings, but I figured I would ask around first before spending the time to do that.

Hopefully my question is clear. Thank you all for your help!

Kenna answered 3/11, 2010 at 0:36 Comment(3)
Would a JLabel do instead of the JTextArea?Goldin
@Andrew Thompson Sure, I could use a JLabel, but then I'd still have to manually insert newlines into the string, which would require me to calculate where they should be based on the width and font settings, and then I have to add some special handling to make it wrap on whole words rather than characters. These are things provided by the JTextArea, so I'd prefer to use that if I can.Kenna
See example below. I like to use a little 'HTML trick' to achieve such things. ;)Goldin
S
6

it uses absolute positioning based on the added component's preferred size.

Sounds like the job of a layout manager.

This requires that my JTextArea would return the correct dimensions on getPreferredSize().

JTextArea textArea = new JTextArea();
textArea.setLineWrap( true );
textArea.setWrapStyleWord( true );
textArea.setText("one two three four five six seven eight nine ten");
System.out.println("000: " + textArea.getPreferredSize());
textArea.setSize(100, 1);
System.out.println("100: " + textArea.getPreferredSize());
textArea.setSize( textArea.getPreferredSize() );
Sinhalese answered 3/11, 2010 at 2:40 Comment(5)
I cannot use a layout manager - I tried them all and concluded that it was easier to use absolute positioning. All I meant by ...it uses absolute positioning based on the added component's preferred size was that this method is relied on so it must be correct.Kenna
Wow! This works! Thank you so much! I never would've thought to try this.Kenna
You are not forced to use a single layout maanger. You can use nested panels with different layout managers to get the job done. Again "determining the position based on the preferred size of the component" is exactly the job of a layout manager. If you don't like the existing layout managers, then write your own. This is what you are doing anyway, except when you implement the LayoutManager interface you have a well known interface to code to.Sinhalese
I understand that I can nest layout managers, and in fact that's exactly what I've done. I'm down to a nested level where there is no layout manager that does exactly what I need, so I used absolute positioning. I considered writing my own layout manager but decided to see if I could make it work before choosing whether it would be worth it to put this logic inside of a layout manager. Thanks again!Kenna
For me, it replies with 000: java.awt.Dimension[width=100,height=16] 100: java.awt.Dimension[width=100,height=48]. I wonder how window managers deal with components that have changing dimentia like apparently JTextFields can...Perineurium
G
5
import java.awt.*;
import javax.swing.*;

class FixedWidthLabel {

    public static void main(String[] args) {

        Runnable r = new Runnable() {
            public void run() {
                String pt1 = "<html><body width='";
                String pt2 =
                    "px'><h1>Label Height</h1>" +
                    "<p>Many Swing components support HTML 3.2 &amp;" +
                    " (simple) CSS.  By setting a body width we can cause the " +
                    " component to find the natural height needed to display" +
                    " the component.<br><br>" +
                    "<p>The body width in this text is set to " +
                    "";
                String pt3 =
                    " pixels." +
                    "";

                JPanel p = new JPanel( new BorderLayout() );

                JLabel l1 = new JLabel( pt1 + "125" + pt2 + "125" + pt3 );
                p.add(l1, BorderLayout.WEST);

                JLabel l2 = new JLabel( pt1 + "200" + pt2 + "200" + pt3 );
                p.add(l2, BorderLayout.CENTER);

                JOptionPane.showMessageDialog(null, p);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
Goldin answered 4/11, 2010 at 2:25 Comment(1)
AhhHh very clever! Good job, and all it required was using the body tag.Kenna
M
0

The solution described in FixedWidthLabel , using <html><body width="..." will require the programmer to provide the message as part of the html string.

If the message is something like invalid integer: i<0 not allowed , then the < will have to be escaped (encoded?), otherwise there is no telling how JLabel will interpret the html.

This adds complexity to this solution.

Only if you know that the message doesn't contain any such characters, you will be allright.

Mythological answered 11/7, 2011 at 13:39 Comment(0)
S
-1

Well perhaps if you know your width you could run some tests and work out how wide each character of text is, that way you could use a loop to determine how many characters fit on each line and total the characters that are to be shown, then you could set the height based on how many lines there are to be.

Say your text has 1000 characters including blank spaces, and the width of a character is equivalent to 4pixels, then you can work out if the width is 400 that 100 characters fit on each line, subsequently you will need 10 lines. Now say the height is 10 for the font size, you now know you need 10 x 10 == 100 pixels, so your TextArea should be 400x100

Synge answered 3/11, 2010 at 2:24 Comment(2)
This approach does not work for non fixed width fonts. Further problems come up when the words are wrapped, wasting part of the end of a line.Goldin
Thanks for your reply, but as stated, this approach doesn't quite work if I want to support variable-sized font (which I need to). Plus, these are all things provided by the JTextArea, so I'd rather not re-invent the wheel.Kenna

© 2022 - 2024 — McMap. All rights reserved.