如何设置外观

Swing 的体系结构经过设计,因此您可以更改应用程序 GUI 的“外观”(L&F)(请参阅Swing 体系结构概述)。 “外观”是指 GUI 小部件的外观(更正式地为JComponents),“感觉”是指小部件的行为方式。

Swing 的体系结构通过将每个组件分为两个不同的类来实现多个 L&F:JComponent子类和相应的ComponentUI子类。例如,每个JList实例都有ListUI的具体实现(ListUI扩展了ComponentUI)。 ComponentUI子类在 Swing 的文档中由各种名称引用-“ UI”,“组件 UI”,“ UI 委托”和“外观委托”均用于标识ComponentUI子类。

大多数开发人员永远不需要直接与 UI 委托进行交互。在大多数情况下,JComponent子类在内部使用 UI 委托以实现关键功能,而JComponent子类提供的掩盖方法用于对 UI 委托的所有访问。例如,JComponent子类中的所有绘画都委托给 UI 委托。通过委托绘画,“外观”可以根据 L&F 的不同而不同。

每个 L&F 都有责任为 Swing 定义的每个ComponentUI子类提供具体的实现。例如,Java 外观创建MetalTabbedPaneUI的实例,以提供JTabbedPane的 L&F。 UI 委托的实际创建由 Swing 为您处理-在大多数情况下,您无需直接与 UI 委托进行交互。

本节的其余部分讨论以下主题:

可用的外观

Sun 的 JRE 提供以下 L&F:

  • CrossPlatformLookAndFeel —这是在所有平台上看起来都相同的“ Java L&F”(也称为“金属”)。它是 Java API(javax.swing.plaf.metal)的一部分,并且是默认设置,如果您在代码中不执行任何操作来设置其他 L&F,将使用该默认设置。

  • SystemLookAndFeel-在这里,应用程序使用其运行系统固有的 L&F。系统 L&F 在运行时确定,其中应用程序要求系统返回适当 L&F 的名称。

  • 合成器-使用 XML 文件创建自己的外观的基础。

  • 复用-一种将 UI 方法委派给多个不同外观实现的方式。

对于 Linux 和 Solaris,如果安装了 GTK 2.2 或更高版本,则系统 L&F 为“ GTK”,否则为“ Motif”。对于 Windows,系统 L&F 是“ Windows”,它模仿正在运行的特定 Windowsos(经典 Windows,XP 或 Vista)的 L&F。 GTK,Motif 和 Windows L&F 由 Sun 提供,并且随 Java SDK 和 JRE 一起提供,尽管它们不是 Java API 的一部分。

苹果提供了自己的 JVM,其中包括其专有的 L&F。

总而言之,当您使用SystemLookAndFeel时,将看到以下内容:

Platform外观
Solaris,Linux 和 GTK 2.2 或更高版本GTK+
其他 Solaris,LinuxMotif
IBM UNIXIBM*
HP UXHP*
Classic WindowsWindows
Windows XPWindows XP
Windows VistaWindows Vista
MacintoshMacintosh*

*由系统供应商提供。

您在 API 中看不到系统 L&F。 Java SDK 附带了所需的 GTK,Motif 和 Windows 软件包,它们是:

com.sun.java.swing.plaf.gtk.GTKLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel

请注意,该路径包括java,而不包括javax

Note:

GTK L&F 仅在安装了 GTK 2.2 或更高版本的 UNIX 或 Linux 系统上运行,而 Windows L&F 仅在 Windows 系统上运行。像 Java(金属)L&F 一样,Motif L&F 可以在任何平台上运行。

Sun 的所有 L&F 都有很多共性。此通用性在 API(javax.swing.plaf.basic)的Basic外观中定义。 Motif 和 Windows L&F 分别通过扩展javax.swing.plaf.basic中的 UI 委托类来构建(可以通过执行相同的操作来构建自定义 L&F)。未经扩展,不得使用“基本” L&F。

在 API 中,您将看到四个 L&F 软件包:

  • javax.swing.plaf.basic —创建自定义 L&F 时要扩展的基本 UI 委托

  • javax.swing.plaf.metal — Java L&F,也称为 CrossPlatform L&F(“金属”是此 L&F 的 Sun 项目名称)。该 L&F 的当前默认“主题”(如下所述)为“海洋”,因此通常称为海洋 L&F。

  • javax.swing.plaf.multi —一种多路复用的外观,它允许 UI 方法同时委派给多个外观实现。它可以用于增强特定外观的行为,例如,通过 L&F 在 Windows 外观之上提供音频提示的 L&F。这是创建残障人士可访问的外观的方式。

  • javax.swing.plaf.synth —使用 XML 文件轻松配置的 L&F(在本类的下一部分中讨论)

您不仅限于 Java 平台随附的 L&F。您可以使用程序的 Classpath 中的任何 L&F。外部 L&F 通常在一个或多个 JAR 文件中提供,您可以在运行时将其添加到程序的 Classpath 中。例如:

java -classpath .;C:\java\lafdir\customlaf.jar YourSwingApplication

一旦外部 L&F 进入程序的 Classpath,您的程序就可以像使用 Java 平台附带的任何 L&F 一样使用它。

以编程方式设置外观

Note:

如果要设置 L&F,则应将其作为应用程序的第一步。否则,无论您请求什么 L&F,都有冒着初始化 Java L&F 的风险。当静态字段引用 Swing 类时,可能会无意中发生,这会导致 L&F 加载。如果尚未指定 L&F,则将加载 JRE 的默认 L&F。对于 Sun 的 JRE,默认值为 Java L&F,对于苹果的 JRE,默认值为 Apple L&F,依此类推。

Swing 组件使用的 L&F 通过javax.swing包中的UIManager类指定。每当创建 Swing 组件时,该组件都会向 UI管理 器询问实现该组件 L&F 的 UI 委托。例如,每个JLabel构造函数都向 UI管理 器查询适合于标签的 UI 委托对象。然后,它使用该 UI 委托对象来实现其所有绘图和事件处理。

要以编程方式指定 L&F,请使用UIManager.setLookAndFeel()方法,并将LookAndFeel的适当子类的完全限定名称作为其参数。例如,以下代码段中的粗体代码使程序使用跨平台的 Java L&F:

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:

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");

or

// Set Motif L&F on any platform
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");

您不仅限于上述参数。您可以为程序的 Classpath 中的任何 L&F 指定名称。

指定外观:命令行

您可以使用-D标志设置swing.defaultlaf属性来在命令行中指定 L&F。例如:

java -Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel MyApp

java -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel MyApp

指定外观:swing.properties 文件

指定当前 L&F 的另一种方法是使用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管理 器需要设置 L&F 时,以下是外观确定步骤:

  • 如果程序在需要外观之前设置 L&F,则 UI管理 器将try创建指定外观类的实例。如果成功,则所有组件都将使用该 L&F。

  • 如果程序尚未成功指定 L&F,则 UI管理 器将使用swing.defaultlaf属性指定的 L&F。如果在命令行的swing.properties文件中都指定了属性,则命令行定义优先。

  • 如果这些步骤均未导致有效的 L&F,则 Sun 的 JRE 使用 Java L&F。其他供应商(例如 Apple)将使用其默认的 L&F。

启动后更改外观

即使程序的 GUI 可见,您也可以使用setLookAndFeel更改 L&F。要使现有组件反映新的 L&F,请对每个顶级容器调用一次SwingUtilities updateComponentTreeUI方法。然后,您可能希望调整每个顶级容器的大小,以反映其包含的组件的新大小。例如:

UIManager.setLookAndFeel(lnfName);
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();

An Example

在以下示例LookAndFeelDemo.java中,您可以try使用不同的外观。该程序创建一个带有按钮和标签的简单 GUI。每次单击按钮,标签都会递增。

您可以通过更改第 18 行的LOOKANDFEEL常量来更改 L&F。前几行的 注解 告诉您可接受的值:

// 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 的部分中,您将看到设置它的几种不同方法,如上所述:

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源文件的列表:

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

Themes

引入主题是一种轻松更改跨平台 Java(金属)外观的颜色和字体的方式。在上面列出的示例程序LookAndfeelDemo.java中,可以通过将第 23 行的THEME常量设置为三个值之一来更改 Metal L&F 的主题:

  • DefaultMetal

  • Ocean

  • Test

自 Java SE 5 起,Ocean比纯 Metal 外观要柔和一些,它一直是 Metal(Java)L&F 的默认主题,尽管它的名字是DefaultMetal并不是 Metal 的默认主题(它在 Java SE 5 之前是,解释其名称)。 Test主题是在TestTheme.java中定义的主题,您必须使用LookAndfeelDemo.java进行编译。在编写时,TestTheme.java设置了三种原色(结果有些奇怪)。您可以修改TestTheme.java以测试您喜欢的任何颜色。

LookAndfeelDemo.java的第 92 行开始可以找到设置主题的代码部分。请注意,您必须使用 Metal L&F 设置主题。

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

SwingSet2 演示程序

当您下载JDK 和 JavaFX 演示和 samplesBinding 包并打开它时,会有一个demo\jfc文件夹,其中包含一个名为SwingSet2的演示程序。该程序具有图形丰富的 GUI,可让您从菜单中更改外观。此外,如果您使用的是 Java(金属)外观,则可以选择各种不同的主题。 SwingSet2\src文件夹中包含各种主题的文件(例如RubyTheme.java)。

这是“海洋”主题,这是跨平台 Java(金属)外观的默认设置:

这是“钢”主题,它是跨平台 Java(金属)外观的原始主题:

要在安装了 JDK 的系统上运行SwingSet2演示程序,请使用以下命令:

java -jar SwingSet2.jar

这将为您提供默认的海洋主题。

要获取金属 L&F,请运行以下命令:

java -Dswing.metalTheme=steel -jar SwingSet2.jar