I want to place some elements inside a JFrame by setLocation(x, y) but my frame is not the size I expect.
The size of my JFrame is 600 x 400 but when I run the app it looks like a JFrame of about 550 x 350.
I would like to understand why this happens, even if there are better ways to implement it.
Thanks in advance for any assistance.
My code:
public static void main(String[] args) {
JFrame mainFrame = new JFrame("Example");
mainFrame.setVisible(true);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(600, 400);
mainFrame.setLayout(null);
mainFrame.setResizable(false);
JPanel p1 = new JPanel();
p1.setSize(100, 100);
p1.setLocation(0,0);
p1.setBackground(Color.BLUE);
mainFrame.add(p1);
JPanel p2 = new JPanel();
p2.setSize(100, 100);
p2.setLocation(500,300);
p2.setBackground(Color.BLUE);
mainFrame.add(p2);
}
Output:
CodePudding user response:
A frame's visible content size is the frame size minus the frame's decorations insets.
So your viewable area will be 600x400 - frameDecorationInsets
, and this will be variable (even across the same platform).
Instead, you should be looking at the size of the parent container, for example
Note, I'm running on MacOS, which has a different frame decoration then Windows, but this concept will still work on both ... and you get resizability
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel p1 = new JPanel();
private JPanel p2 = new JPanel();
public TestPane() {
setLayout(null);
p1.setBackground(Color.BLUE);
add(p1);
p2.setBackground(Color.BLUE);
add(p2);
}
@Override
public void doLayout() {
super.doLayout();
p1.setSize(100, 100);
p1.setLocation(0, 0);
p2.setSize(100, 100);
p2.setLocation(getWidth() - p2.getWidth(), getHeight() - p2.getHeight());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
}
}
But...
Arguably, you shouldn't be using null
layouts, you should be relying on things like JComponent#getPreferredSize
and JFrame#pack
to provide suitable hints about how best you want the window to be sized by default, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
JPanel p1 = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
p1.setBackground(Color.BLUE);
JPanel p2 = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
p2.setBackground(Color.BLUE);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.NORTHWEST;
add(p1, gbc);
gbc.gridx = 1;
gbc.gridy = 1;
gbc.anchor = GridBagConstraints.SOUTHEAST;
add(p2, gbc);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
}
}