【问题标题】:Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?我应该避免在 Java Swing 中使用 set(Preferred|Maximum|Minimum)Size 方法吗?
【发布时间】:2011-11-05 22:51:00
【问题描述】:

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

  1. setPreferredSize
  2. setMinimumSize
  3. setMaximumSize

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

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

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

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

【问题讨论】:

    标签: java swing layout-manager


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

      【解决方案2】:

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

      不,没有正式证据表明不允许调用或覆盖这些方法。事实上,Oracle 表示这些方法用于提供尺寸提示:http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#sizealignment

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

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

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

      当您需要为容器布局管理器提供自定义尺寸提示以便组件布局良好时

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

      • 许多布局管理器不注意组件请求的最大大小。但是,BoxLayoutSpringLayout 可以。此外,GroupLayout 提供了显式设置最小、首选或最大尺寸的能力,而无需触及组件。

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

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

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

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

      如果通过实施您的意思是使用,那么是的。没有一个LayoutManger 可以处理所有事情,每个LayoutManager 都有其优点和缺点,因此可以一起使用它们来生成最终布局。

      参考:

      【讨论】:

      • 提供自定义尺寸提示,这本身就是矛盾的:提供尺寸提示(以 px 为单位!)是组件的专有任务。它根据内部状态细节计算它们,除了它自己之外,任何其他方都无法知道(也无法跟踪)。从客户的角度来看,定制的方法可以是合适的 LayoutManager 和/或组件上的专用 api,允许根据“语义”尺寸相关属性配置尺寸要求,f.i.文本组件中的行数/列数
      • @kleopatra 我仍然很想知道为什么 Oracle 会告诉我们如何使用这些方法以及使用它们的正确方法。我们可能有自己的偏好,但当没有证据表明这一点时,我们不能说设计师不使用它。但这就是我提出赏金的原因,看看它是否会吸引其他人,这些人可以从可靠的来源提供信息,其中 oracle 声明根本不使用这些方法(因此,如果你这样做是不好的做法,例如 setMinimumSize 必须是调用诸如 JSplitPane 之类的东西,这可以在拆分窗格的 Oracle 教程中看到。
      • @David:我将setXxxSize 方法视为一个危险信号,我可能会遇到here,即使文档建议这样做。我几乎总是应该覆盖getXxxSize,在那里可以访问所需的几何图形;甚至简短的例子也比我想的要多回收。 +1 用于提及布局管理器之间的差异并引用教程。
      • D'oh,在我上面的评论中,我的意思是引用答案here
      • +1 "不,没有正式证据表明不允许调用或覆盖这些方法。"发现。标记为答案的帖子是纯废话。
      【解决方案3】:

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

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

      您可以在 here 中找到 Karsten 的文档,以及来自 eclipse here 的一些相当不错的文档。

      【讨论】:

        【解决方案4】:

        我看到它与接受的答案不同。

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

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

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

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

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

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

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

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

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

        我真的需要为布局上的每一个小变化都实现一个新的 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?这比接受了 100+ 的答案要好。这基本上是说“你不应该使用 setPreferredSize!”这是可怕的。在我的工作中,有很多特定的尺寸要求,例如“触摸屏上的按钮必须是 [X] 乘 [Y] 且间距为 [M]x[N]”的安全要求。 btnBar.setPreferredSize( dimTouchBtn ); 是最好的方法。直截了当,不需要自定义布局管理器。我主要使用GridBagLayout 和一些BorderLayoutBoxLayout,方便时嵌套。这是一个强大的组合并且易于使用。
        • 我在上面的评论中很仓促。这是我在接受答案后看到的第一个答案。为什么 SO 不再按票数排序?我认为这是最初计票的核心原因之一。尽管如此,我仍然坚持原来的评论;这是更好的答案之一。除了它的第 6 点——那一点没有那么好。调整大小的原因有很多(少数仍然可能很多),并且 GridBagLayout 在我遇到的大多数情况下都支持这一点。
        • 我认为调整大小与不调整大小不应被视为宗教决定。在某些用例中,没有人想要调整任何东西的大小,例如如果您为信息亭开发 GUI,具有预设的固定分辨率。如果您有不同的目标,例如工业 HMI 显示器和“按钮”的情况,那么是的,触摸屏上的按钮必须至少有 1 厘米乘 1 厘米。在这种情况下,屏幕的 DPI 设置您调整大小的方式。其他输入(例如文本字段)可能根本不会垂直调整大小,有时(例如邮政编码)水平调整大小也是没有意义的。
        【解决方案5】:
        1. 我应该完全避免使用这些方法吗?

          应用代码是的。

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

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

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

          一些(不完整,不幸的是,由于 SwingLabs 迁移到 java.net 导致链接中断)技术原因在 Rules (hehe) 或 @bendicott 在他/她对 @ 的评论中发现987654323@。在社交方面,将大量工作交给你不幸的人,他们必须维护代码并追踪损坏的布局。

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

          是的,有足够强大的 LayoutManager 可以很好地满足“所有布局需求”的近似值。三巨头是 JGoodies FormLayout、MigLayout、DesignGridLayout。所以不,实际上,除了简单的高度专业化的环境之外,您很少编写 LayoutManager。

        5. 如果对 4 的回答是“是”,这会不会导致 LayoutManager 类的泛滥而变得难以维护?

          (4的答案是“否”。)

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

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

        【讨论】:

        • 我不完全确定我至少在两种情况下同意这个建议。 1) 自定义渲染组件 2) 将JEditorPane 与本身不建议宽度的 HTML 一起使用。 OTOH我不确定我是否错过了什么。我会仔细查看线程上的回复,但如果您有任何 cmets 感兴趣,尤其是后一种情况。
        • @Andrew Thompson 1) 自定义组件:组件本身负责返回有用的布局提示,如果他们不这样做,则 impl 有问题 2) 甚至核心组件也有问题 ;-) 3) 我不介意空白(虽然这次不是故意的,谢谢 :-)
        • 我无法相信接受的答案是避免使用 setXXX() 方法的答案。有时您只需要它们向布局管理器提供提示。如果您正在布置面板,那么您绝对应该在必要时随意使用这些方法。说我认为如果您使用适当的布局管理器,您会发现自己并不经常需要这些方法,但有时您只是需要它们。尝试将 JComboBox 或 JSpinner 放在 X_AXIS BoxLayout 中而不使用它们,相信您会发现那里需要 setMaximumSize()。
        • @Michael 不,我绝对不需要它 - 答案总是使用像样的 LayoutManager 并在 manager 级别上进行任何微调(与组件级)
        • 你在整个 stackoverflow 上一直说“使用一个像样的 LayoutManager 并告诉它你想要什么尺寸”,但你从来没有给出任何“像样的”LayoutManager 的具体例子。并且没有一个标准管理器允许直接控制尺寸。
        【解决方案6】:

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

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

        例如,尝试更改应用程序的默认外观。即使仅使用您平台上可用的选项,您也可能会惊讶于结果呈现的糟糕程度。

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

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

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

        【讨论】:

        • +1 一个深思熟虑的答案 - 只是不同意 它们本质上不是邪恶的 仅仅因为它们是 :-) 通常,外部客户没有任何猜测的机会 - 仅仅是假设与局外人所能得到的一样接近 - 一半正确的布局提示:只有组件本身始终拥有所有信息以返回任何有用的信息。既然外人干预了,他们就有责任让这些提示保持最新,而这是他们无法做到的。
        • 嗯,你知道,我对这类事情有更多的“枪不杀人,人杀人”的看法。 :) 如果有人使用这些方法,他们需要了解您提出的关于不可预测的布局提示使用的好处(这就是为什么这些方法的情况合适的确实很少见)。
        • 我认为设置首选尺寸根本不是一个大危险信号。不设置它一个很大的危险信号。让我详细说明。布局管理器——无论它多么聪明——都不知道 gui 小部件的逻辑功能。例如,布局管理器无法区分用于输入邮政编码的 JTextField 和用于输入名称的 JTextField。同样,它无法区分 JTextField 旁边的工具按钮或表单底部的大 OK 按钮。因此,要么需要更好的小部件集,要么需要一些尺寸提示,不是吗?
        • @GeeBee 不,事实上,这是一个危险信号的典型例子。您应该做的是使用JTextField.setColumns 设置列数,从而相应地调整首选大小。如果您使用setPreferredSize,那么您正在硬编码一个大小,这将根据平台字体大小破坏您的布局。 Here are some text fields in a grid bag layout with setColumns called appropriately。对于您的按钮,使用适当的布局/网格权重来控制大小。
        • @GeeBee 现在,如果正确完成,请注意当我减小字体大小时文本字段宽度是如何减小的:i.snag.gy/ZULulh.jpg。即使即时更改字体大小现在也可以自动工作,而不是您必须重新计算所有文本字段宽度并为每个字段再次显式调用 setPreferredSize,您所要做的就是使布局无效,并且它们的大小将会调整。跨度>
        【解决方案7】:

        大多数人对这些方法知之甚少。你绝对不应该忽视这些方法。是否尊重这些方法取决于布局管理器。此页面有一个表格,显示了哪些布局管理器支持其中的哪些方法:

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

        我已经编写 Swing 代码 8 年多了,JDK 中包含的布局管理器始终满足我的需求。我从不需要 3rd 方布局管理器来实现我的布局。

        我会说,在您确定需要这些方法之前,您不应该尝试向布局管理器提供提示。在不提供任何尺寸提示的情况下进行布局(即让布局管理器完成其工作),然后您可以根据需要进行细微的更正。

        【讨论】:

        • 要么存在轻微的误解(你的部分)或误解(我的部分),请自行选择 :-) 你不断重复(这里,在你的博客中,在你与 BoxLayout 相关的答案中) 设置 XXSize 很重要 - 实际上 LayoutManager 对 XXSize 感兴趣(或不感兴趣),即 尺寸提示 独立于它是如何产生的(组件的内部计算或由应用程序代码手动强制)
        • 我不确定我是否理解您在这里的意思。我在上面提到 XXSize() 方法只是提示。如果需要,我真的认为给布局管理器一点提示没有错。在我的 Swing 代码中,您会发现偶尔的 setXXSize() 方法。不是很多,但我偶尔会发现它们是需要的。 JComboBox 和 JSpinner 经常需要提示。尤其是实现后填充的 JComboBox。您似乎反对使用这些方法,我不知道为什么。 (我猜可能是我错过了这艘船)。
        • 不是 methods 是提示,properties 是:组件应该为所有提示报告一些合理的东西,有些(如 fi JComboBox)不't - 在返回 maxInteger 左右。这是一个错误,应该由组合修复。至于你的习惯:当维护同事必须清理它时,一定要远离它:) 硬编码的提示往往会在最轻微的变化时破坏布局,并且很难检测到布局损坏的原因。跨度>
        【解决方案8】:

        一些启发式方法:

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

        • 当您可以依赖组件的谨慎覆盖的getPreferred|Maximum|Minimum]Size 时,请勿使用set[Preferred|Maximum|Minimum]Size(),如here 及以下所示。

        • 请使用set[Preferred|Maximum|Minimum]Size() 导出后validate() 几何,如下所示和here

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

        • comments 中所述,当您发现必须遍历许多组件才能获得派生尺寸时,请考虑替代或自定义布局。

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

        【讨论】:

        • 不同意(您可能已经猜到了:-)“外部因素”的推理:XXSize 属性旨在表达仅在内部的需求。从外部调整这些是误用,也就是黑客攻击。如果您想要一个(内部或 J-)框架,其大小相对于它的首选...调整框架,而不是内容
        • @kleopatra:有点坚持:如果 setXXSize 方法不应该从外部使用,为什么不被声明为私有或受保护的?这不是缺乏设计吗? public 修饰符不是隐式告诉用户可以使用这些方法吗?
        • 我必须同意@kleopatra:setPreferredSize() 总是用任意选择替换组件的计算。
        • @trashgod +100 给你我认为覆盖这些方法没有问题,甚至调用它们(但这当然意味着你有一个自定义组件,因此覆盖会更好)
        • @DavidKroukamp:谢谢。我尊重克娄巴特拉的更丰富经验,但我看到了批判性地研究相反观点的价值。
        【解决方案9】:

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

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

        【讨论】:

        • 感谢您的回答。我不得不假设您的意思也是:“根本不使用 setPreferredSize”,对吗?
        • GridBagLayout 使用约束,您可以在其中为给定组件指定 X 和 Y 中的“权重”,因此 LayoutManager 可以决定如何处理调整大小时的额外空间。 但是您仍然需要/可以使用 setPreferredSize 来确定每个组件的首选大小,请注意,“首选”并不意味着它会一直受到尊重。对于特殊情况,您可能还需要 setMinimumSize 和 setMaximumSize 。他们不是邪恶的,不要相信。 docs.oracle.com/javase/tutorial/uiswing/layout/gridbag.html
        猜你喜欢
        • 2018-06-16
        • 2010-09-07
        • 2011-03-26
        • 1970-01-01
        • 2012-10-14
        • 2010-09-23
        • 2011-12-31
        • 2021-06-03
        相关资源
        最近更新 更多