我应该避免在 Java Swing 中使用 set(Preferred\|Maximum\|Minimum)Size 方法吗?

新手上路,请多包涵

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

  1. 设置首选尺寸
  2. 设置最小尺寸
  3. 设置最大尺寸

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

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

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

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

原文由 Heisenbug 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 833
2 个回答
  1. > 我应该完全避免使用这些方法吗?

是的应用程序代码。

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

我不知道,我个人认为这是一个 API 设计事故。受对子尺寸有特殊想法的复合组件的轻微影响。 “稍微”,因为他们应该已经使用自定义 LayoutManager 实现了他们的需求。

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

一些(不完整,不幸的是,由于 SwingLabs 迁移到 java.net,链接已断开)技术原因在 规则(呵呵) 中或在他/她对 我的回答 的评论中找到的 链接@bendicott 中提到。在社交方面,将大量工作交给你不幸的家伙,他必须维护代码并且必须追踪损坏的布局。

  1. > 我认为没有任何 LayoutManager 可以完全满足所有所需的布局需求。我真的需要为布局上的每个小变化实现一个新的 LayoutManager 吗?

是的,有足够强大的 LayoutManager 可以很好地满足“所有布局需求”。三大类是 JGoodies FormLayout、MigLayout、DesignGridLayout。所以不,在实践中,除了简单的高度专业化的环境外,您很少编写 LayoutManagers。

  1. 如果对 4 的回答是“是”,这是否会导致 LayoutManager 类的激增而变得难以维护?

    (对 4 的回答是“否”。)

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

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

原文由 kleopatra 发布,翻译遵循 CC BY-SA 3.0 许可协议

一些启发式:

  • 不要使用 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 ,您可能必须在调用 pack() 调整容器的大小,但任何此类选择都是任意的。注释可能有助于阐明意图。

  • 如这些 评论 中所述,当您发现必须循环遍历许多组件以获得派生尺寸时,请考虑替代或自定义布局。

在此处输入图像描述

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

原文由 trashgod 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题