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

使用setPreferredSize()设置JFrame首选大小是不是很糟糕?

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

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

例如,我有样本表格:

在此处输入图像描述

显示时不设置首选大小。

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

在此处输入图像描述

这通过调用显示: 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); } }); } } 

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

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

对于文本字段和文本区域等内容,您可以使用setColumnssetRows有关可用于更改帧最终大小的列数(以及文本区域的行)的建议…

所以,使用以下代码……

 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开发人员交谈,他们有同样的问题,只是很多更糟糕的是(单个系统上的多个浏览器,所有渲染都不同)

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

但现在是区分一些最常见的resize方法的好时机:

  • frame.pack() ,如这里所解释的,基本上采用每个单独元素的首选大小。

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

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

编辑:

这个post中的其他post让我想到了在设置组件时使用’魔术常量’。 例如,在Web开发中,通常不赞成使用像素,因为这会因系统而广泛变化。 我想看看尺寸是否也是如此。 简而言之,我的发现并没有得出结论。

这是一款JFrame,在我的带有Retina显示屏的MacBook Pro上采用了new Dimension(200, 300)new Dimension(200, 300)

具有<code/>首选大小</ code>的<code> new Dimension(200,300)</ code>的JFrame

这是一个JFrame,在我的华硕Windows平板电脑(非视网膜显示器)上采用了new Dimension(200, 300)new Dimension(200, 300) ):

具有<code/>首选大小</ code>的<code> new Dimension(200,300)</ code>的JFrame

这些窗口看起来完全相同,虽然我找不到这个,但Dimenion确实是一个已经缩放的比例,考虑到显示器的高度,宽度和分辨率,以便在所有设备上产生近乎准确的渲染。 我想你可以说,这是有道理的,因为它是Java方式。

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

  1. MadProgrammer指出,跨平台的UIManager LookAndFeel之间存在差异

老实说,我认为最终的决定取决于程序员。 在这个测试之后,我几乎仍然得出结论,如果你不打算实现一个半复杂的窗口管理器,使用frame.setPreferredSize()是最好的东西之一。 即便如此,我认为总会有一些不明的变化。