NetBeans 平台:如何以编程方式设置基于 Swing 的 GUI 组件的样式?

NetBeans Platform: How to style the Swing based GUI components programmatically?

简介

我必须使用 NetBeans 平台和 JavaFX 11 编写一个胖客户端。其中一个要求是为应用程序提供默认的深色主题。因此,如果应用程序的用户按下深色模式按钮,则应用程序的 GUI 必须使用深色主题。

问题

虽然我很清楚如何设置 JFX 组件的样式(通过 CSS 文件),但 CSS 文件对菜单栏等 NetBeans 平台的组件没有影响,因为它们是基于 Swing 的。例如,场景对象中的 JavaFX 组件采用深色样式,但 NetBeans 菜单栏仍然是浅色。

问题

如何以编程方式更改 NetBeans 平台组件的样式(就像您在 Web 开发中使用 CSS 或在 JavaFX 中使用 CSS 支持所做的那样)?

平台(至少在我使用的 NB12 中)有一个嵌入式暗 LAF,叫做 FlatDarkLaf,看起来不错。

为了使用它,您需要在ModuleInstall子类的validate()方法中添加以下代码,以便在启动过程中尽早完成。

NbPreferences.root().node("laf").put("laf", "com.formdev.flatlaf.FlatDarkLaf");
UIManager.installLookAndFeel(new UIManager.LookAndFeelInfo("FlatLaf Dark", latDarkLaf.class.getName()));  

切换回默认主题:

NbPreferences.root().node("laf").remove("laf");

我不知道在不重新启动的情况下更改 LAF 的(简单)方法。

有关更完整的示例代码,请查看我在 GitHubUISettings Netbeans 模块中的应用程序 JJazzLab-X。

编辑 Netbeans 12.5

无需调用installLookAndFeel(),更新NbPreferences即可。

更新 NbPreferences 的模块也应该依赖于 非 API Netbeans 平台模块 FlatLaf Look and Feel.

如果您的 Netbeans 平台应用程序使用 Netbeans 品牌(例如,自定义图标和初始屏幕),它会在您的品牌目录中创建 frame.gif 等文件。但是在 运行 的时候,如果你 运行 像 FlatDarkLaf 这样的深色主题,Netbeans 会期望图标被命名为 frame_dark.gif,所以你应该重命名它们。有关详细信息,请参阅 ImageUtilities.loadImage() 的 javadoc。

为了完整起见,我添加了解决我的问题的代码片段:

    private void toggleLookAndFeel() {
        final boolean darkModeEnabled = UIManager.getLookAndFeel().getName().equals("Flat Dark");
        final String darkLookAndFeel = "com.formdev.flatlaf.FlatDarkLaf";
        final String defaultLookAndFeel = UIManager.getSystemLookAndFeelClassName();
        try {
            if (darkModeEnabled) {
                // set laf of swing components
                UIManager.setLookAndFeel(defaultLookAndFeel);
                // use default css file for javafx components
                this.fxPanel.getScene().getStylesheets().remove(0);
            } else {
                // set laf of swing components
                UIManager.setLookAndFeel(darkLookAndFeel);
                // use app.css file for javafx components
                this.fxPanel.getScene().getStylesheets().add(0, getClass().getResource("app.css").toExternalForm());
            }
        } catch (IllegalAccessException | InstantiationException | UnsupportedLookAndFeelException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        triggerSwingComponentUpdate();
    }

    private static void triggerSwingComponentUpdate() {
        SwingUtilities.invokeLater(() -> {
            for (final Window w : Window.getWindows()) {
                SwingUtilities.updateComponentTreeUI(w);
            }
        });
    }