I am using the Nimbus look and feel.
I have two JCheckBoxes, and by default, the text is black when the JCheckBox is enabled, and greyed out when it is disabled. My new requirement is that the program should ignore the enabled state of the JCheckBox, and instead be greyed out when isSelected() is false, and display the text in a specified colour when isSelected() is true.
I have attempted to do this by:
Calling setUI on the JCheckBoxes in question with an instance of my new UI class
private static class MyCheckBoxUI extends BasicCheckBoxUI
{
private Color selectedColor;
public MyCheckBoxUI( Color selectedColor )
{
this.selectedColor = selectedColor;
}
@Override
protected void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text )
{
ButtonModel model = b.getModel();
FontMetrics fm = SwingUtilities2.getFontMetrics(b, g);
int mnemonicIndex = b.getDisplayedMnemonicIndex();
if( model.isSelected() )
{
/*** paint the text normally */
g.setColor( selectedColor );
SwingUtilities2.drawStringUnderlineCharAt(b, g,text, mnemonicIndex,
textRect.x + getTextShiftOffset(),
textRect.y + fm.getAscent() + getTextShiftOffset());
}
else
{
/*** paint the text disabled ***/
g.setColor(b.getBackground().brighter());
SwingUtilities2.drawStringUnderlineCharAt(b, g,text, mnemonicIndex,
textRect.x, textRect.y + fm.getAscent());
g.setColor(b.getBackground().darker());
SwingUtilities2.drawStringUnderlineCharAt(b, g,text, mnemonicIndex,
textRect.x - 1, textRect.y + fm.getAscent() - 1);
}
}
}
In the constructor of my JPanel, I have the following:
jCheckBox1.setUI( new MyCheckBoxUI( Color.red ) );
jCheckBox2.setUI( new MyCheckBoxUI( Color.black ) );
This appears to work as expected, except there is a side effect. Now, the check box will not render the tick in the box when it is selected like it used to (I did not expect this as I have only overridden the paintText method). What have I missed?
Additionally, the use of SwingUtilities2 disturbs me, as I am warned that it is an internal proprietary API that could be removed in a future release. Is there a better way to do this?
You need to play with the UIManager
color properties...
Object disabledTextForeground = UIManager.get("CheckBox[Disabled].textForeground");
Object enabledTextForeground = UIManager.get("CheckBox.foreground");
UIManager.put("CheckBox[Disabled].textForeground", UIManager.get("CheckBox.foreground"));
UIManager.put("CheckBox[Enabled].textForeground", disabledTextForeground);
UIManager.put("CheckBox[Selected+Enabled].textForeground", enabledTextForeground);
This example will allow you to modify the values at a global level, meaning that every JCheckBox
you create will have the same values
For example...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestNimbus {
public static void main(String[] args) {
new TestNimbus();
}
public TestNimbus() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
Object disabledTextForeground = UIManager.get("CheckBox[Disabled].textForeground");
Object enabledTextForeground = UIManager.get("CheckBox.foreground");
UIManager.put("CheckBox[Disabled].textForeground", UIManager.get("CheckBox.foreground"));
UIManager.put("CheckBox[Enabled].textForeground", disabledTextForeground);
UIManager.put("CheckBox[Selected+Enabled].textForeground", enabledTextForeground);
JCheckBox cb1 = new JCheckBox("Option #1");
JCheckBox cb2 = new JCheckBox("Option #2");
JCheckBox cb3 = new JCheckBox("Option #3");
cb1.setSelected(true);
cb3.setEnabled(false);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
frame.add(cb1, gbc);
frame.add(cb2, gbc);
frame.add(cb3, gbc);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
To affect only given instance of JCheckBox
s, you would need to supply the overrides directly to each instance of the JCheckBox
you want to effect...
The top three have their values overridden, while the bottom three remain unaffected and use the UI default values
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestNimbus {
public static void main(String[] args) {
new TestNimbus();
}
public TestNimbus() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
UIDefaults checkBoxDefaults = new UIDefaults();
Object disabledTextForeground = UIManager.get("CheckBox[Disabled].textForeground");
Object enabledTextForeground = UIManager.get("CheckBox.foreground");
checkBoxDefaults.put("CheckBox[Disabled].textForeground", UIManager.get("CheckBox.foreground"));
checkBoxDefaults.put("CheckBox[Enabled].textForeground", disabledTextForeground);
checkBoxDefaults.put("CheckBox[Selected+Enabled].textForeground", enabledTextForeground);
JCheckBox cb1 = new JCheckBox("Option #1");
JCheckBox cb2 = new JCheckBox("Option #2");
JCheckBox cb3 = new JCheckBox("Option #3");
JCheckBox cb4 = new JCheckBox("Normal #1");
JCheckBox cb5 = new JCheckBox("Normal #2");
JCheckBox cb6 = new JCheckBox("Normal #3");
configure(cb1, checkBoxDefaults);
configure(cb2, checkBoxDefaults);
configure(cb3, checkBoxDefaults);
cb1.setSelected(true);
cb4.setSelected(true);
cb3.setEnabled(false);
cb6.setEnabled(false);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
frame.add(cb1, gbc);
frame.add(cb2, gbc);
frame.add(cb3, gbc);
frame.add(cb4, gbc);
frame.add(cb5, gbc);
frame.add(cb6, gbc);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void configure(JCheckBox checkbox, UIDefaults uiDefaults) {
checkbox.putClientProperty("Nimbus.Overrides", uiDefaults);
// checkbox.putClientProperty("Nimbus.Overrides.InheritDefaults", false);
}
});
}
}