【问题标题】:JColorChooser: Save/restore recent colors in Swatches panelJColorChooser:在色板面板中保存/恢复最近的颜色
【发布时间】:2012-06-03 08:49:39
【问题描述】:
我在应用程序的不同位置使用 JColorchooser。可以有多个可以调用 JColorChooser 的面板实例。
选择器中的“色板”面板有一个“最近”颜色区域,该区域仅在 JColorChooser 的每个实例中持续存在。我想 (a) 在我的应用程序中的所有选择器中使用相同的“最近”颜色,并且 (b) 将颜色保存到磁盘 以便这些颜色在关闭并重新启动应用程序后幸存下来。
(至少(a)可以通过在整个应用程序中使用相同的单个选择器实例来解决,但这看起来很麻烦,因为我需要非常小心附加的更改监听器,以及在各种对话框中添加/删除选择器面板.)
我没有找到任何方法可以让我在选择器面板中设置(恢复)这些“最近的”颜色。所以在我看来,实现这一目标的唯一方法是:
- 序列化并保存/恢复整个选择器(选择器面板?)
或
- 从头开始创建我自己的选择器面板
这是正确的,还是我遗漏了什么?
顺便说一句:我还想检测选择器中的双击,但似乎很难找到将鼠标侦听器附加到的正确位置。我真的需要深入研究选择器面板的内部结构来做到这一点吗? (不,检测第二次单击相同颜色时不起作用,因为更改侦听器仅在单击不同颜色时才会触发。)
【问题讨论】:
标签:
java
swing
mouselistener
jcolorchooser
【解决方案1】:
正如您所注意到的,在 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;
}
至于 doubleClick 处理:增强 swatchChooser 以执行操作并根据需要从 mouseListener 调用该操作。
【解决方案2】:
您可以使用JColorChooser.createDialog 方法 - 其中一个参数是JColorChooser。使用JColorChooser 的静态实例并将其设为Dialog modal - 这样,一次只显示一个颜色选择器。
createDialog 方法还将ActionListeners 作为确定和取消按钮的参数。因此,实际上不必管理侦听器。当然,这不会在应用程序的调用中保留最近的颜色,只是在当前应用程序中保留最近的颜色。
【解决方案3】:
这是一种使用反射的解决方法 - 只要底层实现不变,它就会起作用。假设你有一个 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;
}
}