【问题标题】:How to change Swing application's look and feel at runtime?如何在运行时更改 Swing 应用程序的外观?
【发布时间】:2013-04-23 09:10:22
【问题描述】:

我知道有一个SwingUtilities.updateComponentTreeUI(Component c) 方法,但它不能完美运行。例如,我有一个JFileChooser,当前的外观是 Windows,然后我用SwingUtilities.updateComponentTreeUI(mainWindow) 将外观更改为 Nimbus,并且主窗口的样式正确更改,但是当我显示文件选择器时JFileChooser.showOpenDialog(Component parent) 方法,它仍然在 Windows 外观中。如果我使用JPopupMenu.show(Component invoker, int x, int y) 方法显示一个弹出对话框,也会发生同样的情况。

这个问题有什么解决办法吗?

【问题讨论】:

标签: java swing user-interface look-and-feel


【解决方案1】:

假设value是新外观的类名,这里是更新所有窗口和子组件的sn-p:

public static void updateLAF(String value) {
    if (UIManager.getLookAndFeel().getClass().getName().equals(value)) {
        return;
    }
    try {
        UIManager.setLookAndFeel(value);
        for (Frame frame : Frame.getFrames()) {
            updateLAFRecursively(frame);
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedLookAndFeelException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

public static void updateLAFRecursively(Window window) {
    for (Window childWindow : window.getOwnedWindows()) {
        updateLAFRecursively(childWindow);
    }
    SwingUtilities.updateComponentTreeUI(window);
}

【讨论】:

  • 如果您在自己的代码中缓存不属于 Swing 层次结构的 Swing 组件,这将无济于事。
  • @Robin 确实,缓存组件很好。然而,如果它嵌入到另一个组件中,即层次结构,另一种选择是覆盖updateUI,调用super.updateUI,并将调用转发给文件选择器。
  • 我知道这要归功于经验。已经在我自己的代码中花一些时间解决这个问题。通常对于文件选择器,它不包含在层次结构中,而仅在需要时在对话框中打开
  • Window[] wins = Window.getWindows(); 而不是` Window window : frame.getOwnedWindows()` 可能适用于所有可能为isDisplayable()isDisplayable( 的容器)返回删除了Rootpane 或@ 的容器987654329@e 以编程方式更改
  • 更新Window.getWindows() 返回的所有窗口不会影响我尚未在对话框中显示的文件选择器。
【解决方案2】:

调用SwingUtilities.updateComponentTreeUI(mainWindow)只会更新mainWindow下的Swing层次结构中的Swing组件。

如果您将 JFileChooser 存储在代码中的某处(例如,在类的字段中)而不显示 JFileChooser,则选择器将不会被 SwingUtilities.updateComponentTreeUI(mainWindow) 调用更新。您可以通过自己向UIManager 添加一个侦听器并在外观更改时从该侦听器调用SwingUtilities.updateComponentTreeUI(myStoredFileChooser) 来解决此问题。

确保您不会因此而造成内存泄漏,例如让那个监听器只有一个 WeakReferenceJFileChooser (因为 UIManager 的生命周期等于 JVM 的生命周期)

【讨论】:

  • 如何给UIManager添加监听器?
  • 在突出 WeakReference 方面做得很好。
  • @ZhaoYi 你有没有费心打开UIManager 类的javadoc。在那种情况下,我相信你会找到addPropertyChangeListener 方法
  • 正如我在下面所说的,某些组件可能是由 3rd 方库创建的,因此我无法获得它们的引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-19
  • 2019-07-26
  • 1970-01-01
相关资源
最近更新 更多