Java Forum / GUI / October 2007
JTextArea size problem.
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 MagazinesGet 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 ...
|
|
|