Reputation: 522
On a project, I have a JFrame A starting a JDialog B, which itself starts a JDialog C (all using buttons). However, when following one of these procedures :
what is displayed in B is not the same (the second procedure gives a weird ugly thing).
I don't get why that could be, since in both ways my updateAll method is called.
I tried to recreate this with a little program so that it's easier to see what's going on. Solving this may or may not solve it on my actual project, but it will surely help.
Since I don't know where it could come from, here's the full code of my (test) program. Brace yourselves.
The 'A' Frame
public class MyFrame extends JFrame {
private static final long serialVersionUID = 7073064926636937881L;
public MyFrame() {
this.setSize(200, 300);
JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
new MyDialog1().setVisible(true);
}
});
this.getContentPane().add(button);
}
public static void main(String args[]) {
new MyFrame().setVisible(true);
}
}
The 'B' Dialog
public class MyDialog1 extends JDialog {
private static final long serialVersionUID = 9181006217120036637L;
private JScrollPane scrollPane;
public String text = "aaaaaaaaaaa\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\naaaaaaaa\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\naaaaaaaa";
public MyDialog1() {
this.setVisible(false);
this.setSize(800, 600);
this.initComponent();
this.updateAll();
}
private void initComponent() {
this.getContentPane().setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
this.scrollPane = new JScrollPane();
c.gridx = 0;
c.gridy = 0;
this.getContentPane().add(this.scrollPane, c);
c.gridx = 0;
c.gridy = 1;
JButton b = new JButton("Supposedly edit stuff");
final MyDialog1 caller = this;
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
new MyDialog2(caller).setVisible(true);
}
});
this.getContentPane().add(b, c);
c.gridx = 1;
c.gridy = 1;
b = new JButton("Leave");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
setVisible(false);
}
});
this.getContentPane().add(b, c);
}
public void updateAll() {
JPanel mainPanel = new JPanel();
for (int i = 0 ; i < 5 ; i++) {
JPanel subPanel = new JPanel();
JTextArea t = new JTextArea(this.text);
t.setSize(60, 30);
t.setVisible(true);// Useful ? What about setSize ?
subPanel.add(t);
mainPanel.add(subPanel);
}
this.scrollPane.setSize(150, 150); // FIXME When in initComponent, doesn't do anything, and when in updateAll, behavior is inconsistent
this.scrollPane.setViewportView(mainPanel); // Replacing previous JPanel
}
}
The 'C' Dialog
public class MyDialog2 extends JDialog {
private static final long serialVersionUID = 5676648412234106581L;
private MyDialog1 caller;
public MyDialog2(MyDialog1 c) {
this.setSize(100, 150);
this.caller = c;
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
setVisible(false);
caller.text += "\nbbbbbbbbbbbbb\nbbbbbbbbbbbbbbbbbb\nbbbbbbbbbbb\nbbbbbbbbbbbbbb\ncccccccccccccccccccccccccccccccccccccccccccc\ncccccccccc";
caller.updateAll();
}
});
this.getContentPane().add(cancelButton);
}
}
Thanks for your help.
Upvotes: 0
Views: 56
Reputation: 44414
Easy answer which ignores good practice:
Replace this:
this.scrollPane.setSize(150, 150);
with this:
this.scrollPane.setMinimumSize(new Dimension(150, 150));
Calling setSize
on a component which is in a Container with a layout usually does nothing; at best, it will set the size until the next time the container is validated, since the size will be overwritten by the layout manager. However, setting a minimumSize (or preferredSize or maximumSize) sets a persistent property that is respected by (most) layout managers.
Why does setMinimumSize
make a difference? Because you have not set any weightx
or weighty
properties on any of your GridBagConstraints, so there is not enough room for the GridBagLayout to display your JScrollPane at its preferred size. When GridBagLayout determines there isn't enough room to display everything at the size it requires, the layout "punts" and forces everything to revert to its minimum size.
The first time you display the B dialog, you are seeing the JScrollPane at its minimum size (that is, just large enough to display the scrollbars and viewport border). After canceling the C dialog, the setSize(150, 150)
takes effect, but it's likely that any subsequent changes to any descendant of the GridBagLayout would cause that (150, 150) to be overwritten with the JScrollPane's minimum size again.
More complex answer which is good practice:
Remove all calls to setSize in every class. Usually you should not set explicit sizes at all, but if you must do so, use setPreferredSize
.
Components which are made to grow and shrink, like JScrollPanes, should be assigned positive weightx
and weighty
values in their corresponding GridBagConstraints, along with fill
being set to GridBagConstraints.BOTH as pcej suggested.
Upvotes: 0
Reputation: 622
I suggest to use
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.BOTH; // make the component fill its display area entirely
c.ipady = 150; //height
c.anchor = GridBagConstraints.FIRST_LINE_START; // component start from the left top corner
this.getContentPane().add(this.scrollPane, c);
for definition of JScrollPane constraints.
In additition, add validate() and repaint() after modifying elements
this.scrollPane.setViewportView(mainPanel); // Replacing previous JPanel
this.validate();
this.repaint();
Upvotes: 1