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

506

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

  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的情况下实现?
9个回答

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

    对于应用程序代码来说是的。

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

    我不知道,个人认为这是一个API设计错误。稍微受到复合组件对子元素大小的特殊想法的影响。"稍微",因为他们应该使用自定义LayoutManager实现他们的需求。

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

    一些(不完整,不幸的是由于SwingLabs迁移到java.net而导致链接失效)技术原因例如在Rules(hehe)link @bendicott在my answer中发现的评论中提到。社交方面,会给你不幸的同事带来大量的工作,他必须维护代码并跟踪损坏的布局。

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

    是的,有足够强大的LayoutManager可以满足非常好的近似于"所有布局需求"。最重要的三个是JGoodies FormLayout,MigLayout,DesignGridLayout。因此,在实践中,除了简单的高度专业化的环境之外,你很少编写LayoutManager。

  5. 如果问题4的答案是"是",这不会导致LayoutManager类的增加,从而难以维护吗?

    (问题4的答案是"否".)

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

    任何一个大三的都可以,甚至GridBag也可以(从未真正掌握,太麻烦了,功率太小)。


6
我不完全确定我同意这个建议在至少两种情况下。1)自定义渲染组件 2)使用不建议宽度的HTML的JEditorPane。但是,我不确定是否有什么遗漏。我将仔细查看线程上的回复,但如果您对后一种情况有任何评论,我也很感兴趣。 - Andrew Thompson
15
我不敢相信被接受的答案是建议避免使用setXXX()方法的答案。有时候你需要它们来为布局管理器提供提示。如果你正在对面板进行布局,则在必要时绝对可以自由地使用这些方法。我认为,如果你使用适当的布局管理器,你会发现自己很少需要这些方法,但在某些情况下,你仍然需要它们。试着将JComboBox或JSpinner放入X_AXIS BoxLayout中并不使用它们,相信你会发现需要setMaximumSize()方法。 - Michael
6
不,我绝对不需要它——答案始终是使用良好的LayoutManager,并在_manager_级别上进行任何微调(而不是在组件级别上)。 - kleopatra
8
您在stackoverflow上一直强调“使用良好的LayoutManager并告诉它您想要的大小”,但从未给出任何“良好”的LayoutManager的具体示例。而且标准Manager都不允许直接控制大小。 - Ti Strga
3
@TiStrga 嗯,"从来没有" 显然是错误的(这告诉我您并没有真正尝试验证)-说到底,这样的建议是个人偏好(甚至您自己都可以编写)。而且我很少犹豫在任何时刻表述我个人的喜好,目前我最喜欢的是MigLayout。 - kleopatra
显示剩余7条评论

109

一些启发:

  • 在创建自己的组件时,如果你的确想要覆盖get[Preferred|Maximum|Minimum]Size(),请不要使用set[Preferred|Maximum|Minimum]Size()。这个例子可以在这里看到。

  • 如果一个组件已经仔细地重写了getPreferred|Maximum|Minimum]Size,请不要使用set[Preferred|Maximum|Minimum]Size()。这个例子可以在这里和下面看到。

  • 请使用set[Preferred|Maximum|Minimum]Size()来派生出validate()后的几何形状,如下所示和这里所示。

  • 如果一个组件没有首选大小,比如JDesktopPane,你可能需要在调用pack()之后调整容器大小,但这种选择是任意的。注释可以帮助澄清意图。

  • 当你发现需要循环遍历许多组件来获取派生的大小时,请考虑使用替代或自定义布局,这在这些注释中提到。

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://dev59.com/BGw05IYBdhLWcg3weBlF
 * @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
不同意(正如您可能已经猜到的那样 :-))使用“外部因素”的理由:XXSize属性旨在表达仅限内部的需求。从外部调整这些属性是误用,也就是黑客行为。如果您想要一个相对于其首选大小具有特定大小的(内部或J-)框架...请调整框架的大小,而不是内容。 - kleopatra
2
@kleopatra:只是稍微坚持一下:如果 setXXSize 方法不应该从外部使用,为什么没有声明为 private 或 protected?这不是设计上的缺陷吗?公共修饰符难道不会默认告诉用户可以使用这些方法吗? - Heisenbug
3
我同意@kleopatra的观点:setPreferredSize()总是用任意选择替换组件的计算。 - trashgod
2
@trashgod +100 分给你。我认为覆盖这些方法甚至调用它们都没有问题(但前提是你有一个自定义组件,因此覆盖会更好)。 - David Kroukamp
7
谢谢你。我尊重kleopatra更丰富的经验,但我认为批判性地审视相反观点是有价值的。 - trashgod
显示剩余4条评论

53

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

不需要,目前没有正式的证据表明调用或重写这些方法是不允许的。事实上,Oracle表示这些方法用于提供大小提示: http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment

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

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

这些方法是有原因定义的。那么我什么时候应该使用它们?在哪个上下文中?用于什么目的?

当您需要向容器的布局管理器提供自定义的大小提示以使组件能够良好地布局时。

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

  • 许多布局管理器不会注意组件请求的最大大小。 但是,BoxLayout和SpringLayout会注意到。 而且,GroupLayout提供了在不接触组件的情况下显式设置最小、首选或最大大小的能力。
  • 确保您确实需要设置组件的确切大小。每个Swing组件都有不同的首选大小,取决于它使用的字体和外观。因此,设置固定大小可能会在不同的系统上产生各种外观的UI。
  • 有时可能会遇到在GridBagLayout和文本字段中遇到问题,如果容器的大小小于首选大小,则使用最小大小,这可能会导致文本字段收缩很多。
  • JFrame 不强制执行重写的 getMinimumSize(),只有调用其上的 setMinimumSize(..) 才有效

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

    如果你的意思是使用,那么是的。没有一种 LayoutManager 能够处理所有情况,每种 LayoutManager 都有其优缺点,因此可以将它们组合使用以产生最终的布局。

    参考资料:


    3
    “提供自定义大小提示”本身就是一个矛盾:提供大小提示(以像素为单位!)是组件的“唯一”任务。它根据内部状态细节进行计算,除了组件本身以外,其他任何人都无法知道(也无法跟踪)。从客户端的角度来看,定制的方式可以是合适的布局管理器和/或专门的 API,允许按照“语义”大小相关属性配置大小要求,例如文本组件中的行数/列数。 - kleopatra
    4
    @kleopatra,我仍然希望知道为什么Oracle告诉我们如何使用这些方法以及正确的使用方式。我们可能有自己的偏好,但我们不能说设计者不打算使用它们,因为没有证据表明这一点。但这就是为什么我设置了悬赏,希望能吸引其他人提供来自可信来源的信息,其中Oracle声明根本不使用这些方法(因此如果您这样做,例如在JSplitPane上调用setMinimumSize等,这将被视为不良实践)。这可以在Oracle拆分窗格教程中看到。 - David Kroukamp
    4
    @David: 我已经开始认为 setXxxSize 方法是一个警告信号,它可能会导致我最终进入这里(https://dev59.com/blnUa4cB1Zd3GeqPa31l#6785121),即使文档中建议使用。我几乎总是应该重写 getXxxSize 方法,在那里可以访问所需的几何信息;而且即使短小的示例也被重复使用得比我想象的要多。感谢您提到布局管理器的差异并引用教程,我给您点赞。 - trashgod
    1
    在我上面的评论中,我想引用这里的答案(https://dev59.com/UGjWa4cB1Zd3GeqPtLXa#12532237)。 - trashgod
    16
    +1 "不,没有正式证据表明调用或覆盖这些方法是不允许的。" 完全正确。被标记为答案的帖子纯属胡说八道。 - TT.

    26

    这里已经有很多好的答案了,但是我想再补充一些关于为什么通常应该避免使用这些方法的原因(这个问题在一个重复的主题中又出现了):

    除非少数例外,如果你正在使用这些方法,你可能在微调GUI以在特定的外观和系统设置下看起来好(例如,你喜欢的桌面字体等)。这些方法本身并不是根本性的恶,但是使用它们的典型原因是。一旦你开始在布局中微调像素位置和大小,你就有可能使你的GUI在其他平台上破损(或者最低限度,看起来很差)。

    举个例子,试着改变你的应用程序的默认外观和感觉。即使只是使用你平台上可用的选项,你也可能会惊讶于结果渲染得有多糟糕。

    因此,在保持你的GUI在所有平台上功能正常且外观漂亮的前提下(记住,Java的主要好处之一是跨平台性),你应该依赖于布局管理器等自动调整组件大小的方法,以便在你特定的开发环境之外正确地呈现。

    所有这些,你当然可以想象出这些方法被证明是合理的情况。再次强调,它们本质上并不邪恶,但它们的使用通常是潜在GUI问题的一个重要红色信号。请确保你意识到如果/当你使用它们时可能会出现高度复杂的情况,并且始终尝试思考是否有另一种与外观和感觉无关的解决方案来解决问题 - 更多的时候,您会发现这些方法是不必要的。
    顺便说一下,如果你发现自己对标准布局管理器感到沮丧,有很多好的免费、开源的第三方布局管理器,例如JGoodies' FormLayoutMigLayout。一些GUI构建器甚至内置支持第三方布局管理器 - 例如,Eclipse的WindowBuilder GUI编辑器附带了对FormLayoutMigLayout的支持。

    2
    给出一个周到的回答,只是不同意“它们本质上并不邪恶”的说法,因为它们确实是。通常情况下,外部客户根本没有机会猜测 - 只有组件本身始终拥有所有信息才能返回任何有用的提示。而且自从外部干预以来,他们就有责任保持这些提示最新,但他们做不到。 - kleopatra
    2
    嗯,你知道,我对这些事情有一种更像是“枪不杀人,人杀人”的看法。 :) 如果有人使用这些方法,他们必须意识到像你提出的关于布局提示的不可预测使用的好处(这就是为什么适用这些方法的情况确实很少)。 - Jason C
    @GeeBee 现在,正确完成后,请注意当我减小字体大小时文本字段宽度如何减小:https://i.snag.gy/ZULulh.jpg。现在即使动态更改字体大小也会自动工作,而不是您必须重新计算所有文本字段宽度并为每个显式调用setPreferredSize,您只需使布局无效即可,它们的大小将自动调整。 - Jason C
    我不建议在考虑字体大小之前硬编码任何尺寸 - 如果没有直接传达这一点,我很抱歉。我想指出的是,布局管理器不知道小部件的逻辑功能,因此没有意义的尺寸操作,除非我们给出大小提示。例如,将5位数字邮政编码文本字段缩小到15像素宽 - 仅仅因为它有一些权重并且用户在没有约束的情况下缩小了窗口是完全错误的。但将50个字符的电子邮件字段缩小到10个字符是可以的。布局管理器看不到区别,除非我们告诉它。 - Gee Bee
    这包括设置最小、首选和最大尺寸 - 如果我们可以以字符(setColumns)设置尺寸,那将非常好。我们是否有针对最小-首选-最大、宽度和高度的setColumns?您能否轻松地告诉JScrollpane中的JList应该至少可见2行,最多可见10行,而不设置大小提示?当然,我不建议使用硬编码数字,因为像素尺寸取决于字体、JList的标题高度等等...但归根结底,我们需要设置。 - Gee Bee
    显示剩余2条评论

    22
    如果您在Java Swing中遇到布局问题,我强烈推荐Karsten Lentzsch提供的JGoodies FormLayout,它是Forms免费软件库的一部分here。这个非常受欢迎的布局管理器非常灵活,可以开发出非常精美的Java UI。您可以在here找到Karsten的文档,并且从eclipse here获得一些非常好的文档。

    18

    这些方法大多数人都理解不好,但你绝不能忽略这些方法。是否使用这些方法取决于布局管理器。此页面有一个表格显示了哪些布局管理器支持这些方法:

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

    我写Swing代码已经有8年以上的经验,JDK中包含的布局管理器一直满足我的需求。我从未需要第三方布局管理器来实现我的布局。

    我要说的是,在确定需要它们之前,不要尝试使用这些方法给布局管理器提供提示。首先进行布局而没有提供任何大小提示(即让布局管理器完成它的工作),然后在需要时可以进行微小的更正。


    1
    可能存在一些误解(你的)或者不理解(我的),随你选择 :-) 你在重复强调(这里、博客中、与BoxLayout相关的回答中)_set_XXSize很重要,实际上LayoutManager对于XXSize是否感兴趣,即独立于其来源(组件内部计算还是由应用程序代码手动强制)的_sizing hint_。 - kleopatra
    1
    我不确定我理解你在这里的意思。我在上面提到XXSize()方法只是提示。如果需要,给布局管理器一点提示,我真的看不出有什么问题。在我的swing代码中,偶尔会发现一些setXXSize()方法。不多,但有时我发现它们是必要的。JComboBox和JSpinner经常需要提示。特别是在实现后填充的JComboBox。你似乎反对任何和所有使用这些方法,我不知道为什么。(也许我是错过了这个吧)。 - Michael
    5
    提示并非方法,而是属性:组件应该对所有提示报告合理的内容,但某些组件(例如JComboBox)返回了maxInteger等不合理的值。这是一个错误,应该由组合框修复。至于你的习惯:确保在维护同事清理时要离得远 :) 硬编码的提示往往会在最微小的更改时破坏布局,并且很难检测到它们作为破坏布局原因的情况。 - kleopatra

    17
    在需要定义组件子元素之间比例的情况下(例如child1使用10%空间,child2使用40%,child3使用50%),是否可以在不实现自定义布局管理器的情况下实现呢?
    也许GridBagLayout可以满足您的需求。除此之外,网上有大量的布局管理器,我相信一定有一个符合您的要求。

    谢谢你的回答。我得假设你也是指“根本不要使用setPreferredSize”,对吗? - Heisenbug
    1
    GridBagLayout 使用约束条件,其中可以指定给定组件的 X 和 Y 的“权重”,因此 LayoutManager 可以决定在重新调整大小时如何处理额外的空间。但是您仍然需要/可以使用 setPreferredSize 来确定每个组件的首选大小,请注意,“首选”并不总是能够被遵守。对于特殊情况,您可能还需要设置 setMinimumSize 和 setMaximumSize。它们并不是邪恶的,不要相信那种说法。http://docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html - Bigger

    7

    我对被接受的答案有不同看法。

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

    永远不要避免使用它们!它们用于向布局管理器表达组件的大小约束条件。如果您没有使用任何布局管理器并尝试自己管理视觉布局,则可以避免使用它们。

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

    2)这些方法已经被定义了一个原因。那么我应该在什么情况下使用它们?使用场景是什么?用途是什么?

    总是使用。当您创建组件时,请根据该组件的使用设置其实际最小/首选/最大尺寸。例如,如果您有一个用于输入国家符号(例如UK)的JTextField,则其首选尺寸应足够宽以容纳两个字符(使用当前字体等),但可能让它变得更大是毫无意义的。毕竟,国家符号只有两个字符。

    相反,如果您有一个用于输入客户姓名等信息的JTextField,则其首选尺寸可以为像20个字符的像素大小一样,但在布局调整大小时可以变大,因此将最大尺寸设置为更大。同时,拥有0像素宽的JTextField是无意义的,因此请设置合理的最小尺寸(我会说2个字符的像素大小)。

    3)使用这些方法的负面影响到底是什么?

    (我只能想到增加了不同屏幕分辨率系统之间的可移植性。)

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

    4)我认为任何LayoutManager都不能完全满足所有所需的布局需求。

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

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

    例如,下面的布局:

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

    这个布局有两个部分。左边和右边是水平布局。右边是添加到水平布局中的JPanel,并且这个JPanel具有垂直布局,可以将按钮垂直布局。

    当然,在实际布局中可能会变得棘手。因此,基于网格的布局管理器(例如MigLayout)更适合您开发任何严肃的内容。

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

    不,除非您需要非常特殊的东西,否则绝对不应该开发布局管理器。

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

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

    基本上,一旦设置了首选大小,您可能不想使用百分比做任何事情。只是因为百分比是无意义的(例如,将JTextField的大小设置为窗口大小的10%是无意义的-因为可以缩小窗口,使JTextField变为0像素宽,或者可以扩展窗口,使JTextField跨越多个显示器在多显示器设置中)。

    但是,您可能会经常使用百分比来控制GUI的更大构建块的大小(例如面板)。

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


    真的吗?这个代码段是0分?这比那个有100多个赞的被接受答案好多了。那个回答基本上是在说“你永远不应该使用setPreferredSize!”这太可怕了。在我的工作中,有很多具体的尺寸要求,比如“触摸屏幕上的按钮必须是[X] x [Y],间距为[M] x [N]”,这是安全要求。btnBar.setPreferredSize(dimTouchBtn);是实现这一点的最佳方式。直截了当,无需自定义布局管理器。我主要使用GridBagLayout和一些BorderLayoutBoxLayout,方便时进行嵌套。这是一个强大的组合,易于使用。 - Loduwijk
    我在上面的评论中有些草率。这是我接受答案后看到的第一个回答。为什么SO不再按投票数排序了呢?我认为这原本是投票数的核心原因之一。尽管如此,我仍然坚持原来的评论; 这是更好的答案之一。除了它的第6点之外 - 那个不是很好。有很多(少数派仍然可能很多)调整大小的原因,在我遇到的大多数情况下,GridBagLayout在这方面支持得很好。 - Loduwijk
    我认为调整大小与不调整大小不应被视为宗教决定。有使用情况,当没有人想要调整大小,例如,如果您为一个预设固定分辨率的信息亭开发GUI。 如果您有不同的目标,例如工业HMI显示器和“按钮”的情况,那么是的,在触摸屏上,至少需要1cm x 1cm的按钮。 在这种情况下,屏幕的DPI设置了您如何调整大小。其他输入,如文本字段可能根本不会垂直调整大小,并且有时(例如邮政编码)水平调整大小也是无意义的。 - Gee Bee

    1
    我应该完全避免使用这些方法吗? 我不会说“避免”它们。我会说,如果你认为需要它们,那么你可能做错了什么。组件大小是在上下文中确定的。例如,文本组件的大小由您指定的行数和列数以及所选择的字体组成。如果您设置了图形,则按钮和标签的大小将是图形的大小,否则将是显示所设置的文本所需的空间。每个组件都有一个自然大小,布局管理器将使用这些大小来布置所有内容,而无需您指定大小。主要的例外是JScrollPane,它具有与其包含内容无关的大小。对于这些组件,我有时会调用setSize(),并通过调用JFrame.pack()让该大小确定初始窗口大小。通常,我会让窗口大小确定JScrollPane的大小。用户将决定窗口的大小。许多布局管理器忽略您设置的大小,因此它们通常没有太大作用。
    这些方法有其使用的原因。那么什么时候应该使用它们?在什么情况下?为了什么目的?
    我相信它们被添加是为了提供布局管理器的提示。它们可能是出于历史原因而编写的,因为布局管理器是新的,人们并不完全信任它们。我知道一些开发人员会避免使用布局管理器,并手动放置所有内容,只是因为他们不想费心学习新的范例。这是个糟糕的想法。
    使用这些方法的负面影响到底是什么?(我只能想到在不同屏幕分辨率的系统之间增加可移植性。)
    它们是无效的,并且会产生糟糕的布局,对象会被压缩或拉伸到非自然大小。布局也会很脆弱。窗口大小的更改有时会破坏布局并将物品放在错误的位置。
    我不认为任何LayoutManager都能完全满足所有所需的布局需求。我真的需要为每个小变化实现一个新的LayoutManager吗?你不应该“实现”新的LayoutManager,而应该实例化现有的LayoutManager。我经常在单个窗口中使用多个布局管理器。每个JPanel都将有自己的布局管理器。有些人对嵌套布局感到犹豫,因为它们很难维护。当我使用它们时,我为每个布局管理器提供自己的创建方法,以使其更容易看到每个布局管理器的作用。但我从来没有“实现”过一个布局管理器,我只是实例化它们。
    如果对问题4的答案是“是”,那么这是否会导致大量的LayoutManager类,这将变得难以维护?如果您正在为布局的轻微变化实现新的布局管理器类,则使用它们的方式是错误的。如果您只是实现新的布局管理器,那么您可能正在做错事情。我扩展LayoutManager类的唯一时间是为了向JScrollPane添加缩放滑块。
    在需要定义组件的子元素之间的比例时(例如,child1应使用10%的空间,child2 40%,child3 50%),是否可以在不实现自定义LayoutManager的情况下实现?
    JSplitPane有一种指定每个组件应获得的百分比的方法。默认情况下,分隔符是可移动的,但如果您希望关闭它,则可以关闭它。我不经常使用该功能。通常,我有一些占用固定大小的组件,其余的空间由滚动窗格占用。滚动窗格的大小将随着窗口大小调整而调整。如果您有两个并排的滚动窗格,可以将它们放入JSplitPane中,并指定在用户扩展和收缩窗口时赋予每个窗格的新空间的百分比。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接