In case someone marks it as duplicate, I will do it myself: we have a very relative question long before:
Java setResizable(false) changes the window size (swing)
And none solution works for me. Here is my SSCCE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
public class TitleHeightChange extends JFrame {
private static final String lp = System.lineSeparator();
public TitleHeightChange() {
begin();
}
private void begin() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// UIManager.installLookAndFeel("Nimbus", NimbusLookAndFeel.class.getName());
JFrame frame1 = new JFrame();
frame1.setTitle("Frame1");
frame1.setLayout(new BorderLayout());
JTextArea area1 = new JTextArea();
area1.setBorder(BorderFactory.createLineBorder(Color.darkGray,1));
frame1.add(area1, BorderLayout.CENTER);
frame1.addComponentListener(new ComponentListener() {
@Override
public void componentShown(ComponentEvent e) {
// TODO Auto-generated method stub
area1.setText("frame height: " + frame1.getBounds().height + lp
+ "frame width: " + frame1.getBounds().width + lp
+ "content pane height: " + frame1.getContentPane().getBounds().height + lp
+ "content pane width: " + frame1.getContentPane().getBounds().width + lp
+ "title bar height: " + (frame1.getBounds().height-frame1.getContentPane().getBounds().height) + lp
+ "isResizable() value: false");
}
@Override
public void componentResized(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentMoved(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentHidden(ComponentEvent e) {
// TODO Auto-generated method stub
}
});
frame1.setResizable(false);
frame1.pack();
frame1.setBounds(0, 0, 300, 300);
frame1.setLocationRelativeTo(null);
frame1.setVisible(true);
JFrame frame2 = new JFrame();
frame2.setTitle("Frame2");
frame2.setLayout(new BorderLayout());
JTextArea area2 = new JTextArea();
area2.setBorder(BorderFactory.createLineBorder(Color.darkGray,1));
frame2.add(area2, BorderLayout.CENTER);
frame2.addComponentListener(new ComponentListener() {
@Override
public void componentShown(ComponentEvent e) {
// TODO Auto-generated method stub
area2.setText("frame height: " + frame2.getBounds().height + lp
+ "frame width: " + frame2.getBounds().width + lp
+ "content pane height: " + frame2.getContentPane().getBounds().height + lp
+ "content pane width: " + frame2.getContentPane().getBounds().width + lp
+ "title bar height: " + (frame2.getBounds().height-frame2.getContentPane().getBounds().height) + lp
+ "isResizable() value: true");
}
@Override
public void componentResized(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentMoved(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentHidden(ComponentEvent e) {
// TODO Auto-generated method stub
}
});
frame2.setResizable(true);
frame2.pack();
frame2.setBounds(0, 0, 300, 300);
frame2.setLocationRelativeTo(null);
frame2.setVisible(false);
setLayout(new BorderLayout());
JButton b = new JButton();
b.setText("switch");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if (frame1.isVisible()) {
frame1.setVisible(false);
frame2.setVisible(true);
} else {
frame1.setVisible(true);
frame2.setVisible(false);
}
}
});
b.setBounds(0, 0, 100, 30);
add(b, BorderLayout.CENTER);
pack();
setBounds(600, 700, 100, 30);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
TitleHeightChange frame = new TitleHeightChange();
}
});
}
}
I notice that not only the windows changes size, but the title bar also changes height. It is illustrated better with this GIF:
We can see all the data we need in this example. When the frame is not resizable:
frame height: 300
frame width: 300
content pane height: 274
content pane width: 294
title bar height: 26
isResizable() value: false
When the frame is resizable:
frame height: 300
frame width: 300
content pane height: 264
content pane width: 284
title bar height: 36
isResizable() value: true
So when a frame is set to be not resizable, its content pane will add an insets of (5, 5, 5, 5), and to maintain the total size of the JFrame, the title bar is shrinked 10 pixels???? This is absurd.
I have tested with and without Nimbus L&F, it is irrelevant.
How can it be possible and tolerated?
The solution I found, is when we setBounds() after pack(), add 10 pixels at the window which is resizable. But this is ugly, and it does not prevent the title bar to increase.
How can we solve this?
After all it is a Look & Feel problem......
If we use Java default Metal look and feel, and set setDefaultLookAndFeelDecorated(true) before creating both frames, the border/insets of Java default look & feel style will be painted and visible, thus two JFrames have same width and height.
I have played with other L&F and find that javax.swing.plaf.nimbus.NimbusLookAndFeel, com.sun.java.swing.plaf.windows.WindowsLookAndFeel and com.sun.java.swing.plaf.motif.MotifLookAndFeel haven't implemented this extra dragging handler, maybe for aesthetic reasons. (I really doubt that why Java default style wanted to paint this handler. I personally don't think it's imprescindible. I think ppl implementing the other L&F also wanted to avoid it so they came up with a usable but ugly solution. )
This GIF shows you how the default Metal L&F paints the "handle" of resizing in both frames:

来源:https://stackoverflow.com/questions/44303746/swing-setresizabletrue-make-jframe-title-bar-higher-and-window-size-smaller
