Java JColorChooser:在“样例”面板中保存/恢复最近的颜色

Java JColorChooser:在“样例”面板中保存/恢复最近的颜色,java,swing,mouselistener,jcolorchooser,Java,Swing,Mouselistener,Jcolorchooser,我在应用程序的不同位置使用JColorchooser。可以有多个面板实例调用JColorChooser。 选择器中的“样例”面板有一个“最近”颜色的区域,该区域仅存在于JColorChooser的每个实例中。我希望(a)在我的应用程序中的所有选择器中具有相同的“最近”颜色,(b)将颜色保存到磁盘中,以便这些颜色在关闭和重新启动应用程序后仍然有效。 (至少(a)可以通过在整个应用程序中使用相同的单一选择器实例来解决,但这会很麻烦,因为我需要非常小心连接的ChangeListener,并在各种对话框

我在应用程序的不同位置使用JColorchooser。可以有多个面板实例调用JColorChooser。
选择器中的“样例”面板有一个“最近”颜色的区域,该区域仅存在于JColorChooser的每个实例中。我希望(a)在我的应用程序中的所有选择器中具有相同的“最近”颜色,(b)将颜色保存到磁盘中,以便这些颜色在关闭和重新启动应用程序后仍然有效。
(至少(a)可以通过在整个应用程序中使用相同的单一选择器实例来解决,但这会很麻烦,因为我需要非常小心连接的ChangeListener,并在各种对话框中添加/删除选择器面板。)

我没有找到任何方法可以让我在选择器面板中设置(恢复)这些“最近”的颜色。因此,在我看来,实现这一目标的唯一途径是:

  • 序列化并保存/恢复整个选择器(选择器面板?) 或
  • 从头开始创建我自己的选择器面板
这是对的,还是我遗漏了什么


顺便说一句:我也想在选择器中检测到双击,但似乎很难找到合适的位置来连接我的鼠标侦听器。要做到这一点,我真的需要深入研究选择器面板的内部结构吗?(不,检测对同一颜色的第二次单击不起作用,因为更改侦听器仅在单击不同颜色时才会启动。)

正如您所注意到的,在DefaultSwatchChooserPanel中没有公共api来访问最近的颜色,即使该面板本身也无法访问

因为您需要一些逻辑/bean来保存和重置最近的颜色(加上扩展的鼠标交互),所以滚动您自己的是一种方式。要获得一些指导,请看一下样例面板的实现(咳嗽…c&p你需要什么,修改你不需要的)。基本上,类似于

// a bean that keeps track of the colors
public static class ColorTracker extends AbstractBean {

    private List<Color> colors = new ArrayList<>();

    public void addColor(Color color) {
        List<Color> old = getColors();
        colors.add(0, color);
        firePropertyChange("colors", old, getColors());
    }

    public void setColors(List<Color> colors) {
        List<Color> old = getColors();
        this.colors = new ArrayList<>(colors);
        firePropertyChange("colors", old, getColors());
    }

    public List<Color> getColors() {
        return new ArrayList<>(colors);
    }
}

// a custom SwatchChooserPanel which takes and listens to the tracker changes
public class MySwatchChooserPanel ... {

   ColorTracker tracker;

   public void setColorTracker(....) {
       // uninstall old tracker 
       ....
       // install new tracker
       this.tracker = tracker;
       if (tracker != null) 
           tracker.addPropertyChangeListener(.... );
       updateRecentSwatchPanel()
   }

   /** 
    * A method updating the recent colors in the swatchPanel
    * This is called whenever necessary, specifically after building the panel,
    * on changes of the tracker, from the mouseListener
    */
   protected void updateRecentSwatchPanel() {
       if (recentSwatchPanel == null) return;
       recentSwatchPanel.setMostRecentColors(tracker != null ? tracker.getColors() : null);
   }

// the mouseListener which updates the tracker and triggers the doubleClickAction
// if available
class MainSwatchListener extends MouseAdapter implements Serializable {
    @Override
    public void mousePressed(MouseEvent e) {
        if (!isEnabled())
            return;
        if (e.getClickCount() == 2) {
            handleDoubleClick(e);
            return;
        }

        Color color = swatchPanel.getColorForLocation(e.getX(), e.getY());
        setSelectedColor(color);
        if (tracker != null) {
            tracker.addColor(color);
        } else {
            recentSwatchPanel.setMostRecentColor(color);
        }
    }

    /**
     * @param e
     */
    private void handleDoubleClick(MouseEvent e) {
        if (action != null) {
            action.actionPerformed(null);
        }
    }
}


} 

// client code can install the custom panel on a JFileChooser, passing in a tracker
private JColorChooser createChooser(ColorTracker tracker) {
    JColorChooser chooser = new JColorChooser();
    List<AbstractColorChooserPanel> choosers = 
            new ArrayList<>(Arrays.asList(chooser.getChooserPanels()));
    choosers.remove(0);
    MySwatchChooserPanel swatch = new MySwatchChooserPanel();
    swatch.setColorTracker(tracker);
    swatch.setAction(doubleClickAction);
    choosers.add(0, swatch);
    chooser.setChooserPanels(choosers.toArray(new AbstractColorChooserPanel[0]));
    return chooser;
}
//跟踪颜色的bean
公共静态类ColorTracker扩展了AbstractBean{
私有列表颜色=新的ArrayList();
公共空白添加颜色(颜色){
List old=getColors();
颜色。添加(0,颜色);
firePropertyChange(“colors”,old,getColors());
}
公共无效设置颜色(列表颜色){
List old=getColors();
this.colors=新阵列列表(colors);
firePropertyChange(“colors”,old,getColors());
}
公共列表getColors(){
返回新的ArrayList(颜色);
}
}
//一个自定义样例选择器面板,用于获取和侦听跟踪器更改
公共类MyWatchChooserPanel。。。{
彩色跟踪器;
公共void setColorTracker(..){
//卸载旧跟踪器
....
//安装新的跟踪器
this.tracker=跟踪器;
如果(跟踪器!=null)
tracker.addPropertyChangeListener(..);
updateRecentSwatchPanel()
}
/** 
*更新样例面板中最近颜色的方法
*必要时,特别是在构建配电盘之后,会调用此命令,
*在更改跟踪程序时,从mouseListener
*/
受保护的void updateRecentSwatchPanel(){
if(recentSwatchPanel==null)返回;
recentSwatchPanel.setMostRecentColors(tracker!=null?tracker.getColors():null);
}
//更新跟踪器并触发双击操作的鼠标侦听器
//如果有的话
类MainSwatchListener扩展MouseAdapter实现可序列化{
@凌驾
公共无效鼠标按下(MouseEvent e){
如果(!isEnabled())
返回;
如果(如getClickCount()==2){
手动双击(e);
返回;
}
Color Color=swatchPanel.getColorForLocation(e.getX(),e.getY());
设置所选颜色(颜色);
如果(跟踪器!=null){
tracker.addColor(颜色);
}否则{
recentSwatchPanel.setMostRecentColor(颜色);
}
}
/**
*@param e
*/
私有void handleDoubleClick(MouseEvent e){
如果(操作!=null){
action.actionPerformed(空);
}
}
}
} 
//客户端代码可以在JFileChooser上安装自定义面板,并传递一个跟踪器
专用JColorChooser createChooser(颜色跟踪器){
JColorChooser chooser=新的JColorChooser();
列表选择器=
新的ArrayList(Arrays.asList(chooser.getChooserPanels());
选择器。删除(0);
MySwatchChooserPanel样例=新建MySwatchChooserPanel();
样本设置颜色跟踪器(跟踪器);
样例设置动作(双击动作);
添加(0,样例);
chooser.setChooserPanel(chooser.toArray(新的AbstractColorChooserPanel[0]);
返回选择器;
}

至于双击处理:增强swatchChooser以执行操作,并根据需要从mouseListener调用该操作

您可以使用
JColorChooser.createDialog
方法-其中一个参数是
JColorChooser
。使用
JColorChooser
的静态实例,并使其成为
对话框模式
——这样,一次只显示一个颜色选择器


createDialog
方法还将
ActionListeners
作为确定和取消按钮的参数。因此,不必真正管理听众。当然,这不会在整个应用程序调用中保留最近的颜色,只会在当前应用程序中保留最近的颜色。

这里有一个使用反射的解决方法-只要底层实现不发生更改,它就会起作用。假设您有一个JColorChooser,将您最近的颜色添加到其中,如下所示:

    final JColorChooser chooser = new JColorChooser(Color.white);

    for (AbstractColorChooserPanel p : chooser.getChooserPanels()) {

        if (p.getClass().getSimpleName().equals("DefaultSwatchChooserPanel")) {

            Field recentPanelField = p.getClass().getDeclaredField("recentSwatchPanel");
            recentPanelField.setAccessible(true);

            Object recentPanel = recentPanelField.get(p);

            Method recentColorMethod = recentPanel.getClass().getMethod("setMostRecentColor", Color.class);
            recentColorMethod.setAccessible(true);

            recentColorMethod.invoke(recentPanel, Color.BLACK);
            recentColorMethod.invoke(recentPanel, Color.RED);

            //add more colors as desired

            break;
        }

    }