I have a JDialog and I want to have it a certain, given size:
JDialog dialog = new JDialog();
dialog.setSize(800, 600);
dialog.setResizable(false);
Then I add a component:
JLabel label = new JLabel("Test");
dialog.add(label);
Now I could make the dialog visible and check the size of the component
dialog.setVisible(true);
System.out.println(label.getSize());
The answer would be "[width=784,height=562]". Obviously the component was resized to fill the whole client area / content pane of the dialog window. That's fine and as I want it.
Question: How can I obtain the final size of the components before calling setVisible(true)?
So I am at a loss here. I want to make the layoutmanager calculating the right sizes of all components and sub components before showing the dialog, adapted to the overall size of the dialog. But I don't know how.
I now found that it can be done as follows:
JDialog dialog = new JDialog();
JLabel label = new JLabel("Test");
dialog.add(label);
// pack(), setSize(), validate() in this order will
// set sizes on all components as wished
dialog.pack();
dialog.setSize(800, 600);
dialog.validate();
System.out.println(label.getSize());
Also here the output is "[width=784,height=562]" but the dialog is not yet visible. The important part is the combination of pack(), setSize(desiredSize) and validate() in this order. The pack() probably determines a new size of the dialog (preferred sizes of all components), that's why here the size has to be set afterwards and the validate() is responsible for the resizing of the components. Probably setVisible(true) which arrives at the same sizes is doing internally something similar.
It seems a bit of a waste to resize the components several times but without pack() also setSize() and validate() do not have any effect.
I guess the other answers were based on some misunderstanding because they implicitly always assumed that you want to have the preferred size, but there are cases, eg if the user resizes the dialog or if the dialogs size is fixed from the beginning where you cannot attain the preferred size and some components just have to fill the available space.
That was the layout problem here, having a given global size of the dialog and determining the size of the components as they fill the available space. LayoutManagers solve this problem quite nicely, however usually only after setVisible(true).
I tested a bit more:
// new dialog
JDialog dialog = new JDialog();
// new label, prints messages if resized or painted
JLabel label = new JLabel("Test") {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Component painted.");
}
};
label.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
System.out.println("Resized: " + e.getComponent().getSize());
}
});
dialog.add(label);
System.out.println("Size after new JLabel: " + label.getSize());
// pack dialog - necessary for setSize/validate to work
dialog.pack();
System.out.println("Size after pack: " + label.getSize());
// set a size and validate changes sizes
dialog.setSize(800, 600);
dialog.validate();
System.out.println("Size after setSize and validate: " + label.getSize());
// set visible would have also done the trick
dialog.setVisible(true);
System.out.println("Size after setVisible(true): " + label.getSize());
// and another resizing (no validation neccessary)
dialog.setSize(300, 200);
// dispose
dialog.dispose();
And the output is
I learned more about the inner workings of Swing:
I tested some more, also with maximized frames and now can combine all the results into: The first painComponent() is always with the right size and the related componentResized() event always follows afterwards, sometimes two times.However the LayoutManager must know before, otherwise the examples would not be drawn correctly. So in case one draws the background by itself, either read out the right size in every paintComponent or implement a custom layout manager or wait for the resized event and invoke repaint, so the component is drawn two times but it should work. Apllications include cases where the number of components to show depend on the size (as in my geographical map application).
Just to complete the picture I think the flow goes like this in case a user maximized or resized a frame/dialog:
And pack() probably just calls setSize(layout.preferredLayoutSize()) as the first step.
So in case depending on the size you have to add or remove components for example, it could be a good idea to override setSize() and listen there for changes. I initially was listening for Resized() events but they arrive too late for the first drawing.
Top-Level Containers return own Size
, PreferredSize
, Bounds
in two cases (if they are)
already visible
after call pack()
, in your case dialog.pack();
have to calculating with Borders
and ToolBar
came from Native OS
have to get this size from Top-Level Containers#getContentPane().getWhatever
most of JComponents
returns own PreferredSize
, then there no reason to sizing for Standard Layout Manager
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.