Java 为什么在JFrame上设置setPreferredSize()不好?

Java 为什么在JFrame上设置setPreferredSize()不好?,java,swing,Java,Swing,使用setPreferredSize()设置JFrame的首选大小是否被认为是错误的 如果是坏的,什么是将JFrame窗口大小更改为我需要的尺寸的好方法 我知道如何放置组件以反映我需要的最终JFrame尺寸。但如果在调用pack()更改finalJFrame大小之前,使用快捷方式更改首选大小,那么大小是否不好?如果是,为什么 例如,我有一个示例表单: 显示时不设置首选大小 现在,在调用pack()之前,我可以通过调用setPreferredSize()调整表单大小 这通过调用显示:setPr

使用
setPreferredSize()
设置
JFrame
的首选大小是否被认为是错误的

如果是坏的,什么是将
JFrame
窗口大小更改为我需要的尺寸的好方法

我知道如何放置组件以反映我需要的最终JFrame尺寸。但如果在调用
pack()
更改final
JFrame
大小之前,使用快捷方式更改首选大小,那么大小是否不好?如果是,为什么

例如,我有一个示例表单:

显示时不设置首选大小

现在,在调用
pack()
之前,我可以通过调用
setPreferredSize()
调整表单大小

这通过调用显示:
setPreferredSize(新维度(500300))

我可以有类似的效果,设置组件的大小,而布局。但是,只调用
setPreferredSize()
设置帧大小有什么缺点呢

我可以认为设置首选大小是在显示窗口后用鼠标手动调整其大小。不是吗

代码:


就个人而言,我认为使用
frame.setPreferredSize()
调整
JFrame
窗口的大小没有什么错。事实上,我认为这是调整其大小的最合适的解决方案

但现在正是区分一些最常见的调整大小方法的好时机:

  • frame.pack()
    ,如前所述,基本上为每个单独的元素采用首选的大小

  • frame.setSize()
    按预期调整窗口大小,但仅当组件的父级没有明确定义布局管理器时。 对这种方法的使用进行了讨论

这并没有留下任何其他方法来定义窗口的大小,这就是为什么我认为设置首选窗口大小是最好的方法。我仍然会确保定义
setMinimumSize()
setMaximumSize()
,以确保在所有情况下正确调整组件的大小

编辑:

这篇文章中的其他帖子让我想到了在设置组件时使用“魔法常量”。例如,在web开发中,通常不赞成使用像素,因为系统会发生很大变化。我想看看这是否也适用于维度。简言之,我的研究结果得出结论,事实并非如此

这是一个JFrame,其
首选尺寸
新尺寸(200300)
在我的MacBook Pro上,带有视网膜显示器:

新尺寸(200300)的首选尺寸

这是一个JFrame,在我的华硕Windows平板电脑(非视网膜显示器)上拍摄的
首选尺寸
新尺寸(200300)

新尺寸(200300)的首选尺寸

这些窗口看起来一模一样,尽管我找不到发布的,但尺寸实际上已经成比例了,考虑到显示器的高度、宽度和分辨率,可以在所有设备上生成近乎精确的渲染。我想你会说,这是有道理的,因为这是Java的方式

话虽如此,我认为有一些事情需要注意:

  • 正如所指出的,
    UIManager LookAndFeel
    跨平台之间的差异

  • 老实说,我认为最后的决定是留给程序员的。在这次测试之后,我仍然得出结论,如果您不打算实现半复杂的窗口管理器,那么使用
    frame.setPreferredSize()
    是最好的选择之一。即使如此,我认为总会有一些未知的变化。

    被认为是不好的主要原因(坏可能是一个太强的词,不明智可能更好)是使用未知(神奇)数字,而不是经验值

    每个平台(甚至是运行在不同硬件和设置上的类似操作系统)都有自己的内容呈现方式,可以改变各个组件所需的空间量

    对于诸如文本字段和文本区域之类的内容,您可以使用
    setColumns
    setRows
    对可用于更改帧最终大小的列数(以及文本区域的行数)提出建议

    所以,使用下面的代码

    import java.awt.EventQueue;
    import java.awt.FlowLayout;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class TestLayout101 {
    
        public static void main(String[] args) {
            new TestLayout101();
        }
    
        public TestLayout101() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private JTextField fullNameTextField = new JTextField(10);
            private JTextField emailIDTextField = new JTextField(10);
            private JTextArea addressTextArea = new JTextArea(10, 20);
            private JButton submitButton = new JButton("Submit");
            private JButton cancelButton = new JButton("Cancel");
    
            public TestPane() {
    
                setLayout(new GridBagLayout());
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.anchor = GridBagConstraints.WEST;
                gbc.insets = new Insets(4, 4, 4, 4);
    
                add(new JLabel("Full Name: "), gbc);
                gbc.gridy++;
                add(new JLabel("Email ID: "), gbc);
                gbc.gridy++;
                gbc.anchor = GridBagConstraints.NORTHWEST;
                add(new JLabel("Address: "), gbc);
    
                gbc.gridx++;
                gbc.gridy = 0;
                gbc.fill = GridBagConstraints.HORIZONTAL;
                gbc.weightx = 1;
    
                add(fullNameTextField, gbc);
                gbc.gridy++;
                add(emailIDTextField, gbc);
                gbc.gridy++;
                gbc.weighty = 1;
                add(new JScrollPane(addressTextArea), gbc);
    
                JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT, 4, 4));
                buttons.add(submitButton);
                buttons.add(cancelButton);
    
                gbc.gridx = 0;
                gbc.gridy++;
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                gbc.weighty = 0;
                add(buttons, gbc);
            }
        }
    }
    
    这就产生了

    现在只改变一行

    private JTextArea addressTextArea = new JTextArea(10, 20);
                                    // Only this value ---^
    
    它产生了这个

    再一次

    private JTextArea addressTextArea = new JTextArea(10, 40);
                                    // Only this value ---^
    

    我可以更改
    JTextArea
    的行数,也可以影响窗口的高度

    不同之处在于,这些值与系统字体度量结合使用,以计算程序运行时组件的首选大小,因此,对于不同的系统和平台,这些值会有所不同


    布局的要点是将时间集中在意图和工作流程上,而不是试图获得像素完美的解决方案,因为根本没有这样的事情……与web开发人员交谈,他们有相同的问题,只是更糟糕(单个系统上有多个浏览器,所有渲染方式都不同)

    被认为不好的主要原因是使用未知(神奇)数字,而不是经验值。每个平台(甚至是运行在不同硬件和设置上的类似操作系统)都有自己的内容呈现方式,可以改变各个组件所需的空间量。对于像文本字段和文本区域这样的东西,你可以就可以用来更改帧最终大小的列数(以及文本区域的行数)提出建议。我有一个开发人员做过这种事情,当用户使用比他设计的分辨率小的分辨率时,这种事情会在我们面前爆发(另一个问题是滤网包装过多,并且
    private JTextArea addressTextArea = new JTextArea(10, 40);
                                    // Only this value ---^