【Java】Swing-LookAndFeel 初解

参考:

https://blog.csdn.net/sureyonder/article/details/5695420?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-14&spm=1001.2101.3001.4242

https://www.cnblogs.com/zhchoutai/p/8726824.html

 

Swing/LookAndFeel 优美的 MVC 模式会给你一个良好的编程思想。

Swing 是什么?

Swing 是 Java 官方推出的,绝大部分控件都由 Graphics2D 绘制的一种轻量级 GUI 方案。其全部的轻量级控件都继承自 JComponent 类。

须要注意的是,Swing 中依旧有三个重量级控件:JFrame,JDialog,JWindow。只是它们都是窗口,他们都继承自 Window 类。

而不管是 JComponent 还是 Window 它们都继承自 Container 类,这事实上也就意味着:全部的 Swing 控件,都能够做控件容器

Swing 是怎样通过 Graphics2D 绘制这些控件的呢?

答案就是 LookAndFeel 机制。

通俗的说,这就是皮肤

从功能上说。这是一种批量管理 Swing 控件外观的机制;

从根源来说,这是 Swing 的核心。

官方在 Java 7 中正式推出的 NimbusLookAndFeel 则要美观的多。

你问怎样换 LookAndFeel?

在启动你的程序前:

UIManager.setLookAndFeel(…);

就可以

假设是在程序已经启动之后再换 LookAndFeel,那在上面那句之后,建议再加上:

SwingUtilities.updateComponentTreeUI(…);

所谓 MVC 就是:模型(Model)、视图(View)、控制器(Controller)这种一种结构。

Swing 中,差点儿全部的控件都能够清晰的分解成这三大部分。

就拿 JButton 来举例,我们能够这样分解:

JButton——控制器;

ButtonModel——模型。其最常见的详细实现类是:DefaultButtonModel。

ButtonUI——视图,其最常见的详细实现类是:MetalButtonUI;

JButton 负责控制,ButtonModel 提供模型,而 ButtonUI 实现展示。

也就是说,基本上全部的 Swing 控件都是由一个 Control 类、一个 Model 类、一个 UI 类组成的。

部分过于简单和数据无关的控件无 Model 类,比如 JPanel……

Swing 是怎样通过 UI 类来绘制控件的呢?

 Swing 控件在 UI 线程中的绘制过程:

会产生一个 PaintEvent 然后排入 UI 线程的事件处理序列;

而 UI 线程在处理 Swing 控件的 PaintEvent 时,终于都会调用到控件的 paint 方法。

通过源码分析,总结如下:

一个控件要绘制,就必定调用到它的 paint 方法;

而默认的 paint 方法中会调用到 paintComponent 方法;

paintComponent 方法中又会调用 UI 类的 update 方法;

也就是说,一个控件的绘制,和其 UI 类中的 update 方法是息息相关的。

看,UI 类成功的和控件绘制关联上了。

各个控件的 UI 类又是怎么被设置到 Control 类中的呢?

这里要提到一个非常重要的类——UIManager

在 LookAndFeel 机制中,会有大量的键值对存放在一个 UIDefaults(事实上就是个 HashTable)中。

这些键值对记录了控件的边框、各种部分的颜色、字体等等,当中也包含了这个控件相应的 UI 类的类名。

而 UIManager 就是方便我们调用或替换这些键值对的一个管理工具类。

通过源码分析,原来是通过控件类中的 getUIClassID 返回的“键”。来获得 UI 类的类名在 UIDefaults 中的“值”。然后反射生成 UI 类的对象。

总结如下:

在控件构造时,都会去调用 updateUI 方法;

在控件的 updateUI 方法中,会通过 UIManager.getUI 去获取 ui 对象;

而 getUIClass(target.getUIClassID(), uiClassLoader),是通过控件的 uiClassID 这个“键”去获得 UIDefaults 中的相应的“值”;

而最后依据返回的类名,反射生成一个 UI 类的对象(PanelUI),返回给 updateUI 方法;

再通过 setUI 方法赋值给 ui 成员变量。

假设你打算自己写一套 LookAndFeel,当你写了一个 UI 类之后应该怎么和控件相应上呢?

答案就是改写 LookAndFeel 类中的 initClassDefaults 方法,设置相应的组件对。

例如源码:MetalLookAndFeel 类,initClassDefaults 方法:

protected void initClassDefaults(UIDefaults table)
    {
        super.initClassDefaults(table);
        final String metalPackageName = "javax.swing.plaf.metal.";
        Object[] uiDefaults = {
                   "ButtonUI", metalPackageName+ "MetalButtonUI",
                 "CheckBoxUI", metalPackageName+ "MetalCheckBoxUI",
                 "ComboBoxUI", metalPackageName + "MetalComboBoxUI",
              "DesktopIconUI", metalPackageName + "MetalDesktopIconUI",
              "FileChooserUI", metalPackageName + "MetalFileChooserUI",
            "InternalFrameUI", metalPackageName + "MetalInternalFrameUI",
                    "LabelUI", metalPackageName + "MetalLabelUI",
       "PopupMenuSeparatorUI", metalPackageName + "MetalPopupMenuSeparatorUI",
              "ProgressBarUI", metalPackageName + "MetalProgressBarUI",
              "RadioButtonUI", metalPackageName + "MetalRadioButtonUI",
                "ScrollBarUI", metalPackageName + "MetalScrollBarUI",
               "ScrollPaneUI", metalPackageName + "MetalScrollPaneUI",
                "SeparatorUI", metalPackageName + "MetalSeparatorUI",
                   "SliderUI", metalPackageName + "MetalSliderUI",
                "SplitPaneUI", metalPackageName + "MetalSplitPaneUI",
               "TabbedPaneUI", metalPackageName + "MetalTabbedPaneUI",
                "TextFieldUI", metalPackageName + "MetalTextFieldUI",
             "ToggleButtonUI", metalPackageName + "MetalToggleButtonUI",
                  "ToolBarUI", metalPackageName + "MetalToolBarUI",
                  "ToolTipUI", metalPackageName + "MetalToolTipUI",
                     "TreeUI", metalPackageName + "MetalTreeUI",
                 "RootPaneUI", metalPackageName + "MetalRootPaneUI",
        };
        table.putDefaults(uiDefaults);
    }
原文地址:https://www.cnblogs.com/cathygx/p/14350736.html