Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / GUI / October 2007

Tip: Looking for answers? Try searching our database.

JTextArea size problem.

Thread view: 
RedGrittyBrick - 03 Oct 2007 12:02 GMT
In a dialogue box, I want to display some text word-wrapped. I use a
JTextArea and set word wrapping on.

However, the height of the dialogue seems to be incorrectly based on the
Textarea being one line high, (it is two lines high when wrapped).

The println statements show
  Pref  java.awt.Dimension[width=352,height=16]
  Wrap set
  Pref  java.awt.Dimension[width=330,height=16]
Note that the width is reduced but the height is wrong.
  Packed
  Size  java.awt.Dimension[width=330,height=16]
No change due to pack()
  Size  java.awt.Dimension[width=330,height=32]
But after closing, the height is correct (32)!

Qs:
Am I doing something wrong?
Is there a better way to word-wrap some text in a dialogue?

------------------------- 8< ----------------------
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class TestErrorDialog {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new TestErrorDialog();
            }
        });
    }

    private JFrame f;

    TestErrorDialog() {
        JPanel p = new JPanel();
        p.add(new JLabel("Testing ..."));

        f = new JFrame("Test Error Dialog");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(p);
        f.pack();
        f.setVisible(true);
        triggerAnError();
    }

    public void triggerAnError() {
        System.out.println("Error triggered");
        new ErrorDialog(f, "Unable to unwind flanges!",
                "Please contact the help desk "
                + "and tell them absolutely everything.");
        System.exit(0);
    }
}

// ==================================================================

class ErrorDialog extends JDialog implements ActionListener {

    JTextArea messageComponent = new JTextArea(1, 30);

    static final String CLOSE = "Close";

    public ErrorDialog(JFrame parent, String title, String message) {
        super(parent, "Error", true);

        System.out.println("Constructing dialog");

        messageComponent.setText(message);
        messageComponent.setEditable(false);
        System.out.println("Pref  "
                + messageComponent.getPreferredSize());
        messageComponent.setLineWrap(true);
        messageComponent.setWrapStyleWord(true);
        System.out.println("Wrap set");
        System.out.println("Pref  "
                + messageComponent.getPreferredSize());

        JButton closeButton = new JButton(CLOSE);
        closeButton.addActionListener(this);

        JLabel titleLabel = new JLabel("<html><body><h2>" + title
                + "</h2></body></html>");

        JPanel innerPane = new JPanel();
        innerPane.setLayout(
                new BoxLayout(innerPane, BoxLayout.PAGE_AXIS));
        innerPane.setBorder(
                BorderFactory.createEmptyBorder(10,10,10,10));
        for (JComponent component : new JComponent[] { titleLabel,
                messageComponent, closeButton })
            component.setAlignmentX(Component.LEFT_ALIGNMENT);
        innerPane.add(titleLabel);
        innerPane.add(Box.createRigidArea(new Dimension(0, 5)));
        innerPane.add(messageComponent);
        innerPane.add(Box.createRigidArea(new Dimension(0, 5)));
        innerPane.add(closeButton);
        add(innerPane);

        getRootPane().setDefaultButton(closeButton);
        setLocationRelativeTo(parent);
        pack();
        System.out.println("Packed");
        System.out.println("Size  " + messageComponent.getSize());
        setVisible(true);
        System.out.println("Size  " + messageComponent.getSize());
    }

    public void actionPerformed(ActionEvent e) {
            setVisible(false);
    }
} // ErrorDialog
---------------------------- 8< -------------------------
Larry Barowski - 03 Oct 2007 17:03 GMT
> In a dialogue box, I want to display some text word-wrapped. I use a
> JTextArea and set word wrapping on.
>
> However, the height of the dialogue seems to be incorrectly based on the
> Textarea being one line high, (it is two lines high when wrapped).

During layout, the text area doesn't know what its eventual width will
be, so it has no way to provide a useful preferred height. It's a problem
for any component for which the preferred size in one dimension
depends on the actual size in the other. This might be good enough to
solve your problem (replacement for pack()):

 pack();
 messageComponent.setSize(messageComponent.getPreferredSize());
 pack();

You could write your own word-wrapping label class from scratch,
but there is no way to solve the basic problem of height/width
dependence. A double pack(), at least, would still be required.
Knute Johnson - 03 Oct 2007 18:16 GMT
> In a dialogue box, I want to display some text word-wrapped. I use a
> JTextArea and set word wrapping on.
[quoted text clipped - 126 lines]
> } // ErrorDialog
> ---------------------------- 8< -------------------------

A simple solution for multi-line component is to use a JLabel and put
HTML in it.

Signature

Knute Johnson
email s/nospam/knute/

Larry Barowski - 03 Oct 2007 20:56 GMT
> A simple solution for multi-line component is to use a JLabel and put HTML
> in it.

That has the same problem, if you put in enough text for wrap
to occur. There is no way for a component to work around this.
Knute Johnson - 03 Oct 2007 22:25 GMT
>> A simple solution for multi-line component is to use a JLabel and put HTML
>> in it.
>
> That has the same problem, if you put in enough text for wrap
> to occur. There is no way for a component to work around this.

JTextAreas layout funny there are a lot of issues.  The program below
uses a JDialog with a JLabel in it and it sizes just fine.  If he really
wants to use a JTextArea for the text, he can make it work by specifying
 the rows and columns and setting the font to Monospaced.  It will work
then too, see test3 below.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class test {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                final JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                JButton b = new JButton("press me");
                b.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent ae) {
                        JDialog d = new JDialog(f,true);
                        d.setLayout(new GridBagLayout());
                        GridBagConstraints c = new GridBagConstraints();
                        c.insets = new Insets(10,10,10,10);
                        JLabel l = new JLabel(
                         "<html>this is a test<br>" +
                         "of multi-line label<br>" +
                         "it has 3 lines");
                        d.add(l,c);
                        d.pack();
                        d.setLocationRelativeTo(f);
                        d.setVisible(true);
                        d.dispose();
                    }
                });
                f.add(b);
                f.pack();
                f.setVisible(true);
            }
        };
        EventQueue.invokeLater(r);
    }
}

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class test3 {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                final JFrame f = new JFrame();
                f.setLayout(new GridBagLayout());
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                JButton b = new JButton("press me again");
                b.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent ae) {
                        JDialog d = new JDialog(f,true);
                        JTextArea ta = new JTextArea(
                         "Enough text to wrap and be visible on two lines",
                         2,30);
                        ta.setFont(new Font("Monospaced",Font.PLAIN,16));
                        ta.setLineWrap(true);
                        d.add(ta);
                        d.pack();
                        d.setLocationRelativeTo(f);
                        d.setVisible(true);
                        d.dispose();
                    }
                });
                f.add(b);
                f.pack();
                f.setVisible(true);
            }
        };
        EventQueue.invokeLater(r);
    }
}

Signature

Knute Johnson
email s/nospam/knute/

RedGrittyBrick - 03 Oct 2007 23:36 GMT
Thanks Knute, thanks Larry.
Larry Barowski - 04 Oct 2007 12:25 GMT
>>> A simple solution for multi-line component is to use a JLabel and put
>>> HTML in it.
[quoted text clipped - 4 lines]
> JTextAreas layout funny there are a lot of issues.  The program below uses
> a JDialog with a JLabel in it and it sizes just fine.

Yes, but your example uses a label with 3 forced lines of text and
no wrapping. The problem is not with JTextArea, it is with laying
out a component for which the preferred width is flexible and
preferred height depends on width, or vice versa. If a component
can fit the text "exactly" at 4000x10, 200x200, 50x800, and lots
of sizes in between, what should it report for its preferred size?
What should it do when it doesn't get it? Lets say it chooses
200x200...

component: I want to be 200x200.
layout manager: The row you are in will be 400 pixels wide,
  as will you.
component: In that case, I only need to be 100 pixels high.
layout manager: Too late.
programmer: What's this big empty space?

To see this general behavior, add
  messageComponent.setSize(50, Integer.MAX_VALUE)
before the pack() in RGB's original example above.

My solution above would do this:

component: I want to be 200x200.
layout manager: The row you are in will be 400 pixels wide,
  as will you.
component: In that case, I only need to be 100 pixels high.
layout manager: Too late.
program: OK, lets go again, with the knowledge that component
  should be 400 pixels wide.

Which might be more obvious if you code it this way:

pack();
messageComponent.setSize(messageComponent.getWidth(),
              Integer.MAX_VALUE);
pack();
Knute Johnson - 08 Oct 2007 03:57 GMT
>>>> A simple solution for multi-line component is to use a JLabel and put
>>>> HTML in it.
[quoted text clipped - 40 lines]
>                Integer.MAX_VALUE);
> pack();

Larry:

I also included an example that works just fine with a JTextArea.

knute...
Larry Barowski - 08 Oct 2007 05:28 GMT
> I also included an example that works just fine with a JTextArea.

Of course you can get it to work if you know ahead of time
how many lines the wrapped text will require. That is unlikely
in a real-world situation, and was not the case in the example
in the OP.
Knute Johnson - 11 Oct 2007 05:12 GMT
>> I also included an example that works just fine with a JTextArea.
>
> Of course you can get it to work if you know ahead of time
> how many lines the wrapped text will require. That is unlikely
> in a real-world situation, and was not the case in the example
> in the OP.

He said it was two lines.  If you want it to do any number of lines then
you have to call pack() again after you know how many lines it will take.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class test10 {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                final JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                JButton b = new JButton("press me one more time");
                b.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent ae) {
                        JDialog d = new JDialog(f,true);
                        JTextArea ta = new JTextArea(
                         "Enough text to wrap and be visible on two
lines");
                        ta.setColumns(15);
                        ta.setLineWrap(true);
                        d.add(ta);
                        d.pack();
                        ta.setRows(ta.getLineCount());
                        d.pack();
                        d.setLocationRelativeTo(f);
                        d.setVisible(true);
                        d.dispose();
                    }
                });
                f.add(b);
                f.pack();
                f.setVisible(true);
            }
        };
        EventQueue.invokeLater(r);
    }
}

Signature

Knute Johnson
email s/nospam/knute/

Larry Barowski - 11 Oct 2007 13:49 GMT
>>> I also included an example that works just fine with a JTextArea.
>>
[quoted text clipped - 4 lines]
>
> He said it was two lines.

The error message was passed in as a parameter to the error dialog
constructor, so it would be reasonable to assume he wanted a solution
that works for any length of text. Besides, unless the number of rows
are fixed and the width flexible or the text is one character long, the
number of wrapped lines for any text in any component that wraps
text in any gui layout is always system dependent in principle.

>  If you want it to do any number of lines then you have to call pack()
> again after you know how many lines it will take.

I have already posted two solutions that are equivalent to the one
below.

> import java.awt.*;
> import java.awt.event.*;
[quoted text clipped - 32 lines]
>     }
> }
Knute Johnson - 11 Oct 2007 17:13 GMT
>>>> I also included an example that works just fine with a JTextArea.
>>> Of course you can get it to work if you know ahead of time
[quoted text clipped - 53 lines]
>>     }
>> }

Exactly, you made an assumption that he wanted an indeterminate number
of lines and I made the assumption that he wanted two.  Somewhere along
the line one of the several decisions must be made.  Once it is, the
appropriate solution is obvious.

Signature

Knute Johnson
email s/nospam/knute/

Roedy Green - 04 Oct 2007 02:03 GMT
>However, the height of the dialogue seems to be incorrectly based on the
>Textarea being one line high, (it is two lines high when wrapped).

Use the row,columns feature in the TextArea constructor.  If that does
not work use the component-expanding features of the GridBagLayout.
Make sure the you have recently validated after changing the size of
the TextArea.
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.