JDK-6574390 : Disabled Windows XP buttons with foreground color set rendered incorrectly
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2007-06-27
  • Updated: 2011-04-28
Description
FULL PRODUCT VERSION :
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Run using Windows XP (not Classic) look and feel

A DESCRIPTION OF THE PROBLEM :
In Java 1.6 (versions 1.6.0 and 1.6.0_01), disabled buttons whose foreground color has been set are rendered using that foreground color rather than the gray disabled color when using the XP L&F.  In other words, with

JButton b = new JButton("foo");
b.setForeground(Color.BLUE);
b.setEnabled(false);

the JButton will be rendered with blue as the text color rather than appearing disabled. This is unexpected and is a regression from Java 1.5. The problem appears to be in WindowsGraphicsUtils in the paintXPText method, where the codepath to render the text as disabled is only entered if the textColor is an instance of UIResource; otherwise the textColor is used directly.

I suspect this is fallout from 6463915, but I could be wrong.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached program on Windows using the XP Look and Feel. Note the first four buttons have blue text. Press the "Enable/Disable" button to toggle the enabled state of those four buttons.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expected that the buttons are rendered with gray text when disabled (as consistent with Java's behavior under Windows Classic and consistent with Windows' native rendering when a foreground color is set on a disabled button).
ACTUAL -
Buttons' text remains painted blue.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ButtonTest
{
    public static void main(final String[] args)
        throws Exception
    {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        JPanel panel = new JPanel(new FlowLayout());
        
        final AbstractButton t = new JToggleButton("Toggle");
        final AbstractButton b = new JButton("Button");
        final AbstractButton c = new JCheckBox("Check");
        final AbstractButton r = new JButton("Radio");

		t.setForeground(Color.BLUE);
		b.setForeground(Color.BLUE);
		c.setForeground(Color.BLUE);
		r.setForeground(Color.BLUE);

        panel.add(t);
        panel.add(b);
        panel.add(c);
        panel.add(r);
        
        panel.add(new JButton(new AbstractAction("Enable/Disable") {
			public void actionPerformed(ActionEvent event) {
				t.setEnabled(!t.isEnabled());
				b.setEnabled(!b.isEnabled());
				c.setEnabled(!c.isEnabled());
				r.setEnabled(!r.isEnabled());
			}
		}));
		
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Override the setForeground method of each of JButton, JToggleButton, JRadioButton and JCheckBox to be:

  setForeground(new ColorUIResource(color));

this causes the WindowsGraphicsUtils.paintXPText codepath to enter the section that handles painting enabled/disabled correctly.