创建自定义布局管理器
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/custom.html
在开始创建自定义布局管理器之前,请确保没有现有的布局管理器符合您的要求。特别是像GridBagLayout
、SpringLayout
和BoxLayout
这样的布局管理器在许多情况下都足够灵活。您还可以从其他来源找到布局管理器,比如从互联网上。最后,您可以通过将组件分组到诸如面板之类的容器中来简化布局。
注意: 本课程涵盖了手动编写布局代码,这可能具有挑战性。如果您不想学习布局管理的所有细节,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码而不想使用GroupLayout
,那么推荐使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 来创建您的 GUI,请参阅在 JavaFX 中使用布局。
要创建自定义布局管理器,您必须创建一个实现LayoutManager
接口的类。您可以直接实现它,或者实现其子接口LayoutManager2
。
每个布局管理器必须至少实现LayoutManager
接口所需的以下五个方法:
void addLayoutComponent(String, Component)
被Container
类的add
方法调用。通常不将字符串与其组件关联的布局管理器在此方法中不执行任何操作。
void removeLayoutComponent(Component)
被Container
方法remove
和removeAll
调用。布局管理器重写此方法以清除与Component
关联的内部状态。
Dimension preferredLayoutSize(Container)
被Container
类的getPreferredSize
方法调用,该方法本身在各种情况下被调用。此方法应计算并返回容器的理想大小,假设其中的组件将达到或超过其首选大小。此方法必须考虑容器的内部边框,这些边框由getInsets
方法返回。
Dimension minimumLayoutSize(Container)
被Container
的getMinimumSize
方法调用,该方法本身在各种情况下都会被调用。该方法应计算并返回容器的最小尺寸,假设其中的组件将在其最小尺寸或以上。该方法必须考虑容器的内部边框,这些边框由getInsets
方法返回。
void layoutContainer(Container)
用于定位和调整容器中每个组件的大小。布局管理器的layoutContainer
方法实际上不会绘制组件。它只是调用每个组件的setSize
、setLocation
和setBounds
方法中的一个或多个来设置组件的大小和位置。
该方法必须考虑容器的内部边框,这些边框由getInsets
方法返回。如果适用,它还应考虑容器的方向(由getComponentOrientation
方法返回)。您不能假设在调用layoutContainer
之前将调用preferredLayoutSize
或minimumLayoutSize
方法。
除了实现前述的五个方法外,布局管理器通常会实现至少一个公共构造函数和toString
方法。
如果您希望支持组件约束、最大尺寸或对齐方式,则您的布局管理器应实现LayoutManager2
接口。事实上,出于这些原因以及许多其他原因,几乎所有现代布局管理器都需要实现LayoutManager2
。该接口在LayoutManager
所需的五个方法基础上添加了五个方法:
addLayoutComponent(Component, Object)
getLayoutAlignmentX(Container)
getLayoutAlignmentY(Container)
invalidateLayout(Container)
maximumLayoutSize(Container)
这些方法中,最重要的是addLayoutComponent(Component, Object)
和invalidateLayout(Container)
。addLayoutComponent
方法用于使用指定的约束对象向布局中添加组件。invalidateLayout
方法用于使布局失效,因此如果布局管理器缓存了信息,则应将其丢弃。有关LayoutManager2
的更多信息,请参阅LayoutManager2
API 文档。
最后,每当您创建自定义布局管理器时,都应注意保持对不再是Container
子级的Component
实例的引用。换句话说,布局管理器应覆盖removeLayoutComponent
以清除与Component
相关的任何缓存状态。
自定义布局的示例
示例CustomLayoutDemo
使用了一个名为DiagonalLayout
的自定义布局管理器。您可以在DiagonalLayout.java
中找到布局管理器的源代码。DialogLayout
以对角线方式从左到右布置组件,每行一个组件。这里是使用DialogLayout
布置五个按钮的 CustomLayoutDemo 的图片。
点击启动按钮以使用Java™ Web Start运行CustomLayoutDemo
(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
不使用布局管理器(绝对定位)
尽管可以不使用布局管理器,但尽可能使用布局管理器。布局管理器使得更容易调整外观和感觉依赖的组件外观,不同的字体大小,容器的大小变化以及不同的语言环境。布局管理器也可以轻松地被其他容器以及其他程序重复使用。
**注意:**本课程涵盖了手动编写布局代码,这可能具有挑战性。如果您不想学习布局管理的所有细节,您可能更喜欢使用GroupLayout
布局管理器结合构建工具来布局您的 GUI。其中一个构建工具是 NetBeans IDE。否则,如果您想手动编码而不想使用GroupLayout
,那么推荐使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果您有兴趣使用 JavaFX 创建 GUI,请参阅在 JavaFX 中使用布局。
如果一个容器包含的组件的大小不受容器的大小、字体、外观和语言更改的影响,那么绝对定位可能是合理的。包含内部框架的桌面窗格属于这一类别。内部框架的大小和位置不直接取决于桌面窗格的大小。程序员确定内部框架在桌面窗格内的初始大小和位置,然后用户可以移动或调整框架的大小。在这种情况下,布局管理器是不必要的。
另一种适合使用绝对定位的情况是自定义容器,该容器执行特定于容器的大小和位置计算,并且可能需要了解容器的专门状态。这是分割窗格的情况。
创建一个没有布局管理器的容器涉及以下步骤。
- 将容器的布局管理器设置为 null,调用
setLayout(null)
。 - 对容器的每个子元素调用
Component
类的setbounds
方法。 - 调用
Component
类的repaint
方法。
然而,使用绝对定位创建容器可能会在包含容器的窗口调整大小时出现问题。
这是一个内容窗格使用绝对定位的框架的快照。
点击“启动”按钮以使用Java™ Web Start运行 AbsoluteLayoutDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。
其代码位于AbsoluteLayoutDemo.java
中。以下代码片段显示了如何在内容窗格中创建和布局组件。
pane.setLayout(null); JButton b1 = new JButton("one"); JButton b2 = new JButton("two"); JButton b3 = new JButton("three"); pane.add(b1); pane.add(b2); pane.add(b3); Insets insets = pane.getInsets(); Dimension size = b1.getPreferredSize(); b1.setBounds(25 + insets.left, 5 + insets.top, size.width, size.height); size = b2.getPreferredSize(); b2.setBounds(55 + insets.left, 40 + insets.top, size.width, size.height); size = b3.getPreferredSize(); b3.setBounds(150 + insets.left, 15 + insets.top, size.width + 50, size.height + 20); ...*//In the main method:* Insets insets = frame.getInsets(); frame.setSize(300 + insets.left + insets.right, 125 + insets.top + insets.bottom);
解决常见布局问题
原文:
docs.oracle.com/javase/tutorial/uiswing/layout/problems.html
注意: 本课程涵盖了手动编写布局代码,这可能具有挑战性。如果你不想学习布局管理的所有细节,可以选择使用GroupLayout
布局管理器结合构建工具来布局你的 GUI。其中一种构建工具是 NetBeans IDE。否则,如果你想手动编码而不想使用GroupLayout
,那么推荐使用GridBagLayout
作为下一个最灵活和强大的布局管理器。
如果你有兴趣使用 JavaFX 来创建 GUI,请查看使用 JavaFX 中的布局。
问题: 如何指定组件的确切尺寸?
- 一些较现代的布局管理器提供了覆盖组件设置的尺寸的方法。检查你正在使用的布局管理器是否允许你指定组件大小。
- 确保你真的需要设置组件的确切尺寸。每个 Swing 组件的首选尺寸都不同,取决于其使用的字体和外观。因此,通常没有必要指定 Swing 组件的确切尺寸。
- 如果组件不受布局管理器控制,可以通过调用
setSize
或setBounds
方法来设置其大小。否则,你需要提供尺寸提示,然后确保你使用的布局管理器尊重尺寸提示。 - 如果你扩展了 Swing 组件类,可以通过重写组件的
getMinimumSize
、getPreferredSize
和getMaximumSize
方法来给出尺寸提示。这种方法的好处在于,每个get*Xxxx*Size
方法可以通过调用super.get*Xxxx*Size()
来获取组件的默认尺寸提示。然后在返回之前可以调整尺寸,如果有必要的话。这对于文本组件特别方便,其中你可能希望固定宽度,但高度由内容确定。然而,有时会在GridBagLayout
和文本字段中遇到问题,如果容器的尺寸小于首选尺寸,则使用最小尺寸,这可能会导致文本字段大幅缩小。 - 另一种给出尺寸提示的方法是调用组件的
setMinimumSize
、setPreferredSize
和setMaximumSize
方法。 - 如果为已经可见的组件指定了新的尺寸提示,则需要在其上调用
revalidate
方法,以确保其包含层次结构再次布局。然后调用repaint
方法。
注意: 无论您如何指定组件的大小,请确保组件的容器使用一个能够尊重组件请求大小的布局管理器。FlowLayout
和 GridBagLayout
布局管理器使用组件的首选大小(后者取决于您设置的约束条件),但 BorderLayout
和 GridLayout
通常不会。BoxLayout
布局管理器通常使用组件的首选大小(尽管组件可以更大),并且是少数几个尊重组件最大大小的布局管理器之一。
问题: 我添加了组件到容器后,组件没有显示出来。
- 在添加组件后,您需要调用
revalidate
和repaint
才能使组件显示在容器中。
问题: 我的自定义组件尺寸太小了。
- 组件是否实现了
getPreferredSize
和getMinimumSize
方法?如果是,它们是否返回了正确的值? - 您是否使用了一个可以利用所有可用空间的布局管理器?请参阅选择布局管理器的提示以获取一些关于选择布局管理器并指定其使用特定组件的最大可用空间的提示。
如果您在此列表中找不到您的问题,请参阅解决常见组件问题。
问题和练习:在容器内布置组件
原文:
docs.oracle.com/javase/tutorial/uiswing/QandE/questions-ch4.html
问题
在以下每个问题中,选择最适合描述布局的布局管理器。假设由布局管理器控制的容器是JPanel
。
1. 该容器有一个组件应尽可能占据空间
a. BorderLayout
b. GridLayout
c. GridBagLayout
d. a 和 b
e. b 和 c
2. 该容器有一行组件,应该以相同大小显示,填充容器的整个区域。
a. FlowLayout
b. GridLayout
c. BoxLayout
d. a 和 b
3. 该容器以列形式显示多个组件,额外的空间位于前两个组件之间。
a. FlowLayout
b. BoxLayout
c. GridLayout
d. BorderLayout
4. 该容器可以在不同时间显示三个完全不同的组件,可能取决于用户输入或程序状态。即使组件的大小不同,从一个组件切换到下一个也不应更改为组件分配的空间量。
a. SpringLayout
b. BoxLayout
c. CardLayout
d. GridBagLayout
练习
1. 实现问题 1 中描述和显示的布局。
2. 实现问题 2 中描述和显示的布局。
3. 实现问题 3 中描述和显示的布局。
4. 实现问题 4 中描述和显示的布局。
5. 通过添加一行代码,使您为练习 2 编写的程序显示组件从右到左,而不是从左到右。
检查您的答案。
课程:修改外观和感觉
原文:
docs.oracle.com/javase/tutorial/uiswing/lookandfeel/index.html
示例索引
这节课告诉你如何改变你的 Swing 应用程序的外观和感觉。应用程序的“外观”指的是它的外观。而“感觉”指的是小部件的行为。你可以选择使用默认的 Swing 外观和感觉(比如 Metal 外观和感觉的 Ocean 主题),或者使用本地平台的外观和感觉(比如 Windows、GTK+),或者你可以自定义自己的外观和感觉。
如何设置外观和感觉
设置外观和感觉为可用外观和感觉之一的基本信息。提供了通过编程和命令行设置外观和感觉的信息。
Synth 外观和感觉
提供了如何使用 Synth 包自定义外观和感觉的信息。
Nimbus 外观和感觉
提供了如何使用 JDK 7 发布的 Nimbus 包自定义外观和感觉的信息。
如果你有兴趣使用 JavaFX 创建你的 GUI,请参阅使用 CSS 为 JavaFX 应用程序设置外观和感觉和使用 JavaFX 图表。
如何设置外观和感觉
原文:
docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
Swing 的架构设计使您可以更改应用程序 GUI 的“外观和感觉”(L&F)(请参阅A Swing Architecture Overview)。“外观”指的是 GUI 小部件的外观(更正式地说,JComponents
),而“感觉”指的是小部件的行为方式。
Swing 的架构通过将每个组件分为两个不同的类来实现多个 L&Fs 的功能:一个JComponent
子类和一个对应的ComponentUI
子类。例如,每个JList
实例都有一个ListUI
的具体实现(ListUI
扩展自ComponentUI
)。在 Swing 的文档中,ComponentUI
子类被称为各种名称——“UI”,“组件 UI”,“UI 代理”和“外观和感觉代理”都用来标识ComponentUI
子类。
大多数开发人员几乎不需要直接与 UI 代理交互。在大多数情况下,UI 代理由JComponent
子类内部用于关键功能,JComponent
子类提供了所有对 UI 代理的访问的覆盖方法。例如,JComponent
子类中的所有绘图都委托给 UI 代理。通过委托绘图,外观可以根据 L&F 的不同而变化。
每个 L&F 都有责任为 Swing 定义的每个ComponentUI
子类提供具体实现。例如,Java 外观和感觉创建一个MetalTabbedPaneUI
实例来为JTabbedPane
提供 L&F。UI 代理的实际创建由 Swing 为您处理——在大多数情况下,您几乎不需要直接与 UI 代理交互。
本节的其余部分讨论以下主题:
- 可用的外观和感觉
- 以编程方式设置外观和感觉
- 指定外观和感觉:命令行
- 指定外观和感觉:swing.properties
- UI 管理器如何选择外观和感觉
- 启动后更改外观和感觉
- 一个示例
- 主题
- SwingSet2 演示程序
可用的外观和感觉
Sun 的 JRE 提供以下 L&Fs:
CrossPlatformLookAndFeel
—这是在所有平台上看起来相同的“Java L&F”(也称为“Metal”)。它是 Java API 的一部分(javax.swing.plaf.metal
),如果您在代码中不做任何设置,则将使用默认值。SystemLookAndFeel
—在这里,应用程序使用与其运行的系统相对应的 L&F。系统 L&F 在运行时确定,应用程序会询问系统返回适当 L&F 的名称。- Synth——用 XML 文件创建自己的外观和感觉的基础。
- 多路复用—一种让 UI 方法同时委托给多个不同外观实现的方式。
对于 Linux 和 Solaris,如果安装了 GTK+ 2.2 或更高版本,则系统 L&Fs 是“GTK+”,否则是“Motif”。对于 Windows,系统 L&F 是“Windows”,模仿正在运行的特定 Windows OS 的 L&F—经典 Windows、XP 或 Vista。GTK+、Motif 和 Windows L&Fs 由 Sun 提供,并随 Java SDK 和 JRE 一起提供,尽管它们不是 Java API 的一部分。
苹果提供了自己的 JVM,其中包含他们专有的 L&F。
总之,当您使用 SystemLookAndFeel
时,您将看到以下内容:
平台 | 外观和感觉 |
Solaris、安装了 GTK+ 2.2 或更高版本的 Linux | GTK+ |
其他 Solaris、Linux | Motif |
IBM UNIX | IBM* |
HP UX | HP* |
经典 Windows | Windows |
Windows XP | Windows XP |
Windows Vista | Windows Vista |
Macintosh | Macintosh* |
- 由系统供应商提供。
在 API 中看不到系统 L&F。它需要的 GTK+、Motif 和 Windows 包已随 Java SDK 一起提供:
com.sun.java.swing.plaf.gtk.GTKLookAndFeel com.sun.java.swing.plaf.motif.MotifLookAndFeel com.sun.java.swing.plaf.windows.WindowsLookAndFeel
请注意路径包括 java
,而不是 javax
。
注意: GTK+ L&F 只能在安装了 GTK+ 2.2 或更高版本的 UNIX 或 Linux 系统上运行,而 Windows L&F 只能在 Windows 系统上运行。与 Java(Metal)L&F 一样,Motif L&F 可在任何平台上运行。
所有 Sun 的 L&Fs 都有很多共同点。这种共同点在 API 中的 Basic
外观和感觉中定义(javax.swing.plaf.basic
)。Motif 和 Windows L&Fs 分别通过扩展 javax.swing.plaf.basic
中的 UI 代理类构建(可以通过相同的方式构建自定义 L&F)。“Basic” L&F 不会在不被扩展的情况下使用。
在 API 中,您将看到四个 L&F 包:
javax.swing.plaf.basic
—在创建自定义 L&F 时要扩展的基本 UI 代理javax.swing.plaf.metal
—Java L&F,也被称为跨平台 L&F(“Metal” 是这个 L&F 的 Sun 项目名称)。这个 L&F 的当前默认“主题”(下面讨论)是“Ocean”,因此通常被称为 Ocean L&F。javax.swing.plaf.multi
—一个多路复用外观,允许 UI 方法同时委托给多个外观实现。它可以用于增强特定外观的行为,例如在 Windows 外观之上提供音频提示的外观。这是创建残障人士可访问的外观的一种方式。javax.swing.plaf.synth
—使用 XML 文件轻松配置的 L&F(在本课程的下一部分讨论)
您不限于使用 Java 平台提供的 L&Fs。您可以使用程序类路径中的任何 L&F。外部 L&Fs 通常以一个或多个 JAR 文件的形式提供,您可以在运行时将其添加到程序的类路径中。例如:
java -classpath .;C:\java\lafdir\customlaf.jar YourSwingApplication
一旦外部 L&F 在程序的类路径中,程序就可以像使用 Java 平台提供的任何 L&Fs 一样使用它。
以编程方式设置外观和感觉
注意: 如果要设置外观和感觉,应该在应用程序中的第一步就这样做。否则,你可能会在请求的外观和感觉之外初始化 Java 外观和感觉。当静态字段引用 Swing 类时,可能会无意中发生这种情况,导致加载外观和感觉。如果尚未指定外观和感觉,则加载 JRE 的默认外观和感觉。对于 Sun 的 JRE,默认是 Java 外观和感觉,对于 Apple 的 JRE 是 Apple 外观和感觉,依此类推。
Swing 组件使用的外观和感觉是通过javax.swing
包中的UIManager
类指定的。每当创建一个 Swing 组件时,该组件都会向 UI 管理器请求实现组件外观和感觉的 UI 委托。例如,每个JLabel
构造函数都会查询 UI 管理器以获取适用于标签的 UI 委托对象。然后使用该 UI 委托对象来实现所有的绘制和事件处理。
要以编程方式指定外观和感觉,可以使用UIManager.setLookAndFeel()
方法,并将适当的LookAndFeel
子类的完全限定名称作为参数。例如,以下代码中的粗体代码使程序使用跨平台的 Java 外观和感觉:
public static void main(String[] args) { try { // Set cross-platform Java L&F (also called "Metal") UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName()); } catch (UnsupportedLookAndFeelException e) { // handle exception } catch (ClassNotFoundException e) { // handle exception } catch (InstantiationException e) { // handle exception } catch (IllegalAccessException e) { // handle exception } new SwingApplication(); //Create and show the GUI. }
或者,这段代码使程序使用系统外观和感觉:
public static void main(String[] args) { try { // Set System L&F UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName()); } catch (UnsupportedLookAndFeelException e) { // handle exception } catch (ClassNotFoundException e) { // handle exception } catch (InstantiationException e) { // handle exception } catch (IllegalAccessException e) { // handle exception } new SwingApplication(); //Create and show the GUI. }
你也可以将外观和感觉的实际类名作为UIManager.setLookAndFeel()
的参数。例如,
// Set cross-platform Java L&F (also called "Metal") UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
或
// Set Motif L&F on any platform UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
你不限于前面的参数。你可以为程序类路径中的任何外观和感觉指定名称。
指定外观和感觉:命令行
你可以通过使用-D
标志设置swing.defaultlaf
属性在命令行中指定外观和感觉。例如:
java -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel MyApp java -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel MyApp
指定外观和感觉:swing.properties 文件
另一种指定当前外观和感觉的方法是使用swing.properties
文件来设置swing.defaultlaf
属性。这个文件可能需要你自己创建,在 Sun 的 Java 发布版本的lib
目录中(其他 Java 供应商可能使用不同的位置)。例如,如果你在*javaHomeDirectory*\bin
中使用 Java 解释器,那么swing.properties
文件(如果存在)就在*javaHomeDirectory*\lib
中。以下是swing.properties
文件的示例内容:
# Swing properties swing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel
UI 管理器如何选择外观和感觉
当 UI 管理器需要设置外观和感觉时,以下是外观和感觉确定步骤:
- 如果程序在需要外观和感觉之前设置了外观和感觉,UI 管理器会尝试创建指定外观和感觉类的实例。如果成功,所有组件都将使用该外观和感觉。
- 如果程序没有成功指定外观和感觉,那么 UI 管理器将使用
swing.defaultlaf
属性指定的外观和感觉。如果swing.properties
文件和命令行中都指定了该属性,则以命令行定义为准。 - 如果这些步骤都没有导致有效的外观和感觉,Sun 的 JRE 将使用 Java 外观和感觉。其他供应商,如苹果,将使用其默认外观和感觉。
启动后更改外观和感觉
即使程序的 GUI 可见,您也可以使用setLookAndFeel
更改外观和感觉。为了使现有组件反映新的外观和感觉,每个顶级容器调用一次SwingUtilities
的updateComponentTreeUI
方法。然后,您可能希望调整每个顶级容器的大小以反映其包含组件的新大小。例如:
UIManager.setLookAndFeel(lnfName); SwingUtilities.updateComponentTreeUI(frame); frame.pack();
一个示例
在以下示例中,LookAndFeelDemo.java
,您可以尝试不同的外观和感觉。该程序创建了一个简单的 GUI,带有一个按钮和一个标签。每次单击按钮时,标签会递增。
您可以通过更改第 18 行的LOOKANDFEEL
常量来更改外观和感觉。前几行的注释告诉您哪些值是可接受的:
// Specify the look and feel to use by defining the LOOKANDFEEL constant // Valid values are: null (use the default), "Metal", "System", "Motif", // and "GTK" final static String LOOKANDFEEL = "Motif";
这里将常量设置为"Motif",这是一个可以在任何平台上运行的外观和感觉(默认为"Metal")。"GTK+"不会在 Windows 上运行,而"Windows"只会在 Windows 上运行。如果选择无法运行的外观和感觉,您将获得 Java 或 Metal 外观和感觉。
在实际设置外观和感觉的代码部分,您将看到几种不同的设置方式,如上所述:
if (LOOKANDFEEL.equals("Metal")) { lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName(); // an alternative way to set the Metal L&F is to replace the // previous line with: // lookAndFeel = "javax.swing.plaf.metal.MetalLookAndFeel";
您可以通过注释/取消注释两个替代方案来验证这两个参数是否有效。
Java 中文官方教程 2022 版(二十三)(2)https://developer.aliyun.com/article/1486784