在使用多个自己的 UI(例如 JTabbedPane)的 Java Swing 应用程序中,有时启动后,整个应用程序的外观 (L&F) 会变回默认值。它很快显示一切正确,然后在一秒或更短的时间内,整个应用程序更改为丑陋的默认值。
不幸的是,这很难重现。当我使用 java-1.6.0-openjdk-amd64 直接从 Eclipse 中启动它时,这种情况很少发生,到目前为止仅在 Ubuntu 下发生。我也安装了较新的java版本,但我使用1.6来测试兼容性。
由于这种情况要么发生在所有组件上,要么没有发生在任何组件上,所以看起来我如何派生 UI 并不重要。它甚至会在不使用自定义 UI 的情况下改回这个小更改:
JTextField textField = new JTextField();
textField.setBorder(null);
因此,如果发生这种情况,则会显示边框。
由于这很难重现,我无法给出总是发生这种情况的代码示例。实际上,上面的例子已经是一个例子,但并不总是这样。但我希望找到遇到类似问题的人,其中 L&F 或对其进行的任何更改突然且不需要地更改回默认值。如果是这样,如果您能分享您的经验并希望找到解决方案,我将不胜感激。
---------------- 编辑: 我找到了两个解决方法:
- 对于边框问题,我只是使用
textField.setBorder(new EmptyBorder());
而不是将其设置为 null。 对于 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 的调用具有以下堆栈跟踪(由上面代码中的注释 block 生成):
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 上。
最佳答案
我在具有线程问题的应用程序中看到了类似的症状 - 如果我是你,我会仔细检查所有 GUI 是否都是在事件调度线程上构建的。
关于具有自己的 L&F 的 Java Swing 有时会突然切换回默认 L&F,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18800687/