i am trying to make a colored dropdown list with colored items (please see code below). The color is getting applied after the combobox loses focus.
is this correct
please split Editor and Renderer, and add to DefaultListCellRenderer these two methods
cellHasFocus
isSelected
example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.event.EventListenerList;
class ColorComboBoxEditor1 implements ComboBoxEditor {
final protected JLabel editor;
//final protected JButton editor;
private EventListenerList listenerList = new EventListenerList();
ColorComboBoxEditor1(Color initialColor) {
editor = new JLabel("");
/*editor = new JButton("");
editor.setBackground(initialColor);
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Color currentBackground = editor.getBackground();
Color color = JColorChooser.showDialog(editor, "Color Chooser", currentBackground);
if ((color != null) && (currentBackground != color)) {
//editor.setBackground(color);
editor.setForeground(color);
fireActionEvent(color);
}
}
};
editor.addActionListener(actionListener);*/
}
@Override
public void addActionListener(ActionListener l) {
listenerList.add(ActionListener.class, l);
}
@Override
public Component getEditorComponent() {
return editor;
}
@Override
public Object getItem() {
return editor.getBackground();
}
@Override
public void removeActionListener(ActionListener l) {
listenerList.remove(ActionListener.class, l);
}
@Override
public void selectAll() {
}
@Override
public void setItem(Object newValue) {
if (newValue instanceof Color) {
Color color = (Color) newValue;
//editor.setBackground(color);
editor.setForeground(color);
editor.setText(String.valueOf(newValue));
} else {
try {
Color color = Color.decode(newValue.toString());
//editor.setBackground(color);
editor.setForeground(color);
editor.setText(String.valueOf(newValue));
} catch (NumberFormatException e) {
}
}
}
protected void fireActionEvent(Color color) {
Object listeners[] = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ActionListener.class) {
ActionEvent actionEvent = new ActionEvent(editor, ActionEvent.ACTION_PERFORMED, color.toString());
((ActionListener) listeners[i + 1]).actionPerformed(actionEvent);
}
}
}
}
class ColorCellRenderer1 implements ListCellRenderer {
private DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
// Width doesn't matter as the combo box will size
private final static Dimension preferredSize = new Dimension(0, 20);
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel renderer = (JLabel) defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof Color) {
//renderer.setBackground((Color) value);
renderer.setBackground(Color.white);
renderer.setForeground((Color) value);
}
if (cellHasFocus || isSelected) {
renderer.setBorder(new LineBorder(Color.DARK_GRAY));
} else {
renderer.setBorder(null);
}
renderer.setPreferredSize(preferredSize);
return renderer;
}
}
class ColorComboBoxEditorRendererDemo1 {
public ColorComboBoxEditorRendererDemo1() {
Color colors[] = {Color.BLACK, Color.BLUE, Color.GREEN, Color.RED, Color.WHITE, Color.YELLOW};
JFrame frame = new JFrame("Color JComboBox");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JComboBox comboBox = new JComboBox(colors);
comboBox.setEditable(true);
comboBox.setRenderer(new ColorCellRenderer1());
Color color = (Color) comboBox.getSelectedItem();
ComboBoxEditor editor = new ColorComboBoxEditor1(color);
comboBox.setEditor(editor);
frame.add(comboBox, BorderLayout.NORTH);
final JLabel label = new JLabel();
label.setOpaque(true);
label.setBackground((Color) comboBox.getSelectedItem());
frame.add(label, BorderLayout.CENTER);
ActionListener actionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
Color selectedColor = (Color) comboBox.getSelectedItem();
label.setBackground(selectedColor);
}
};
comboBox.addActionListener(actionListener);
frame.setSize(300, 200);
frame.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
ColorComboBoxEditorRendererDemo1 cCBERD1 = new ColorComboBoxEditorRendererDemo1();
}
});
}
}
The foreground text colors in your example seem to work correctly. Certain other colors are managed by the component's UI delegate for a given Look & Feel, as shown below. Note that the delegate may choose to apply a color in a way that preserves contrast in various states, e.g selected, enabled, etc. You can learn more in the article UIManager Defaults.
public static void main(String[] args) {
UIManager.put("ComboBox.background", new ColorUIResource(Color.lightGray));
UIManager.put("ComboBox.selectionBackground", new ColorUIResource(Color.magenta));
UIManager.put("ComboBox.selectionForeground", new ColorUIResource(Color.yellow));
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@SuppressWarnings("synthetic-access")
public void run() {
createAndShowGUI();
}
});
}
Here is another approach:
//JList#setSelectionForeground(...) version
static class ColoredCellRenderer implements ListCellRenderer {
protected DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
private final Color selectionBackground = new Color(240,200,200);
public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Color fgc = Colors.valueOf((String)value).color;
if(index<0) {
//comboBox.setForeground(fgc); //Windows, CDE/Motif Look & Feel
list.setSelectionForeground(fgc);
list.setSelectionBackground(selectionBackground);
}
JLabel renderer = (JLabel) defaultRenderer.getListCellRendererComponent(
list, value, index, isSelected, cellHasFocus);
if (index != -1) {
renderer.setForeground(fgc);
}
return renderer;
}
}
//html version
static class ComboHtmlRenderer extends DefaultListCellRenderer {
private final Color selectionBackground = new Color(240,200,200);
@Override public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean hasFocus) {
Color fgc = Colors.valueOf((String)value).color;
if(index<0) {
list.setSelectionBackground(selectionBackground);
}
JLabel l = (JLabel)super.getListCellRendererComponent(
list, value, index, isSelected, hasFocus);
l.setText("<html><font color="+hex(fgc)+">"+value);
l.setBackground(isSelected?selectionBackground:list.getBackground());
return l;
}
private static String hex(Color c) {
return String.format("#%06x", c.getRGB()&0xffffff);
}
}