# 如何设置外观和感觉 > 原文: [https://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html](https://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html) Swing 的体系结构旨在让您可以更改应用程序 GUI 的“外观”(L& F)(参见 [Swing 架构概述](http://www.oracle.com/technetwork/java/architecture-142923.html))。 “外观”指的是 GUI 小部件的外观(更正式地说,`JComponents`),“感觉”指的是小部件的行为方式。 Swing 的体系结构通过将每个组件分成两个不同的类来实现多个 L& Fs:`JComponent`子类和相应的`ComponentUI`子类。例如,每个`JList`实例都具有`ListUI`的具体实现(`ListUI`扩展`ComponentUI`)。 `ComponentUI`子类在 Swing 的文档中以各种名称引用 - “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 委托交互。 本节的其余部分讨论以下主题: * [外观和感觉](#available) * [以编程方式设置外观](#programmatic) * [指定外观:命令行](#commandLine) * [指定外观:swing.properties](#properties) * [UI 管理器如何选择外观](#steps) * [启动后改变外观](#dynamic) * [一个例子](#example) * [主题](#themes) * [SwingSet2 演示程序](#swingset2) Sun 的 JRE 提供以下 L& Fs: 1. `CrossPlatformLookAndFeel` - 这是所有平台上看起来相同的“Java L& F”(也称为“金属”)。它是 Java API(`javax.swing.plaf.metal`)的一部分,如果您在代码中不执行任何操作来设置不同的 L& F,则默认使用它。 2. `SystemLookAndFeel` - 在那里,应用程序使用 L& F,它是运行它的系统的原生。系统 L& F 在运行时确定,其中应用程序要求系统返回适当的 L& F 的名称。 3. Synth-使用 XML 文件创建自己的外观的基础。 4. 多路复用 - 一种让 UI 方法同时委托给许多不同外观实现的方法。 对于 Linux 和 Solaris,如果安装了 GTK + 2.2 或更高版本,则系统 L& Fs 为“GTK +”,否则为“Motif”。对于 Windows,系统 L& F 是“Windows”,它模仿运行经典 Windows,XP 或 Vista 的特定 Windows 操作系统的 L& F. GTK +,Motif 和 Windows L& Fs 由 Sun 提供,随 Java SDK 和 JRE 一起提供,尽管它们不是 Java API 的一部分。 Apple 提供自己的 JVM,其中包括其专有的 L& F. 总之,当您使用`SystemLookAndFeel`时,您会看到以下内容: | 平台 | 外观和感觉 | | --- | --- | | Solaris,Linux,GTK + 2.2 或更高版本 | GTK + | | 其他 Solaris,Linux | 主题 | | IBM UNIX | IBM * | | HP UX | 生命值* | | 经典 Windows | 视窗 | | Windows XP | Windows XP | | Windows Vista | Windows Vista | | 苹果 | 苹果* | *由系统供应商提供。 您没有在 API 中看到系统 L& F.它需要的 GTK +,Motif 和 Windows 软件包随 Java SDK 一起提供: ```java com.sun.java.swing.plaf.gtk.GTKLookAndFeel com.sun.java.swing.plaf.motif.MotifLookAndFeel com.sun.java.swing.plaf.windows.WindowsLookAndFeel ``` 请注意,路径包括`java`,而不是`javax`。 * * * **Note:** The GTK+ L&F will only run on UNIX or Linux systems with GTK+ 2.2 or later installed, while the Windows L&F runs only on Windows systems. Like the Java (Metal) L&F, the Motif L&F will run on any platform. * * * 所有 Sun 的 L& Fs 都有很多共性。这种通用性在 API 中的`Basic`外观中定义(`javax.swing.plaf.basic`)。 Motif 和 Windows L& Fs 都是通过扩展`javax.swing.plaf.basic`中的 UI 委托类来构建的(可以通过做同样的事情来构建自定义 L& F)。没有扩展就不使用“基本”L& F. 在 API 中,您将看到四个 L& F 包: * `javax.swing.plaf.basic` -basic UI 代表在创建自定义 L& F 时进行扩展 * `javax.swing.plaf.metal` -Java L& F,也称为 CrossPlatform L& F(“Metal”是该 L& F 的 Sun 项目名称)此 L& F 的当前默认“主题”(下面讨论)是“海洋,所以这通常被称为海洋 L& F. * `javax.swing.plaf.multi` - 一种多路复用的外观,允许 UI 方法同时委托给许多外观实现。它可以用于增强特定外观的感觉,例如使用 L& F,它在 Windows 外观和感觉之上提供音频提示。这是一种创造残疾人无障碍外观的方式。 * `javax.swing.plaf.synth` - 使用 XML 文件轻松配置 L& F(在本课的下一节中讨论) ```java java -classpath .;C:\java\lafdir\customlaf.jar YourSwingApplication ``` 一旦外部 L& F 进入您的程序类路径,您的程序就可以像 Java 平台附带的任何 L& F 一样使用它。 * * * **Note:** If you are going to set the L&F, you should do it as the very first step in your application. Otherwise you run the risk of initializing the Java L&F regardless of what L&F you've requested. This can happen inadvertently when a static field references a Swing class, which causes the L&F to be loaded. If no L&F has yet been specified, the default L&F for the JRE is loaded. For Sun's JRE the default is the Java L&F, for Apple's JRE the Apple L&F, and so forth. * * * Swing 组件使用的 L& F 通过`javax.swing`包中的`UIManager`类指定。每当创建 Swing 组件时,组件都会向 UI 管理器询问实现组件 L& F 的 UI 委托。例如,每个`JLabel`构造器向 UI 管理器查询适用于标签的 UI 委托对象。然后,它使用该 UI 委托对象来实现其所有绘图和事件处理。 要以编程方式指定 L& F,请使用`UIManager.setLookAndFeel()`方法,并将`LookAndFeel`的相应子类的完全限定名称作为其参数。例如,以下代码段中的粗体代码使程序使用跨平台 Java L& F: ```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. } ``` 或者,此代码使程序使用系统 L& F: ```java 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()`的参数。例如, ```java // Set cross-platform Java L&F (also called "Metal") UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); ``` 要么 ```java // Set Motif L&F on any platform UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); ``` 您不限于前面的参数。您可以为程序类路径中的任何 L& F 指定名称。 您可以使用`-D`标志在命令行指定 L& F 来设置`swing.defaultlaf`属性。例如: ```java java -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel MyApp java -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel MyApp ``` 指定当前 L& F 的另一种方法是使用`swing.properties`文件来设置`swing.defaultlaf`属性。您可能需要创建的此文件位于 Sun Java 版本的`lib`目录中(其他 Java 供应商可能使用不同的位置)。例如,如果您在`_javaHomeDirectory_ \ bin`中使用 Java 解释器,则`swing.properties`文件(如果存在)位于`_javaHomeDirectory_ 中] \ lib` 。以下是 [`swing.properties`](swing.properties) 文件内容的示例: ```java # Swing properties swing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel ``` 以下是 UI 管理器需要设置 L& F 时出现的外观确定步骤: 1. 如果程序在需要外观之前设置 L& F,则 UI 管理器尝试创建指定的外观类的实例。如果成功,所有组件都使用 L& F. 2. 如果程序未成功指定 L& F,则 UI 管理器使用由`swing.defaultlaf`属性指定的 L& F.如果在命令行的`swing.properties`文件*和*中都指定了该属性,则命令行定义优先。 3. 如果这些步骤都没有产生有效的 L& F,则 Sun 的 JRE 使用 Java L& F.其他供应商,如 Apple,将使用其默认的 L& F. 即使在程序的 GUI 可见之后,您也可以使用`setLookAndFeel`更改 L& F.为了使现有组件反映新的 L& F,每个顶级容器调用一次`SwingUtilities` `updateComponentTreeUI`方法。然后,您可能希望调整每个顶级容器的大小以反映其包含的组件的新大小。例如: ```java UIManager.setLookAndFeel(lnfName); SwingUtilities.updateComponentTreeUI(frame); frame.pack(); ``` 在以下示例中,`LookAndFeelDemo.java`,您可以尝试不同的外观和感觉。该程序使用按钮和标签创建一个简单的 GUI。每次单击该按钮,标签都会递增。 您可以通过更改第 18 行的`LOOKANDFEEL`常量来更改 L​​& F.前面几行的注释告诉您可接受的值: ```java // 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”,这是一个可在任何平台上运行的 L& F(默认情况下为“Metal”)。 “GTK +”不能在 Windows 上运行,“Windows”只能在 Windows 上运行。如果您选择不会运行的 L& F,您将获得 Java 或 Metal,L& F. 在实际设置 L& F 的代码部分中,您将看到几种不同的设置方式,如上所述: ```java 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"; ``` 您可以通过对两个备选方案进行注释/取消注释来验证这两个参数是否有效。 这是 [`LookAndFeelDemo`](../examples/lookandfeel/LookAndFeelDemoProject/src/lookandfeel/LookAndFeelDemo.java) 源文件的列表: ```java package lookandfeel; import javax.swing.*; import java.awt.*; import java.awt.event.*; import javax.swing.plaf.metal.*; public class LookAndFeelDemo implements ActionListener { private static String labelPrefix = "Number of button clicks: "; private int numClicks = 0; final JLabel label = new JLabel(labelPrefix + "0 "); // 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 = "Metal"; // If you choose the Metal L&F, you can also choose a theme. // Specify the theme to use by defining the THEME constant // Valid values are: "DefaultMetal", "Ocean", and "Test" final static String THEME = "Test"; public Component createComponents() { JButton button = new JButton("I'm a Swing button!"); button.setMnemonic(KeyEvent.VK_I); button.addActionListener(this); label.setLabelFor(button); JPanel pane = new JPanel(new GridLayout(0, 1)); pane.add(button); pane.add(label); pane.setBorder(BorderFactory.createEmptyBorder( 30, //top 30, //left 10, //bottom 30) //right ); return pane; } public void actionPerformed(ActionEvent e) { numClicks++; label.setText(labelPrefix + numClicks); } private static void initLookAndFeel() { String lookAndFeel = null; if (LOOKANDFEEL != null) { 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"; } else if (LOOKANDFEEL.equals("System")) { lookAndFeel = UIManager.getSystemLookAndFeelClassName(); } else if (LOOKANDFEEL.equals("Motif")) { lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; } else if (LOOKANDFEEL.equals("GTK")) { lookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"; } else { System.err.println("Unexpected value of LOOKANDFEEL specified: " + LOOKANDFEEL); lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName(); } try { UIManager.setLookAndFeel(lookAndFeel); // If L&F = "Metal", set the theme if (LOOKANDFEEL.equals("Metal")) { if (THEME.equals("DefaultMetal")) MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme()); else if (THEME.equals("Ocean")) MetalLookAndFeel.setCurrentTheme(new OceanTheme()); else MetalLookAndFeel.setCurrentTheme(new TestTheme()); UIManager.setLookAndFeel(new MetalLookAndFeel()); } } catch (ClassNotFoundException e) { System.err.println("Couldn't find class for specified look and feel:" + lookAndFeel); System.err.println("Did you include the L&F library in the class path?"); System.err.println("Using the default look and feel."); } catch (UnsupportedLookAndFeelException e) { System.err.println("Can't use the specified look and feel (" + lookAndFeel + ") on this platform."); System.err.println("Using the default look and feel."); } catch (Exception e) { System.err.println("Couldn't get specified look and feel (" + lookAndFeel + "), for some reason."); System.err.println("Using the default look and feel."); e.printStackTrace(); } } } private static void createAndShowGUI() { //Set the look and feel. initLookAndFeel(); //Make sure we have nice window decorations. JFrame.setDefaultLookAndFeelDecorated(true); //Create and set up the window. JFrame frame = new JFrame("SwingApplication"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); LookAndFeelDemo app = new LookAndFeelDemo(); Component contents = app.createComponents(); frame.getContentPane().add(contents, BorderLayout.CENTER); //Display the window. frame.pack(); frame.setVisible(true); } public static void main(String[] args) { //Schedule a job for the event dispatch thread: //creating and showing this application's GUI. javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } } ``` 介绍主题是一种轻松改变跨平台 Java(金属)外观和颜色的颜色和字体的方法。在上面列出的示例程序`LookAndfeelDemo.java`中,您可以通过将第 23 行的`THEME`常量设置为以下三个值之一来更改 Metal L& F 的主题: * `DefaultMetal` * `Ocean` * `Test` `Ocean`,比纯金属外观略微柔和,自 Java SE 5 以来一直是 Metal(Java)L& F 的默认主题。尽管它的名称,`DefaultMetal`不是 Metal 的默认主题(它在 Java SE 5 之前,它解释了它的名字)。 `Test`主题是 [``TestTheme.java``](../examples/lookandfeel/LookAndFeelDemoProject/src/lookandfeel/TestTheme.java)中定义的主题,您必须使用`LookAndfeelDemo.java`进行编译。正如它所写,`TestTheme.java`设置三原色(有些奇怪的结果)。您可以修改`TestTheme.java`来测试您喜欢的任何颜色。 设置主题的代码部分从`LookAndfeelDemo.java`的第 92 行开始。请注意,您必须使用 Metal L& F 来设置主题。 ```java if (LOOKANDFEEL.equals("Metal")) { if (THEME.equals("DefaultMetal")) MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme()); else if (THEME.equals("Ocean")) MetalLookAndFeel.setCurrentTheme(new OceanTheme()); else MetalLookAndFeel.setCurrentTheme(new TestTheme()); UIManager.setLookAndFeel(new MetalLookAndFeel()); } ``` 当您下载 [JDK 和 JavaFX 演示和样例](http://www.oracle.com/technetwork/java/javase/downloads/index.html)包并打开它时,有一个`demo\jfc`文件夹包含一个名为`SwingSet2`的演示程序。该程序具有图形丰富的 GUI,允许您从菜单中更改外观。此外,如果您使用 Java(金属)外观,您可以选择各种不同的主题。各种主题的文件(例如,`RubyTheme.java`)可在`SwingSet2\src`文件夹中找到。 这是“海洋”主题,这是跨平台 Java(金属)外观的默认主题: ![](img/38a8bf71ede9759787954c09ba8bbf18.jpg) 这是“钢铁”主题,这是跨平台 Java(金属)外观的原始主题: ![](img/7309e77d4ae15b4bb871b4db5f3174c9.jpg) 要在安装了 JDK 的系统上运行`SwingSet2`演示程序,请使用以下命令: ```java java -jar SwingSet2.jar ``` 这将为您提供默认主题 Ocean。 要获得金属 L& F,请运行以下命令: ```java java -Dswing.metalTheme=steel -jar SwingSet2.jar ```