How to show only HSV JColorChooser field?
OK, just for a laugh, I decided to create the desired JPanel from scratch by hooking it into the view as a View-Controller, since the model is trivial here - a color field inside the controller. To use this component, you instantiate the component, add it to your GUI whenever you want, and simply add a PropertyChangeListener to it that listens for its COLOR property:
hsvChooserPanel.addPropertyChangeListener(HsvChooserPanel.COLOR, pce -> {
Color c = (Color) pce.getNewValue();
// do what you want with Color value, c, here
});
Test class:
Version 2: This allows any 3 HSV bar / bar combination combinations, either one with a hue-oriented bar or saturation or value (here Brightness). It uses an enum, ColorProperty, which has 3 values, ColorProperty.HUE, ColorProperty.SATURATION and ColorProperty.BRIGHTNESS, and calculations in the enumeration elements themselves on how to create a color bar and color square BufferedImages. Comments are welcome:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestHsvChooser2 {
// ***** choose which color panel / color bar you'd like to test:
// private static final ColorProperty COLOR_PROP = ColorProperty.HUE;
// private static final ColorProperty COLOR_PROP = ColorProperty.BRIGHTNESS;
private static final ColorProperty COLOR_PROP = ColorProperty.SATURATION;
private static void createAndShowGui() {
HsvChooserPanel2 hsvChooserPanel = new HsvChooserPanel2(COLOR_PROP);
JPanel testPanel = new JPanel();
JPanel outerPanel = new JPanel(new BorderLayout());
outerPanel.add(testPanel);
outerPanel.setBorder(BorderFactory.createTitledBorder("Test Panel"));
hsvChooserPanel.addPropertyChangeListener(HsvChooserPanel2.COLOR, pce -> {
Color c = (Color) pce.getNewValue();
testPanel.setBackground(c);
});
JPanel gridPanel = new JPanel(new GridLayout(0, 1, 10, 10));
gridPanel.add(hsvChooserPanel);
gridPanel.add(outerPanel);
JFrame frame = new JFrame("HSV Chooser");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(gridPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
The whole shebang:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.event.SwingPropertyChangeSupport;
@SuppressWarnings("serial")
public class HsvChooserPanel2 extends JPanel {
public static final String COLOR = "color";
private static final int PREF_W = 180;
private static final int PREF_H = PREF_W;
private static final int PREF_W_CB = 20;
private static final int GAP = 10;
private MyColorPanel2 colorPanel = null;
private MyColorBar2 colorBar = null;
private InnerControl2 innerControl = null;
public HsvChooserPanel2(ColorProperty colorProp) {
colorPanel = new MyColorPanel2(PREF_W, PREF_H, colorProp);
colorBar = new MyColorBar2(PREF_W_CB, PREF_H, colorProp);
innerControl = new InnerControl2(this, colorPanel, colorBar);
colorPanel.setColorPropertyValue(Color.RED); // !! magic value
setLayout(new BorderLayout(GAP, GAP));
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
add(colorPanel, BorderLayout.CENTER);
add(colorBar, BorderLayout.LINE_END);
// propagate COLOR changes in the inner controller
// to this component property change support
innerControl.addPropertyChangeListener(COLOR, pce -> {
firePropertyChange(COLOR, pce.getOldValue(), pce.getNewValue());
});
}
}
// listens for changes to both the color bar and the color panel
class InnerControl2 {
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private HsvChooserPanel2 hsvChooser;
private MyColorPanel2 colorPanel;
private MyColorBar2 colorBar;
private Color color; // This is all there is to the model, a "bound"
// property
public InnerControl2(HsvChooserPanel2 hsvChooser, MyColorPanel2 colorPanel, MyColorBar2 colorBar) {
this.hsvChooser = hsvChooser;
this.colorPanel = colorPanel;
this.colorBar = colorBar;
// listen for changes
colorPanel.addPropertyChangeListener(ColorPanelParent.CURSOR, new ColorPanelListener());
colorBar.addPropertyChangeListener(ColorPanelParent.CURSOR, new ColorBarListener());
}
public Color getColor() {
return color;
}
// classic setter method for a "bound" property
public void setColor(Color color) {
Color oldValue = this.color;
Color newValue = color;
this.color = color;
// notify listeners of the change
pcSupport.firePropertyChange(HsvChooserPanel2.COLOR, oldValue, newValue);
}
// allow outside classes the ability to listen
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(name, listener);
}
public HsvChooserPanel2 getHsvChooser() {
return hsvChooser;
}
// inner listeners
private class ColorPanelListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
Point p = colorPanel.getCursorP();
Color c = colorPanel.getColor(p);
colorBar.setColorPropertyValue(c);
setColor(c); // this will fire the prop change
// support
}
}
private class ColorBarListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// get hue from the color bar and use it to set the main hue
// of the color panel
Point p = colorBar.getCursorP();
Color c = colorBar.getColor(p);
colorPanel.setColorPropertyValue(c);
}
}
}
// parent of both color bar panel and color panel
@SuppressWarnings("serial")
abstract class ColorPanelParent extends JPanel {
public static final String CURSOR = "cursor";
private int prefW;
private int prefH;
private Point cursorP = new Point(0, 0);
private BufferedImage img = null;
private ColorProperty colorProperty;
private boolean panel;
public ColorPanelParent(int prefW, int prefH, ColorProperty colorProperty, boolean panel) {
this.prefW = prefW;
this.prefH = prefH;
this.colorProperty = colorProperty;
this.panel = panel;
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
setBorder(BorderFactory.createLineBorder(Color.BLACK));
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(prefW, prefH);
}
public int getPrefH() {
return prefH;
}
public int getPrefW() {
return prefW;
}
public ColorProperty getColorProperty() {
return colorProperty;
}
public BufferedImage getImg() {
return img;
}
public Point getCursorP() {
return cursorP;
}
public void setImg(BufferedImage img) {
this.img = img;
repaint();
}
public Color getColor(Point p) {
Color c = null;
if (getImg() != null) {
int rgb = getImg().getRGB(p.x, p.y);
c = new Color(rgb);
}
return c;
}
// when the main hue is changed, we have to create a new
// background image to reflect the new main color
public void setColorPropertyValue(Color color) {
int w = getPrefW();
int h = getPrefH();
BufferedImage img = getColorProperty().createImage(color, w, h, panel);
setImg(img);
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
// change the cursor point and then
// notify prop change support of changes
private class MyMouse extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
mouseResponse(e);
}
@Override
public void mouseDragged(MouseEvent e) {
mouseResponse(e);
}
private void mouseResponse(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (!contains(e.getPoint())) {
x = Math.max(0, x);
x = Math.min(prefW - 1, x);
y = Math.max(0, y);
y = Math.min(prefH - 1, y);
}
Point oldValue = cursorP;
cursorP = new Point(x, y);
firePropertyChange(CURSOR, oldValue, cursorP);
repaint();
}
}
}
// color bar on the right side of the HsvChooser JPanel.
// Controller action: Changing selection point on this JPanel
// will change the hue of the color panel
@SuppressWarnings("serial")
class MyColorBar2 extends ColorPanelParent {
public MyColorBar2(int prefW, int prefH, ColorProperty colorProperty) {
super(prefW, prefH, colorProperty, false);
// create and set the background image
setColorPropertyValue(Color.RED); // fix the magic number?
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // draws the background image
// this draws a line at the cursor location
g.setXORMode(Color.WHITE);
int y = getCursorP().y;
g.drawLine(0, y, getPrefW(), y);
}
}
// color panel on the left side of the HsvChooser JPanel.
// Controller action: Changing selection point on this JPanel
// will notify listeners of a new COLOR selection
@SuppressWarnings("serial")
class MyColorPanel2 extends ColorPanelParent {
private static final int CURSOR_RADIUS = 8;
public MyColorPanel2(int prefW, int prefH, ColorProperty colorProperty) {
super(prefW, prefH, colorProperty, true);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // draws the background image
// draws the cross hatch indicating color selection point
g.setXORMode(Color.WHITE);
int x = getCursorP().x;
int y = getCursorP().y;
int x1 = x - CURSOR_RADIUS;
int y1 = y - CURSOR_RADIUS;
int x2 = x + CURSOR_RADIUS;
int y2 = y + CURSOR_RADIUS;
g.drawLine(x1, y, x2, y);
g.drawLine(x, y1, x, y2);
}
}
enum ColorProperty {
HUE {
@Override
public BufferedImage createImage(Color color, int w, int h, boolean panel) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
if (panel) {
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
// float array is HSB
float hue = Color.RGBtoHSB(red, green, blue, null)[0];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float s = ((float) j) / (float) w;
float b = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, s, b).getRGB();
img.setRGB(j, i, rgb);
}
}
} else {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float hue = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, 1f, 1f).getRGB();
img.setRGB(j, i, rgb);
}
}
}
return img;
}
},
SATURATION {
@Override
public BufferedImage createImage(Color color, int w, int h, boolean panel) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
// float array is HSB
float[] hsb = Color.RGBtoHSB(red, green, blue, null);
return panel ? createPanelImg(w, h, img, hsb) : createBarImg(w, h, img, hsb);
}
private BufferedImage createBarImg(int w, int h, BufferedImage img, float[] hsb) {
float hue = hsb[0];
// float brightness = hsb[2];
float brightness = 1f;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float saturation = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, saturation, brightness).getRGB();
img.setRGB(j, i, rgb);
}
}
return img;
}
private BufferedImage createPanelImg(int w, int h, BufferedImage img, float[] hsb) {
float saturation = hsb[1];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float hue = ((float) j) / (float) w;
float b = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, saturation, b).getRGB();
img.setRGB(j, i, rgb);
}
}
return img;
}
},
BRIGHTNESS {
@Override
public BufferedImage createImage(Color color, int w, int h, boolean panel) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
// float array is HSB
float[] hsb = Color.RGBtoHSB(red, green, blue, null);
return panel ? createPanelImg(w, h, img, hsb) : createBarImg(w, h, img, hsb);
}
private BufferedImage createBarImg(int w, int h, BufferedImage img, float[] hsb) {
float hue = hsb[0];
// float saturation = hsb[1];
float saturation = 1f;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float brightness = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, saturation, brightness).getRGB();
img.setRGB(j, i, rgb);
}
}
return img;
}
private BufferedImage createPanelImg(int w, int h, BufferedImage img, float[] hsb) {
float brightness = hsb[2];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float hue = ((float) j) / (float) w;
float saturation = (h - (float) i) / (float) h;
int rgb = Color.getHSBColor(hue, saturation, brightness).getRGB();
img.setRGB(j, i, rgb);
}
}
return img;
}
};
public abstract BufferedImage createImage(Color color, int w, int h, boolean panel);
}
source to share
A look at the javax.swing.colorchooser
internals shows that it ColorChooserComponentFactory
subclasses AbstractColorChooserPanel
using ColorChooserPanel
and the appropriate subclass ColorModel
. ColorChooserPanel
contains the parts you want as two instances DiagramComponent
: the left name is called diagram
and the right one is slider
called.
Instead of removing components from an existing one, ColorChooserPanel
consider creating a custom picker that contains only the items you want .
class MyChooserPanel extends AbstractColorChooserPanel implements PropertyChangeListener {
private final ColorModel model;
private final DiagramComponent diagram;
private final DiagramComponent slider;
MyChooserPanel(ColorModel model) {
this.model = model;
this.diagram = new DiagramComponent(this.panel, true);
this.slider = new DiagramComponent(this.panel, false);
}
…
}
Naturally, you will have to repeat some of the (package-) private code, but the result will be less brittle.
source to share
My decision:
colorChooser.setPreviewPanel(new JPanel());
AbstractColorChooserPanel[] panels = colorChooser.getChooserPanels();
for (AbstractColorChooserPanel accp : panels) {
if(!accp.getDisplayName().equals("HSV")) {
colorChooser.removeChooserPanel(accp);
}
}
JComponent current = (JComponent) colorChooser.getComponents()[0];
while( !current.getClass().toString().equals( "class javax.swing.colorchooser.ColorChooserPanel" ) ){
current = (JComponent) current.getComponents()[0];
}
for(Component jc : current.getComponents()){
if(!jc.getClass().toString().equals( "class javax.swing.colorchooser.DiagramComponent" )){
current.remove(jc);
}
}
This removes everything I don't want, but I think creating a custom one would be the best solution.
I'm going to try trashgod to see if it works better.
source to share
You can use the Swing Utils class to find components of a given type in a panel.
In the example below, you can find all the sliders and then make them invisible:
import java.awt.*;
import java.util.List;
import javax.swing.*;
import javax.swing.colorchooser.*;
public class ColorChooserPanel extends JPanel
{
ColorChooserPanel()
{
JColorChooser chooser = new JColorChooser();
AbstractColorChooserPanel[] panels = chooser.getChooserPanels();
for (AbstractColorChooserPanel panel: panels)
{
if ("HSL".equals(panel.getDisplayName()))
{
add( panel );
List<JSlider> sliders = SwingUtils.getDescendantsOfType(JSlider.class, panel, true);
for (JSlider slider: sliders)
{
slider.setVisible( false );
}
}
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("ColorChooserPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ColorChooserPanel());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
source to share