如何在我的自定义 JComponent 中监听默认颜色变化?

Posted

技术标签:

【中文标题】如何在我的自定义 JComponent 中监听默认颜色变化?【英文标题】:How to listen default color change inside my custom JComponent? 【发布时间】:2022-01-08 05:53:59 【问题描述】:

我是一些JComponent 扩展的作者。我写了一些示例组件。

在一个示例组件中,我只是用预定义的子组件填充它们:

public class JSwingExample02 extends JComponent 

    public JSwingExample02() 
        populate();
    

    private void populate() 
        setLayout(new BorderLayout());
        JLabel jLabel = new JLabel("Hello World!");
        add(jLabel, BorderLayout.CENTER);
    

在其他组件中,我从头开始绘制它们

@Override protected void paintComponent(Graphics g) 
    Graphics2D g2 = (Graphics2D)g;

    g2.fillOval(10, 10, 100, 100);

现在我的组件是通过第三方代码(IDEA 插件)使用的,它为其应用了颜色主题:尽管我没有任何颜色代码行,但我的组件显示为“深色主题”。

例如

即文字是白色的。

我如何聆听这些颜色,即事先知道它们,例如,如果我想用它们明确地绘制一些东西?

【问题讨论】:

实现一个自定义监听器并让这些组件注册监听器。覆盖相关方法(例如setBackground(Color bg))来触发这些监听器。 听什么? 对不起。我不明白你的问题。你的意思是应该听哪些方法? 尝试通过UIManager.getLookAndFeel();获取自定义组件的LAF你也可以通过UIManager.addPropertyChangeListener监听LAF的变化 UIManager中监听哪个属性? 【参考方案1】:

有不同的方法来获取和设置颜色。这里有几个。这将创建一个简单的框架/面板组合来显示背景颜色。您还可以在paintComponent 方法中设置颜色。根据您的绘画内容,它将是前景或背景。

JColorChooser 是一种让用户选择颜色的好方法。它可以接受默认颜色并返回选择的任何颜色。

如果你真的想知道颜色何时发生变化,你需要为组件建立一个监听器并监听属性变化。该示例显示了demo 面板侦听前景和背景颜色的变化。您的每个组件都必须注册一个属性监听器来处理事件。

注意: Demo 类实际上是在监听它自己的变化。不必如此。任何实现PropertyChangeListener 接口的类都可以侦听来自任何其他触发属性更改的类的属性更改事件。只需确保在注册事件时使用特定的类实例即可。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class ColorDemo extends JPanel implements PropertyChangeListener
    
    public static void main(String[] args) 
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ColorDemo demo = new ColorDemo();           
        demo.setPreferredSize(new Dimension(200,200));

        // listen for these properties
        demo.addPropertyChangeListener("background", demo );
        demo.addPropertyChangeListener("foreground", demo );
        
        frame.add(demo);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        
        
        demo.setBackground(Color.CYAN);
        System.out.println(
                "back ground color is : " + demo.getBackground());
        demo.setVisible(true);
        // use color chooser
        Color newColor = JColorChooser.showDialog(null,
                "Color Chooser", demo.getBackground());
        System.out.println(
                "Retrieved new color from chooser " + newColor);
        System.out.println(
                "default foreground color is :" + demo.getForeground());
        
        demo.setForeground(Color.RED);
        demo.repaint();
    
        
    public void paintComponent(Graphics g) 
            super.paintComponent(g);
            System.out.println(
                    "Graphics context color : " + g.getColor());
        
    
    public void propertyChange(PropertyChangeEvent pce) 
        String name = pce.getPropertyName();
        System.out.println(name + " change caught");
        System.out.println("old " + name + " was " + pce.getOldValue());
        System.out.println("new " + name + " is " + pce.getNewValue());
        System.out.println();
    

【讨论】:

是的,但是我监听了背景和前景属性——从不调用监听器。 你从来没有在你的问题中这么说。但是,如果您是 JComponent 的子类,那么如果您注册了它们,您应该会收到属性更改。如果您用 JComponent 替换 JPanel,我的示例仍然有效。我建议您提供minimal reproducible example。 你看我的例子,看看你是否做了同样的事情?此外,如果您的组件完全是从头开始构建的(即没有 AWT 类的 API 子类化),那么您也需要在每个想要监听的属性中触发自己的事件。 您的示例有效,因为您扩展了JPanel。这是JPanel 的一个属性,它反映了背景设置。我已经扩展了JComponent,它仍然有效。不是我在设置颜色,是调用者做的。不知何故,它出现在Graphics 和其他道具中。 问题是:设置组件颜色/主题的标准方法是什么,组件作者应该依赖。我不能要求第三方致电setBackground,我需要适应第三方所做的事情。【参考方案2】:

尝试设置 LAF 并监听 LAF 变化:

class JSwingExample02 extends JComponent  

    public JSwingExample02(PropertyChangeListener listener) 
        //set LAF
        try 
            UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
         catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException ex) 
            ex.printStackTrace();
        
        //listen to LAF changes
        UIManager.addPropertyChangeListener(listener);
        populate();
    

    private void populate() 
        setLayout(new BorderLayout());
        JLabel jLabel = new JLabel("Hello World!");
        add(jLabel, BorderLayout.CENTER);
    

    //returns active LAF
    public LookAndFeel lookAndFeel()
        return UIManager.getLookAndFeel();
    

“lookAndFeel”属性更改会在 LAF 更改时触发。 有关其他属性的列表,请参阅 this Q&A。

【讨论】:

以上是关于如何在我的自定义 JComponent 中监听默认颜色变化?的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的自定义主题中包含自定义 js 文件?

UIBarButtonItem 的默认后退按钮背景图像出现在我的自定义

在我的自定义列表视图中添加一个复选框(一次只能选中一个)

如何将视觉添加到 JComponent

如何扩展 JComponent 并使用它来编写自定义游戏板?

如何在我的自定义类型中包含非命名模块 TS 定义