在使用多个自己的 UI(例如 JTabbedPane)的 Java Swing 应用程序中,有时在启动后,整个应用程序的外观 (L&F) 会更改回默认值。它快速显示一切正确,然后在一秒钟或更短的时间内整个应用程序更改为丑陋的默认设置。
不幸的是,这很难重现。当我使用 java-1.6.0-openjdk-amd64 直接从 Eclipse 中启动它时,它很少发生,到目前为止仅在 Ubuntu 下发生。我也安装了较新的 java 版本,但我使用 1.6 来测试兼容性。
由于它发生在所有组件或没有组件发生,看起来 II 如何派生 UI 并不重要。它甚至改变了这个没有使用自定义 UI 的小改动:
JTextField textField = new JTextField();
textField.setBorder(null);
所以如果它发生了,那么边界就会出现。
由于这很难重现,我不能给出一个总是发生的代码示例。实际上,上面的例子已经是一个例子,但它并不总是发生。但我希望找到遇到类似问题的人,其中 L&F 或其任何更改突然和不需要的更改回默认值。如果是这样,如果您能分享您的经验并希望有一个解决方案,我将不胜感激。
---------------- 编辑:我发现了两个解决方法:
- 对于边框问题,我只是简单地使用
textField.setBorder(new EmptyBorder());
而不是将其设置为空。 对于 UI 的重置,这确实是由对 updateUI 的不必要调用引起的,我为我的自定义 swing 对象创建了覆盖 updateUI() 的子类,例如:
public class JTabbedPaneNoHeads extends JTabbedPane { public JTabbedPaneNoHeads() { setUI(new GUITabbedPaneNoHeadsUI()); } @Override public GUITabbedPaneNoHeadsUI getUI() { return (GUITabbedPaneNoHeadsUI) ui; } @Override public void updateUI() { /* This was to find out who is calling updateUI: StackTraceElement[] _stackTrace = Thread.currentThread().getStackTrace(); for (StackTraceElement element : _stackTrace ){ System.out.print(element + " -- "); } System.out.println(); */ setUI(new GUITabbedPaneNoHeadsUI()); } }
现在一切正常。
顺便说一句:对 updateUI 的调用具有以下堆栈跟踪(由上面代码中的注释块生成):
livedocket.GUI.design.JTabbedPaneNoHeads.updateUI(JTabbedPaneNoHeads.java:22)
javax.swing.SwingUtilities.updateComponentTreeUI0(SwingUtilities.java:1230)
.... many more of these updateComponentTreeUI0 ...
javax.swing.SwingUtilities.updateComponentTreeUI0(SwingUtilities.java:1245)
javax.swing.SwingUtilities.updateComponentTreeUI(SwingUtilities.java:1221)
javax.swing.plaf.metal.MetalLookAndFeel$AATextListener.updateWindowUI(MetalLookAndFeel.java:2329)
javax.swing.plaf.metal.MetalLookAndFeel$AATextListener.updateAllUIs(MetalLookAndFeel.java:2342)
javax.swing.plaf.metal.MetalLookAndFeel$AATextListener.access$200(MetalLookAndFeel.java:2295)
javax.swing.plaf.metal.MetalLookAndFeel$AATextListener$1.run(MetalLookAndFeel.java:2370)
java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:226)
java.awt.EventQueue.dispatchEventImpl(EventQueue.java:673)
java.awt.EventQueue.access$300(EventQueue.java:96)
java.awt.EventQueue$2.run(EventQueue.java:634)
java.awt.EventQueue$2.run(EventQueue.java:632)
java.security.AccessController.doPrivileged(Native Method)
java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:108)
java.awt.EventQueue.dispatchEvent(EventQueue.java:643)
java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
正如我之前提到的,这些调用很少发生,而且只在 Java 1.6 上发生。