Swing - setResizable(true) make JFrame title bar higher and window size smaller

夙愿已清 提交于 2019-12-06 14:08:21

问题


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?


回答1:


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!