Swing - setResizable(true) 使 JFrame 标题栏更高,窗口尺寸更小
如果有人将其标记为重复,我会自己做:很久以前我们有一个非常相关的问题:
我们可以在这个例子中看到我们需要的所有数据.当框架不可调整大小时:
帧高:300框架宽度:300内容窗格高度:274内容窗格宽度:294标题栏高度:26isResizable() 值:假
当框架可调整大小时:
帧高:300框架宽度:300内容窗格高度:264内容窗格宽度:284标题栏高度:36isResizable() 值:真
那么当一个frame设置为不可调整大小时,它的内容窗格会添加一个(5, 5, 5, 5)的insets,并且为了保持JFrame的总大小,标题栏缩小了10个像素????这太荒谬了.
我在有和没有 Nimbus L&F 的情况下都进行了测试,这无关紧要.
这怎么可能和容忍?
我找到的解决方案是,当我们在 pack()
之后 setBounds()
,在可调整大小的窗口处添加 10 个像素.但这很难看,并且不妨碍标题栏增加.
我们如何解决这个问题?
解决方案毕竟是Look &感觉有问题……
如果我们使用 Java 默认的 Metal 外观,并在创建两个框架之前设置 setDefaultLookAndFeelDecorated(true)
,Java 默认外观的边框/插图感觉样式将被绘制并可见,因此两个 JFrame 具有相同的宽度和高度.
我和其他 L&F 玩过,发现 javax.swing.plaf.nimbus.NimbusLookAndFeel
, com.sun.java.swing.plaf.windows.WindowsLookAndFeel
和 com.sun.java.swing.plaf.motif.MotifLookAndFeel
没有实现这个额外的拖动处理程序,可能是出于审美原因.(我真的怀疑为什么 Java 默认样式要绘制这个处理程序.我个人认为这不是不可思议的.我认为实现其他 L&F 的人也想避免它,所以他们想出了一个可用但丑陋的解决方案.)
此 GIF 向您展示了默认的 Metal L&F 如何在两个帧中绘制调整大小的句柄":
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:
相关文章