为什么在JFrame上设置setPreferredSize()很糟糕?

时间:2014-11-09 08:16:59

标签: java swing

使用JFrame设置setPreferredSize()的首选尺寸是不是很糟糕?

如果不好,有什么方法可以将JFrame窗口大小更改为我需要的尺寸。

我知道按照我需要的最终JFrame维度来放置组件。但是,如果我在调用setPreferredSize()之前使用快捷方式使用调用pack()更改首选大小来更改最终JFrame大小是不是很糟糕?如果是这样的话?

例如我有样本表格:

enter image description here

无需设置首选尺寸即可显示。

现在我可以在致电setPreferredSize()之前致电pack()调整表单大小。

enter image description here

通过调用setPreferredSize(new Dimension(500, 300));

显示

在布置组件尺寸时,我可以产生类似的效果。但是,只需调用setPreferredSize()即可设置帧大小的缺点。

我可以考虑将首选大小设置为在显示后用鼠标手动调整显示窗口的大小。不是吗?

代码:

import java.awt.Dimension;

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class MyFrame extends JFrame {
    private static final long serialVersionUID = 1L;

    private JTextField fullNameTextField = new JTextField();
    private JTextField emailIDTextField = new JTextField();
    private JTextArea addressTextArea = new JTextArea();
    private JButton submitButton = new JButton("Submit");
    private JButton cancelButton = new JButton("Cancel");

    public MyFrame(){
        super("MyFrame");

        layoutComponents();

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationByPlatform(true);

        setPreferredSize(new Dimension(500, 300));

        pack();
    }

    private void layoutComponents(){
        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);

        JLabel fullNameLabel = new JLabel("Full Name:");
        JLabel emailIDLabel = new JLabel("Email ID:");
        JLabel addressLabel = new JLabel("Address:");

        JScrollPane addressScrollPane = new JScrollPane(addressTextArea);

        layout.setHorizontalGroup(
                layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                        .addGap(10)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                                .addGroup(layout.createSequentialGroup()
                                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                                                .addComponent(fullNameLabel)
                                                .addComponent(emailIDLabel)
                                                .addComponent(addressLabel)
                                            )
                                        .addGap(15)
                                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                                                .addComponent(fullNameTextField, 10, 200, Short.MAX_VALUE)
                                                .addComponent(emailIDTextField)
                                                .addComponent(addressScrollPane)
                                                .addGroup(layout.createSequentialGroup()
                                                        .addGap(0, 0, Short.MAX_VALUE)
                                                        .addComponent(submitButton)
                                                        .addGap(10)
                                                        .addComponent(cancelButton)
                                                    )
                                            )
                                    )
                            )
                        .addGap(10)
                    )
            );

        layout.setVerticalGroup(
                layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                        .addGap(10)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                                .addComponent(fullNameLabel)
                                .addComponent(fullNameTextField)
                            )
                        .addGap(5)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                                .addComponent(emailIDLabel)
                                .addComponent(emailIDTextField)
                            )
                        .addGap(5)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                                .addComponent(addressLabel)
                                .addComponent(addressScrollPane, 20, 60, Short.MAX_VALUE)
                            )
                        .addGap(15)
                        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                                .addComponent(submitButton)
                                .addComponent(cancelButton)
                            )
                        .addGap(10)
                    )
            );

        layout.linkSize(submitButton, cancelButton);

        getRootPane().setDefaultButton(submitButton);
    }

    public static void main(String [] args){
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new MyFrame().setVisible(true);
            }
        });
    }
}

2 个答案:

答案 0 :(得分:6)

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

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

对于文本字段和文本区域之类的内容,您可以使用setColumns和{提供有关可用于更改帧最终大小的列数(以及文本区域的行)的建议{1}}例如......

所以,使用以下代码......

setRows

哪个产生......

Compact

现在只改变一行......

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);
        }
    }
}

它产生了这个......

Mini

再次......

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

Luxury

我可以更改private JTextArea addressTextArea = new JTextArea(10, 40); // Only this value ---^ 的行数并影响窗口的高度。

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

布局的要点是花时间专注于意图和工作流程,而不是试图获得像素完美的解决方案,因为根本没有这样的事情......与Web开发人员交谈,他们有同样的问题,更糟糕的是(单个系统上的多个浏览器,所有呈现方式都不同)

答案 1 :(得分:1)

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

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

  • frame.pack(),正如所解释的那样here基本上采用了每个元素的首选大小。

  • frame.setSize()按预期调整窗口大小,但前提是组件的父级没有明确定义布局管理器。 有关此方法here的使用的讨论。

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

修改

这个帖子中的其他帖子让我想到了使用'魔术常数'在设置组件。例如,在Web开发中,通常不赞成使用像素,因为这会因系统而广泛变化。我想看看尺寸是否也是如此。简而言之,我的研究结果表明它没有。

这是一个带有prefered size new Dimension(200, 300) prefered size的JFrame,带有Retina显示屏的MacBook Pro:

JFrame with a <code>prefered size</code> of <code>new Dimension(200, 300)</code>

我的华硕Windows平板电脑(非视网膜显示屏)采用了new Dimension(200, 300) UIManager LookAndFeel的JFrame:

JFrame with a <code>prefered size</code> of <code>new Dimension(200, 300)</code>

这些窗口看起来完全一样,虽然我无法找到这个,但Dimenion确实是一个已经缩放的比例,考虑到显示器的高度,宽度和分辨率,以产生接近准确的跨所有设备呈现。我想你可以说,这是有道理的,因为它是Java方式。

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

  1. MadProgrammer跨平台的frame.setPreferredSize()之间的差异指出
  2. 老实说,我认为最后的决定取决于程序员。在此测试之后,我几乎仍然得出结论,如果您不打算实现一个半复杂的窗口管理器,那么使用{{1}}是最好的东西之一。即便如此,我认为总会有一些不明的变化。