Java Swing 模块化配色方案

Posted

技术标签:

【中文标题】Java Swing 模块化配色方案【英文标题】:Java Swing modular color scheme 【发布时间】:2015-04-09 15:03:21 【问题描述】:

我正在使用 Java 的 Swing 工具包设置一个大型 GUI(比我以前做过的任何事情都大),我想设置我自己的自定义配色方案来绘制颜色,以便所有颜色定义都在一个地方。为此,我决定创建一个名为 ColorPalette 的伪静态***类(来自 https://***.com/a/7486111/4547020 帖子),其中包含一个 SchemeEnum程序员为整个 GUI 设置配色方案。

我希望颜色选择独立于配色方案的知识。有谁知道设计模式或有效的方法来做到这一点?我不完全相信我当前的设置是实现这一点的最佳方式,但我想设置一个模块化设计,添加更多 ColorEnumsSchemeEnums(在编译时,而不是运行时)。

为了澄清起见,我希望程序员能够简单地选择一个 ColorEnum 并根据 ColorEnum 返回一个 java.awt.Color 对象和定义的SchemeEnum

例如:

        // Use the BASIC color scheme
        ColorPalette.setCurrentScheme(ColorPalette.SchemeEnum.BASIC);

        // Set button backgrounds
        testButton.setBackground(ColorPalette.ColorEnum.DARK_RED.getColor());
        testButton2.setBackground(ColorPalette.ColorEnum.BLUE.getColor());

应该返回不同的Color对象而不是

        // Use the DARK color scheme
        ColorPalette.setCurrentScheme(ColorPalette.SchemeEnum.DARK);

        // Set button backgrounds
        testButton.setBackground(ColorPalette.ColorEnum.DARK_RED.getColor());
        testButton2.setBackground(ColorPalette.ColorEnum.BLUE.getColor());

因为他们有不同的 SchemeEnums,即使他们向 ColorPalette 请求相同的颜色。这样,更改 SchemeEnum 会更改 GUI 中的每种颜色,只需更改一行代码(或者甚至可以在运行时更改颜色)。

我听说过 HashTables 用于像这样的大型数据存储,但我不知道它们是如何工作的。这可能适用于这里吗?

到目前为止,这是我的代码。提前致谢!

package common.lookandfeel;

import java.awt.Color;

/**
 * Class which contains the members for the color scheme used throughout the project.
 * <p>This class is essentially static (no constructor, class is final, all members static) and
 * should not be instantiated.
 */
public final class ColorPalette

    /**
     * The list of color schemes to choose from.
     */
    public static enum SchemeEnum
    
        BASIC, DARK, METALLIC
    

    /**
     * The list of color descriptions to choose from.
     */
    public static enum ColorEnum
    
        LIGHT_RED(256,0,0), RED(192,0,0), DARK_RED(128,0,0),
        LIGHT_GREEN(0,256,0), GREEN(0,192,0), DARK_GREEN(0,128,0),
        LIGHT_BLUE(0,0,256), BLUE(0,0,192), DARK_BLUE(0,0,128),
        LIGHT_ORANGE(256,102,0), ORANGE(256,102,0), DARK_ORANGE(192,88,0),
        LIGHT_YELLOW(256,204,0), YELLOW(256,204,0), DARK_YELLOW(192,150,0),
        LIGHT_PURPLE(136,0,182), PURPLE(102,0,153), DARK_PURPLE(78,0,124);

        private int red;
        private int green;
        private int blue;

        private ColorEnum(int r, int g, int b)
        
            this.red = r;
            this.green = g;
            this.blue = b;
        

        /**
         * Get the selected color object for this Enum.
         * @return The color description as a Color object.
         */
        public Color getColor()
        
            // WANT TO RETURN A COLOR BASED ON currentScheme
            return new Color(red, green, blue);
        
    

    private static SchemeEnum currentScheme = SchemeEnum.BASIC;

    /**
     * Default constructor is private to prevent instantiation of this makeshift 'static' class.
     */
    private ColorPalette()
    
    

    /**
     * Get the color scheme being used on this project.
     * @return The current color scheme in use on this project.
     */
    public static SchemeEnum getCurrentScheme()
    
        return currentScheme;
    

    /**
     * Set the overall color scheme of this project.
     * @param currentPalette The color scheme to set for use on this project.
     */
    public static void setCurrentScheme(SchemeEnum cp)
    
        currentScheme = cp;
    

    /**
     * Main method for test purposes only.  Unpredictable results.
     * @param args Command line arguments.  Should not be present.
     */
    public static void main(String[] args)
    
        // Declare and define swing data members
        JFrame frame = new JFrame("Test Environment");
        CustomButton testButton = new CustomButton ("Hello World");
        CustomButton testButton2 = new CustomButton ("I am a button!");

        // Use a particular color scheme
        ColorPalette.setCurrentScheme(ColorPalette.SchemeEnum.BASIC);

        // Set button backgrounds
        testButton.setBackground(ColorPalette.ColorEnum.DARK_RED.getColor());
        testButton2.setBackground(ColorPalette.ColorEnum.BLUE.getColor());

        // Place swing components in Frame
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(testButton, BorderLayout.NORTH);
        frame.getContentPane().add(testButton2, BorderLayout.SOUTH);
        frame.pack();
        frame.setVisible(true);

        // Set allocated memory to null
        frame = null;
        testButton = null;
        testButton2 = null;

        // Suggest garbage collecting to deallocate memory
        System.gc();
    

【问题讨论】:

直接在 UIManager 中定义颜色或创建自己的外观和感觉会更简单,也许使用Synth 大部分 JComponents 都有属性数组,例如作为 JButton,这些属性对于所有可能的事件(选中、按下、武装......)都是不同的,使用自定义 L&F,在某些情况下可以设置配色方案(以避免重新发明***) == 在 UIManager 中的键内循环 【参考方案1】:

看起来和听起来您只需将 SchemeEnum 组合成由 ColorEnums 组成,就像您如何让 ColorEnum 由 rgb 值组成一样。

public static enum SchemeEnum

    // Don't really know what colors you actually want
    BASIC(ColorEnum.RED, ColorEnum.GREEN, ColorEnum.ORANGE),
    DARK(ColorEnum.DARK_RED, ColorEnum.DARK_GREEN, ColorEnum.DARK_ORANGE),
    METALLIC(ColorEnum.LIGHT_RED, ColorEnum.LIGHT_GREEN, ColorEnum.LIGHT_ORANGE);

    // nor know how many colors make up a scheme
    public ColorEnum mainColor;
    public ColorEnum secondaryColor;
    public ColorEnum borderColor;

    private SchemeEnum(ColorEnum mainColor, ColorEnum secondaryColor, 
                       ColorEnum borderColor)
    
        this.mainColor = mainColor;
        this.secondaryColor = secondaryColor;
        this.borderColor = borderColor;
    

然后,使用如下代码,其中颜色基于所选方案:

testButton.setBackground(ColorPalette.getCurrentScheme().mainColor.getColor());

【讨论】:

这种方法看起来非常模块化,不需要很多改变!我也喜欢为颜色标记用途而不是命名标记描述的想法(即mainColorborderColor 等而不是YELLOWDARK_GREEN 等)。我最初的概念是调整每种颜色的外观(即DARK 方案将只是BASIC 方案,但阴影有点暗)。如果我不是新成员,我会提供 +1 :) @FallDownT 新用户可以通过查看和滚动帮助 -> 游览页面来获得大量代表点。 @FallDownT 另外,您可能有兴趣查看 Nimbus 的外观和感觉,它能够设置看起来不错的配色方案。 docs.oracle.com/javase/tutorial/uiswing/lookandfeel/color.html 我之前看过 Numbus,认为它没有提供足够的多功能性。不过现在,我遇到了这样一个问题:每个 SchemeEnum 大约有 50 个 Color 对象,而 50 个参数的构造函数不一定是好习惯。关于如何在构造函数中为每个 SchemeEnum 设置每个 Color 的任何想法? @FallDownT 我可能会,不过我必须去一段时间。这似乎很奇怪,你有 50 种独特的颜色来构成 UI 的配色方案……这似乎不对,50 种独特的颜色似乎是正确的,但由 50 种颜色组成的方案却不是。【参考方案2】:

在重新发明***之前,Swing 基于可插拔的外观 API,请参阅 Modifying the Look and Feel。

正确的方法是定义自己的外观和感觉并加载它。因为您想提供可变数量的更改,所以使用Synth 之类的东西可能会更好。这允许您为对象定义级联属性,并允许您从其他属性继承(因此您可以设计一组基本属性,然后只更改您在每个后续外观中需要的属性)。

作弊方法是直接修改UIManager,更改当前外观使用的各种属性。如果您想进行小的调整,这有时会更容易。

无论哪种方式,这都会影响应用程序创建的所有组件,而无需在启动时更改外观即可

【讨论】:

我刚刚阅读了有关 Synth 的 Oracle 教程,它看起来很有前途。在编写简单的 android 应用程序时,我只接触过几次 XML,所以我对它比较陌生。然而,根据我的阅读,这似乎是一种更有效的方式来改变 GUI 的整体外观,而无需为了改变它们的外观而重载 JComponents 去年年底我为我的工作场所做了一个原型,它使用基本外观并构建了 4 种不同的外观和感觉。我不会说这很容易开始,但最终结果非常棒,特别是当您可以仅基于组件 name 属性为单个组件(如 JButton)提供自定义时,因此您可以拥有一个基本按钮外观和一些自定义外观,例如“确定”和“取消”按钮...... 我一直在尝试使用 xml 文件,但我不确定哪些选项可用/如何充分利用 xml 文件。我已经阅读了有关 oracle 的教程,并且正在使用示例 xmls 作为资源,但是您是否碰巧知道任何其他资源可以帮助我快速学习如何开发 Synth xml 文件?我真的很喜欢这种技术将 laf 与代码隔离开来的方式。 是的,它将 laf 与代码隔离开来,这就是重点,把它想象成 css。你可以看看其他一些实现。

以上是关于Java Swing 模块化配色方案的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio 配色方案,如何找出这是哪种配色方案

如何进入幻灯片配色方案 设置蓝色为背景配色方案 应用于所有幻灯片

如何使免疫调试器配色方案看起来像 OllyDbg 配色方案?

vim配色方案设置(更换vim配色方案)

eclipse怎么设置 monokai 配色方案

如何修改sublime text2默认的Monokia配色方案让其更适合PHP