我应该避免使用set(首选|最大值|最小值)Java Swing 中的大小方法?

2022-08-31 04:24:27

我曾多次因建议使用以下方法而受到批评:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

在组件上。当我想定义显示的组件之间的比例时,我看不到使用它们的任何替代方案。有人告诉我:Swing

对于布局,答案总是相同的:使用合适的布局管理器

我在网上搜索了一下,但我没有找到任何关于这个主题的全面分析。所以我有以下问题:

  1. 我应该完全避免使用这些方法吗?
  2. 定义这些方法是有原因的。那么我应该什么时候使用它们呢?在什么情况下?目的何在?
  3. 使用这些方法的负面后果究竟是什么?(我只能考虑在具有不同屏幕分辨率的系统之间增加便携性)。
  4. 我不认为任何布局管理器都可以完全满足所有所需的布局需求。我真的需要为布局上的每一个小变化实现一个新的布局管理器吗?
  5. 如果4的答案是“是”,这不会导致OutwayManager类的激增,这将变得难以维护吗?
  6. 在我需要定义组件子项之间的比例的情况下(例如,child1 应使用 10% 的空间,child2 40%,child3 50%),是否可以在不实现自定义 LayoutManager 的情况下实现这一点?

答案 1
  1. 我应该完全避免使用这些方法吗?

    是,表示应用程序代码。

  2. 定义这些方法是有原因的。那么我应该什么时候使用它们呢?在什么情况下?目的何在?

    我不知道,我个人认为这是一个API设计事故。稍微受制于对儿童尺寸有特殊想法的复合成分。“稍微”,因为他们应该使用自定义布局管理器来实现他们的需求。

  3. 使用这些方法的负面后果究竟是什么?(我只能考虑在具有不同屏幕分辨率的系统之间增加可移植性。

    一些(不完整,不幸的是,由于SwingLabs迁移到 java.net)技术原因而中断,例如在规则(嘿嘿)或链接中提到@bendicott在他/她对我的答案的评论中找到。在社交方面,向你不幸的家伙展示大量的工作,他们必须维护代码,并且必须跟踪一个破碎的布局。

  4. 我不认为任何布局管理器都可以完全满足所有所需的布局需求。我真的需要为布局上的每一个小变化实现一个新的布局管理器吗?

    是的,有足够强大的布局管理器,可以很好地接近“所有布局需求”。三大是JGoodies FormLayout,MigLayout,DesignGridLayout。所以不,在实践中,除了简单的高度专业化环境之外,你很少编写布局管理器。

  5. 如果4的答案是“是”,这不会导致OutwayManager类的激增,这将变得难以维护吗?

    (4的答案是“不”。

  6. 在我需要定义组件的子项之间的比例的情况下(例如,子项 1 应使用 10% 的空间,子项 2 40%,子项 3 50%),是否可以在不实现自定义 LayoutManager 的情况下实现这一目标?

    任何一个三巨头都可以,甚至GridBag都不能(从来没有费心去真正掌握,太多的麻烦太少的力量)。


答案 2

一些启发式方法:

  • 当您真正想要覆盖 时,不要使用,就像在创建自己的组件时可能会做的那样,如下所示set[Preferred|Maximum|Minimum]Size()get[Preferred|Maximum|Minimum]Size()

  • 不要在可以依赖组件的仔细覆盖时使用,如此及下面所示。set[Preferred|Maximum|Minimum]Size()getPreferred|Maximum|Minimum]Size

  • 使用来派生后几何图形,如下图和此处所示。set[Preferred|Maximum|Minimum]Size()validate()

  • 如果组件没有首选大小,例如,您可能必须调整容器的大小,但任何此类选择都是任意的。注释可能有助于澄清意图。JDesktopPane

  • 当您发现必须遍历许多组件才能获得派生大小时,请考虑备用布局或自定义布局,如这些注释中所述。

enter image description here

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
 * @see https://stackoverflow.com/questions/7229226
 * @see https://stackoverflow.com/questions/7228843
 */
public class DesignTest {

    private List<JTextField> list = new ArrayList<JTextField>();
    private JPanel panel = new JPanel();
    private JScrollPane sp = new JScrollPane(panel);

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                DesignTest id = new DesignTest();
                id.create("My Project");
            }
        });
    }

    private void addField(String name) {
        JTextField jtf = new JTextField(16);
        panel.add(new JLabel(name, JLabel.LEFT));
        panel.add(jtf);
        list.add(jtf);
    }

    private void create(String strProjectName) {
        panel.setLayout(new GridLayout(0, 1));
        addField("First Name:");
        addField("Last Name:");
        addField("Address:");
        addField("City:");
        addField("Zip Code:");
        addField("Phone:");
        addField("Email Id:");
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
            .addPropertyChangeListener("permanentFocusOwner",
            new FocusDrivenScroller(panel));
        // Show half the fields
        sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        sp.validate();
        Dimension d = sp.getPreferredSize();
        d.setSize(d.width, d.height / 2);
        sp.setPreferredSize(d);

        JInternalFrame internaFrame = new JInternalFrame();
        internaFrame.add(sp);
        internaFrame.pack();
        internaFrame.setVisible(true);

        JDesktopPane desktopPane = new JDesktopPane();
        desktopPane.add(internaFrame);

        JFrame frmtest = new JFrame();
        frmtest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmtest.add(desktopPane);
        frmtest.pack();
        // User's preference should be read from java.util.prefs.Preferences
        frmtest.setSize(400, 300);
        frmtest.setLocationRelativeTo(null);
        frmtest.setVisible(true);
        list.get(0).requestFocusInWindow();
    }

    private static class FocusDrivenScroller implements PropertyChangeListener {

        private JComponent parent;

        public FocusDrivenScroller(JComponent parent) {
            this.parent = parent;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            Component focused = (Component) evt.getNewValue();
            if (focused != null
                && SwingUtilities.isDescendingFrom(focused, parent)) {
                parent.scrollRectToVisible(focused.getBounds());
            }
        }
    }
}

推荐