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

Should I avoid the use of set(Preferred|Maximum|Minimum) size methods in Java Swing?

提问人:Heisenbug 提问时间:8/29/2011 最后编辑:Ben the CoderHeisenbug 更新时间:4/11/2023 访问量:67464

问:

有几次,我因为建议使用以下方法而受到批评:

  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 的情况下实现这一点?
Java Swing 布局管理器

评论


答:

17赞 Thomas 8/29/2011 #1

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

也许会满足您的需求。除此之外,网络上还有大量的布局管理器,我敢打赌有一个适合您的要求。GridBagLayout

评论

0赞 Heisenbug 8/29/2011
谢谢你的回答。我必须假设你的意思也是:“根本不使用 setPreferredSize”,对吧?
1赞 Bigger 5/28/2013
GridBagLayout 使用约束,您可以在其中指定给定组件的 X 和 Y 中的“权重”,以便 LayoutManager 可以决定如何处理调整大小时的额外空间。但是你仍然需要/可以使用 setPreferredSize 来确定每个组件的首选大小,请注意,“preferred”并不意味着它会一直被遵守。对于特殊情况,您可能还需要 setMinimumSize 和 setMaximumSize。他们不是邪恶的,不要相信这一点。docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
22赞 Tom 8/29/2011 #2

如果您在 Java Swing 中遇到布局问题,那么我强烈推荐 Karsten Lentzsch 作为 Forms 免费软件库的一部分免费提供的 JGoodiesFormLayout

这个非常流行的布局管理器非常灵活,可以开发非常精美的 Java UI。

你可以在这里找到 Karsten 的文档,以及一些来自 eclipse 的相当不错的文档。

249赞 kleopatra 8/29/2011 #3
  1. 我应该完全避免使用这些方法吗?

    是,用于应用程序代码。

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

    我不知道,我个人认为这是 API 设计事故。对儿童尺寸有特殊想法的复合组件略微强迫。“稍微”,因为他们应该使用自定义 LayoutManager 实现他们的需求。

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

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

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

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

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

    (4 的答案是否定的。

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

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

评论

6赞 Andrew Thompson 8/30/2011
我不完全确定我至少在两种情况下同意这个建议。1) 自定义渲染组件 2) 使用 HTML 本身并不建议宽度。OTOH:我不确定我是否错过了什么。我会仔细审查线程上的回复,但如果您有任何评论,尤其是对后一种情况,我会很感兴趣。JEditorPane
15赞 Michael 7/9/2013
我简直不敢相信公认的答案是说要避免使用 setXXX() 方法。有时,您只需要它们向布局管理器提供提示。如果您正在布置一个面板,那么您绝对应该在必要时随意使用这些方法。话虽如此,我认为如果您使用适当的布局管理器,您会发现自己并不经常需要这些方法,但有时您只需要它们。尝试将 JComboBox 或 JSpinner 放在 BoxLayout 中X_AXIS而不是使用它们,相信您会发现那里需要 setMaximumSize()。
6赞 kleopatra 7/9/2013
@Michael不,我绝对不需要它 - 答案始终是使用一个体面的 LayoutManager 并在管理器级别(相对于组件级别)进行任何微调
8赞 Ti Strga 3/8/2014
你一直在说“使用一个像样的 LayoutManager 并告诉它你想要什么大小”,但你从来没有给出任何“像样”的 LayoutManager 的具体例子。而且没有一个标准管理器允许直接控制尺寸。
3赞 kleopatra 3/8/2014
@TiStrga好吧,从来没有明显错(只是告诉我你并没有真正尝试验证这一点;-) - 归根结底,这样的建议是个人偏好(你甚至可以自己写)。而且我很少犹豫在任何时候说出我的个人偏好,目前是 MigLayout。
109赞 trashgod 8/29/2011 #4

一些启发式方法:

  • 当您真正想要覆盖时,请不要使用,就像在创建自己的组件时所做的那样,如下所示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()

  • 如果组件没有首选大小,例如 ,您可能必须在调用 之后调整容器的大小,但任何此类选择都是任意的。评论可能有助于澄清意图。JDesktopPanepack()

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

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

评论

2赞 kleopatra 8/29/2011
不同意(正如您可能已经猜到的那样:-)通过“外部因素”进行推理:XXSize 属性旨在表达内部需求。从外部调整这些是误用,也就是黑客攻击。如果您想要一个(内部或 J 型)框架,其特定尺寸相对于它的首选......调整框架大小,而不是内容大小
2赞 Heisenbug 8/29/2011
@kleopatra:只是坚持一点:如果 setXXSize 方法不应该从外部使用,为什么没有被声明为私有或受保护?这不是缺乏设计吗?public 修饰符不是隐式地告诉用户可以使用这些方法吗?
3赞 trashgod 8/29/2011
我必须同意@kleopatra:总是用任意选择替换组件的计算。setPreferredSize()
2赞 David Kroukamp 10/4/2012
@trashgod +100 给你,我认为重写这些方法没有问题,甚至调用它们(但当然这意味着你有一个自定义组件,因此重写会更好)
7赞 trashgod 10/4/2012
@DavidKroukamp:谢谢。我尊重克列奥帕特拉的更多经验,但我认为批判性地审视相反的观点是有价值的。
53赞 David Kroukamp 10/1/2012 #5

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

不可以,没有正式证据表明不允许调用或覆盖这些方法。事实上,甲骨文表示,这些方法用于给出大小提示:http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment

扩展 Swing 组件(而不是在自定义组件实例上调用该方法)时,它们也可能被重写(这是 Swing 的最佳实践)

最重要的是,无论您如何指定组件的大小,请确保组件的容器使用遵循请求的组件大小的布局管理器。

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

当您需要向容器布局管理器提供自定义大小提示时,以便组件布局良好

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

  • 许多布局管理器不注意组件请求的最大大小。但是,确实如此。此外,它还能够显式设置最小、首选或最大尺寸,而无需接触组件。BoxLayoutSpringLayoutGroupLayout

  • 确保您确实需要设置组件的确切大小。每个 Swing 组件都有不同的首选大小,具体取决于它使用的字体和外观。因此,设置大小可能会在不同的系统上产生不同的 UI 外观

  • 有时会遇到文本字段的问题,其中,如果容器的大小小于首选大小,则使用最小大小,这可能会导致文本字段大幅缩小。GridBagLayout

  • JFrame不强制覆盖,仅调用其作品getMinimumSize()setMinimumSize(..)

我不认为任何 LayoutManager 可以完全满足所有所需的布局 需要。我真的需要为每个 LayoutManager 实现一个新的 LayoutManager 吗? 我的布局变化不大?

如果通过实现,你的意思是使用,那么是的。没有一个可以处理所有事情,每个都有其优点和缺点,因此每个都可以一起使用以产生最终的布局。LayoutMangerLayoutManager

参考:

评论

3赞 kleopatra 10/1/2012
提供自定义大小提示 这本身就是一个矛盾:提供大小提示(以 px 为单位)是组件的专属任务。它根据内部状态详细信息来计算它们,除了它自己之外,其他任何一方都无法知道(也无法跟踪)。从客户端的角度来看,自定义方式可以是合适的 LayoutManager 和/或组件上的专用 api,允许根据“语义”大小相关属性(例如文本组件中的行/列数)配置大小要求
4赞 David Kroukamp 10/1/2012
@kleopatra我仍然想知道为什么 Oracle 会告诉我们如何使用这些方法以及使用它们的正确方法。我们可能有自己的偏好,但我们不能说设计师在没有证据表明这一点的情况下不使用它。但这就是为什么我提出赏金的原因,看看它是否会吸引其他人,这些人可以从可靠的来源提供信息,其中 oracle 声明根本不使用这些方法(因此,如果你这样做,就会成为不好的做法,例如,必须在 JSplitPane 等东西上调用 setMinimumSize,这可以在 Oracle 拆分窗格教程中看到。
4赞 trashgod 10/2/2012
@David:我开始将这些方法视为一个危险信号,即使文档建议,我也可能在这里结束。我几乎总是应该覆盖 ,其中可以访问所需的几何图形;即使是简短的例子也被回收利用,比我想想的要多。+1 提及布局管理器之间的差异并引用教程。setXxxSizegetXxxSize
1赞 trashgod 10/4/2012
哦,在我上面的评论中,我的意思是在这里引用答案。
16赞 TT. 6/6/2013
+1 “不,没有正式证据表明不允许调用或覆盖这些方法。”点对点。标记为答案的帖子是普通的 BS。
18赞 Michael 3/26/2013 #6

大多数人对这些方法知之甚少。您绝对不应该忽视这些方法。由布局管理器决定他们是否遵循这些方法。此页面有一个表格,显示哪些布局管理器支持以下哪些方法:

http://thebadprogrammer.com/swing-layout-manager-sizing/

我已经编写 Swing 代码 8+ 年了,JDK 中包含的布局管理器一直满足我的需求。我从来不需要第三方布局管理器来实现我的布局。

我要说的是,在你确定需要它们之前,你不应该尝试用这些方法给布局管理器提示。在不给出任何大小提示的情况下进行布局(即让布局管理器完成其工作),然后如果需要,您可以进行细微的更正。

评论

1赞 kleopatra 7/10/2013
要么是轻微的误解(你),要么是误解(我),请做出你的选择:-)你不断重复(在这里,在你的博客中,在与BoxLayout相关的答案中)设置XXSize是重要的 - 实际上LayoutManager对XXSize感兴趣(或不感兴趣),这是大小调整提示,与它是如何产生的(由组件内部计算或由应用程序代码手动强制)
1赞 Michael 7/10/2013
我不确定我是否理解你在这里得到什么。我在上面提到 XXSize() 方法只是提示。如果需要,我真的认为给布局管理器一点提示并没有错。在我的 swing 代码中,您会偶尔找到一个 setXXSize() 方法。不多,但每隔一段时间我就会发现它们被需要。JComboBox 和 JSpinner 经常需要提示。尤其是实现后填充的 JComboBox。你似乎反对这些方法的任何和所有使用,我不知道为什么。(也许我是那个错过了这艘船的人,我猜)。
5赞 kleopatra 7/10/2013
不是方法是提示,属性是:组件应该报告所有提示的合理内容,有些(如 f.i. JComboBox)不会 - 返回 maxInteger 左右。这是一个错误,应该由组合修复。至于你的习惯:当维护者同事必须清理它时,一定要离得很远:)硬编码提示往往会在最轻微的更改时破坏布局,并且很难被检测为布局损坏的原因。
26赞 Jason C 3/11/2014 #7

这里有很多很好的答案,但我想补充一点关于你通常应该避免这些的原因(这个问题刚刚在一个重复的主题中再次出现):

除了少数例外,如果您使用这些方法,您可能正在微调您的 GUI,使其在特定的外观和感觉上看起来不错(以及您的系统特定设置,例如您喜欢的桌面字体等)。这些方法本身并不是邪恶的,但使用它们的典型原因是邪恶的。一旦您开始调整布局中的像素位置和大小,您就有可能在其他平台上破坏 GUI(或至少看起来很糟糕)。

例如,尝试更改应用程序的默认外观。即使只是使用平台上可用的选项,您也可能会惊讶于结果的呈现效果有多差。

因此,为了让你的 GUI 在所有平台上都能正常运行和美观(请记住,Java 的主要好处之一是它的跨平台性),你应该依靠布局管理器等来自动调整组件的大小,以便它在特定开发环境之外正确呈现。

综上所述,您当然可以想象这些方法是合理的情况。同样,它们本质上并不是邪恶的,但它们的使用通常是一个的危险信号,表明潜在的 GUI 问题。只要确保你意识到,如果你/当你使用它们时,很有可能出现并发症,并始终尝试思考是否有另一种独立于外观和感觉的解决方案来解决你的问题--通常你会发现这些方法不是必需的。

顺便说一句,如果你发现自己对标准的布局管理器感到沮丧,有很多很好的免费开源第三方管理器,例如JGoodies的FormLayoutMigLayout。一些 GUI 构建器甚至内置了对第三方布局管理器的支持——例如,Eclipse 的 WindowBuilder GUI 编辑器附带了对 和 的支持。FormLayoutMigLayout

评论

2赞 kleopatra 3/11/2014
+1 一个体贴的答案 - 只是不同意他们并不是天生邪恶的,因为他们是:-)通常,外部客户端没有任何机会猜测 - 并且仅仅假设与外部人员所能得到的一样接近 - 一半的正确布局提示:只有组件本身始终拥有所有信息,以返回任何有用的信息。而且,由于外人干涉的那一刻起,他们有责任使这些提示保持最新,而他们无法做到。
2赞 Jason C 3/11/2014
嗯,你知道,我对这类事情有一种更“枪不杀人,人杀人”的看法。:)如果有人使用这些方法,他们需要注意一些事情,比如你提出的关于布局提示的不可预测用法的优点(这就是为什么这些方法合适的情况确实很少见)。
0赞 Gee Bee 3/13/2017
我认为设置首选尺寸根本不是一个大的危险信号。不设置它是一个很大的危险信号。让我详细说明一下。布局管理器 - 无论它多么聪明 - 都不知道 gui 小部件的逻辑功能。例如,布局管理器无法区分用于输入邮政编码的 JTextField 和用于输入名称的 JTextField。同样,它无法区分 JTextField 旁边的工具按钮或窗体底部的大 OK 按钮。因此,要么需要更好的小部件集,要么需要一些尺寸提示,不是吗?
0赞 Jason C 3/13/2017
@GeeBee 不,事实上,这是危险信号的一个典型例子。您应该做的是使用 JTextField.setColumns 设置列计数,从而相应地调整首选大小。如果你这样做,那么你就是在硬编码一个大小,这将根据平台字体大小破坏你的布局。下面是网格包布局中的一些文本字段,其中适当调用了 setColumns。对于按钮,请使用适当的布局/网格粗细来控制大小。setPreferredSize
0赞 Jason C 3/13/2017
@GeeBee 现在,正确完成此操作后,请注意当我减小字体大小时文本字段宽度是如何减小的:i.snag.gy/ZULulh.jpg。现在,即使即时更改字体大小也会自动工作,而不必重新计算所有文本字段宽度并为每个文本字段再次显式调用 setPreferredSize,您所要做的就是使布局失效,它们的大小将进行调整。
7赞 Gee Bee 2/17/2016 #8

我看到它与公认的答案不同。

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

永远不要回避!它们用于向布局管理器表达组件的大小限制。如果您不使用任何布局管理器,则可以避免使用它们,并尝试自行管理可视化布局。

不幸的是,Swing 没有合理的默认尺寸。但是,与其设置组件的尺寸,不如使用合理的默认值降低自己的组件。(在这种情况下,您可以在后代类中调用 setXXX。或者,您可以覆盖 getXXX 方法以获得相同的效果。

2)定义方法有原因。那么我应该什么时候使用它们呢?在什么情况下?出于什么目的?

总是。创建组件时,请根据该组件的使用情况设置其实际的最小/首选/最大大小。例如,如果您有一个用于输入国家/地区符号(如英国)的 JTextField,则其首选大小应与适合两个字符(使用当前字体等)一样宽,但让它变大可能毫无意义。毕竟,国家符号是两个字符。 相反,如果您有一个用于输入客户名称的 JTextField,它可以具有 20 个字符的首选大小,但如果调整布局大小,它可能会变得更大,因此将最大大小设置为更多。同时,拥有 0px 宽的 JTextField 是没有意义的,因此请设置一个实际的最小大小(我会说 2 个字符的像素大小)。

3)使用这些方法的负面后果究竟是什么?

(我只能考虑在具有不同屏幕分辨率的系统之间增加可移植性)。

没有负面后果。这些是布局管理器的提示。

4)我不认为任何布局管理器可以完全满足所有所需的布局需求。

我真的需要为布局上的每个小变化实现一个新的 LayoutManager 吗?

不,绝对不是。通常的方法是级联不同的基本布局管理器,例如水平布局和垂直布局。

例如,下面的布局:

<pre>
+--------------+--------+
| ###JTABLE### | [Add]  | 
| ...data...   |[Remove]|
| ...data...   |        |
| ...data...   |        |
+--------------+--------+
</pre>

有两个部分。左右部分为水平布局。右侧部分是添加到水平布局中的 JPanel,此 JPanel 具有垂直布局,垂直布局按钮。

当然,这在现实生活中的布局可能会变得棘手。因此,如果您要开发任何严肃的东西,基于网格的布局管理器(如 MigLayout)会更好。

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

不,你绝对不应该开发布局管理器,除非你需要一些非常特别的东西。

6) 在我需要定义比例的情况下......

在组件的子项之间(例如,child1 应使用 10% 的空间,child2 应使用 40%,child3 应使用 50%),是否可以在不实现自定义 LayoutManager 的情况下实现这一点?

基本上,一旦设置了正确的首选尺寸,您可能不想以百分比为单位做任何事情。简单地说,因为百分比是没有意义的(例如,JTextField 的 10% 是没有意义的 - 因为可以缩小窗口以使 JTextField 变为 0px 宽,或者可以扩展窗口以使 JTextField 跨多显示器设置中的两个显示器)。

但是,有时您可以使用百分比来控制 gui 的较大构建块(例如面板)的大小。

您可以使用 JSplitPane,您可以在其中预设两侧的比例。或者,您可以使用 MigLayout,它允许您以百分比、像素和其他单位设置此类约束。

评论

0赞 Loduwijk 3/9/2017
真?这是 0?这比公认的有 100+ ups 的答案要好。这基本上是说“Thou shalt nevar use setPreferredSize!”,这太可怕了。在我的工作中,有很多特定的尺寸要求,例如“触摸屏上的按钮必须是 [X] x [Y],中间的间距为 [M]x[N]”安全要求。 是最好的方法。简单明了,无需自定义布局管理器。我主要使用一些和,在方便的时候嵌套。这是一个强大的组合,易于使用。btnBar.setPreferredSize( dimTouchBtn );GridBagLayoutBorderLayoutBoxLayout
0赞 Loduwijk 3/9/2017
我在上面的评论中很仓促。这是我接受答案后看到的第一个答案。为什么 SO 不再按票数排序?我认为这是最初计票的核心原因之一。尽管如此,我仍然坚持原始评论;这是更好的答案之一。除了它的点 #6 - 那个没有那么好。调整大小的原因有很多(少数仍然可能很大),而 GridBagLayout 在我遇到的大多数情况下都很好地支持了这一点。
0赞 Gee Bee 3/13/2017
我认为调整大小与不调整大小不应被视为宗教决定。在有些用例中,没有人愿意调整任何内容的大小,例如,如果您为自助服务终端开发一个具有预设固定分辨率的 GUI。如果您有不同的目标,例如工业 HMI 显示器和“按钮”的情况,那么是的,触摸屏上的按钮必须至少有 1 厘米 x 1 厘米。在这种情况下,屏幕的 DPI 会设置调整大小的方式。其他输入(如文本字段)可能根本不会垂直调整大小,有时(例如邮政编码)水平调整大小也毫无意义。
1赞 MiguelMunoz 10/18/2018 #9

我应该完全避免使用这些方法吗?我不会说“避免”它们。我想说的是,如果你认为你需要它们,你可能做错了什么。组件大小是在上下文中确定的。例如,文本组件大小由指定的行数和列数以及可能选择的字体决定。按钮和标签大小将是图形的大小(如果已设置)或显示所设置文本所需的空间。每个组件都有一个自然大小,布局管理器将使用这些组件来布置所有内容,而无需您指定大小。主要的例外是 JScrollPane,它的大小与它所包含的任何内容无关。对于这些,我有时会调用 ,并让该大小确定初始窗口大小,方法是调用 。通常,我会让窗口大小决定 JScrollPane 的大小。用户将确定窗口的大小。许多布局管理器无论如何都会忽略您设置的大小,因此它们通常不会做太多好事。setSize()JFrame.pack()

定义这些方法是有原因的。那么我应该什么时候使用它们呢?在什么情况下?出于什么目的?我相信添加它们是为了向布局管理器提供提示。它们可能是出于历史原因而编写的,因为布局管理器是新来的,人们并不完全信任他们。我认识一些开发人员,他们避免使用布局管理器并手动放置所有内容,只是因为他们不想费心学习新的范式。这是一个可怕的主意。

使用这些方法的负面后果究竟是什么?(我只能考虑在具有不同屏幕分辨率的系统之间增加可移植性)。它们效率低下,并且会产生糟糕的布局,物体被挤压或拉伸到非自然大小。而且布局会很脆弱。更改窗口大小有时会破坏布局并将内容放在错误的位置。

我不认为任何 LayoutManager 可以完全满足所有所需的布局需求。我真的需要为布局上的每个小变化实现一个新的 LayoutManager 吗?不应“实现”新的 LayoutManager。您应该实例化现有的。我经常在一个窗口中使用多个布局管理器。每个 JPanel 都有自己的布局管理器。有些人对嵌套布局犹豫不决,因为它们很难维护。当我使用它们时,我给每个人自己的创建方法,以便更容易看到每个人的作用。但我从不“实现”布局管理器。我只是实例化它们。

如果 4 的答案是“是”,这不会导致 LayoutManager 类的激增而变得难以维护吗?如果要为布局中的细微变化实现新的布局管理器类,则使用它们是错误的。如果您只是实现新的布局管理器,那么您可能做错了什么。我唯一一次扩展 LayoutManager 类,是向 JScrollPane 添加缩放滑块。

在我需要定义组件的子项之间的比例的情况下(例如,child1 应使用 10% 的空间,child2 40%,child3 50%),是否可以在不实现自定义 LayoutManager 的情况下实现这一点?JSplitPane 有一种方法可以指定每个组件应获得的百分比。默认情况下,分隔线是可移动的,但您可以根据需要将其关闭。我不怎么使用这个功能。我通常有一些组件占用一定大小,其余空间由滚动窗格占用。滚动窗格大小将随窗口大小进行调整。如果有两个并排滚动窗格,则可以将它们放在 JSplitPane 中,并指定在用户展开和收缩窗口时为每个滚动窗格提供的新空间百分比。