tangguo

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

java

次批评我建议使用以下方法:

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize
    在Swing组件上。当我要定义显示组件之间的比例时,我看不到任何替代方法。我被告知:

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

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

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

阅读 385

收藏
2020-11-19

共2个答案

小编典典

我应该完全避免使用那些方法吗?

是,表示应用程序代码。

出于某种原因定义了这些方法。那么我什么时候应该使用它们呢?在哪种情况下?出于什么目的?

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

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

某些技术原因(不完整,不幸的是,由于SwingLabs迁移到java.net而导致链接断开),例如,在“规则”(hehe)或他/她对我的答案的评论中找到的@bendicott链接中提到了技术原因。在社交上,将大量工作交给不幸的同事,他必须维护代码并必须查找损坏的布局。

我认为任何LayoutManager都不能完全满足所有所需的布局需求。我真的需要为我的布局中的每个小变化实现一个新的LayoutManager吗?

是的,有足够强大的LayoutManagers可以很好地满足“所有布局需求”。前三个是JGoodies FormLayout,MigLayout,DesignGridLayout。因此,实际上,除了简单的高度专业化的环境外,您很少编写LayoutManager。

如果对4的回答为“是”,这是否会导致LayoutManager类的泛滥而导致难以维护?

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

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

三巨头中的任何一个都不能甚至不可以使用GridBag(永远不要操心真正的大师,以太少的力气就麻烦很多)。

2020-11-19
小编典典

一些启发式:

不要使用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,您可能必须调整容器的大小,但是任何这样的选择都是任意的。发表评论可能有助于澄清意图。

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

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