Java 11下用JLayer搭配JScrollPane时Synthetica外观抛出类转换异常
Java 11 + Synthetica 下JLayer结合JScrollPane抛出类转换异常的修复方案
问题描述
在Java 11环境中使用Synthetica外观时,将JLayer直接包裹JScrollPane会抛出类转换异常,但该场景在Java 8下可正常运行。
代码示例
public class TestFrame extends JFrame { TestFrame() { this.setSize(300,400); this.getContentPane().setLayout(new FlowLayout()); JTextArea textArea = new JTextArea(20, 20); JScrollPane scrollableTextArea = new JScrollPane(textArea); LayerUI<JScrollPane> layerUI = new LayerUI(); JLayer<JScrollPane> jLayer = new JLayer(scrollableTextArea, layerUI); this.add(jLayer); } public static void main(String[] args) { try { UIManager.setLookAndFeel(new SyntheticaAluOxideLookAndFeel()); TestFrame testFrame = new TestFrame(); testFrame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }
错误堆栈信息
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: class javax.swing.JLayer cannot be cast to class javax.swing.JScrollPane (javax.swing.JLayer and javax.swing.JScrollPane are in module java.desktop of loader 'bootstrap') at de.javasoft.plaf.synthetica.painter.ScrollPanePainter.paintScrollPaneBorder(ScrollPanePainter.java:274) at de.javasoft.plaf.synthetica.painter.SyntheticaPainter.paintScrollPaneBorder(SyntheticaPainter.java:640) at java.desktop/javax.swing.plaf.synth.SynthScrollPaneUI.paintBorder(SynthScrollPaneUI.java:125) at java.desktop/javax.swing.plaf.synth.SynthBorder.paintBorder(SynthBorder.java:63) at java.desktop/javax.swing.JComponent.paintBorder(JComponent.java:967) at java.desktop/javax.swing.JComponent.paint(JComponent.java:1075) at java.desktop/javax.swing.JLayer.paint(JLayer.java:475) at java.desktop/javax.swing.plaf.LayerUI.paint(LayerUI.java:80) at java.desktop/javax.swing.plaf.ComponentUI.update(ComponentUI.java:161) at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:797) at java.desktop/javax.swing.JLayer.paint(JLayer.java:470) at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907) at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083) at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907) at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083) at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:590) at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907) at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5262)
修复方案
方案1:调整JLayer的包裹层级
不要直接用JLayer包裹JScrollPane,而是将JLayer应用到JScrollPane内部的视口组件(比如示例中的JTextArea),再将JLayer放入JScrollPane中。修改后的代码:
public class TestFrame extends JFrame { TestFrame() { this.setSize(300,400); this.getContentPane().setLayout(new FlowLayout()); JTextArea textArea = new JTextArea(20, 20); // 先给文本区域添加JLayer LayerUI<JTextArea> layerUI = new LayerUI<>(); JLayer<JTextArea> jLayer = new JLayer<>(textArea, layerUI); // 将JLayer放入JScrollPane JScrollPane scrollableTextArea = new JScrollPane(jLayer); this.add(scrollableTextArea); } public static void main(String[] args) { try { UIManager.setLookAndFeel(new SyntheticaAluOxideLookAndFeel()); TestFrame testFrame = new TestFrame(); testFrame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }
方案2:自定义修复Synthetica的ScrollPanePainter
异常根源是Synthetica的ScrollPanePainter在Java 11中未处理JLayer包装的场景,直接强制转换组件类型。可以自定义Painter类覆盖原有逻辑,在转换前先判断组件类型:
import de.javasoft.plaf.synthetica.painter.ScrollPanePainter; import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JLayer; import javax.swing.JScrollPane; public class FixedScrollPanePainter extends ScrollPanePainter { @Override public void paintScrollPaneBorder(Graphics g, JComponent c) { JScrollPane scrollPane = null; // 优先获取真正的JScrollPane组件 if (c instanceof JScrollPane) { scrollPane = (JScrollPane) c; } else if (c instanceof JLayer) { JLayer<?> layer = (JLayer<?>) c; Object view = layer.getView(); if (view instanceof JScrollPane) { scrollPane = (JScrollPane) view; } } // 调用原逻辑处理有效组件,否则执行默认逻辑 if (scrollPane != null) { super.paintScrollPaneBorder(g, scrollPane); } else { super.paintScrollPaneBorder(g, c); } } }
之后需要通过Synthetica的配置机制替换原有的Painter,具体可参考其官方自定义皮肤文档。
方案3:升级Synthetica至Java 11兼容版本
检查Synthetica官方是否发布了支持Java 11及以上版本的更新包,官方通常会修复这类跨版本兼容性问题。
内容的提问来源于stack exchange,提问作者Ashan
相关产品推荐
相关产品推荐

