JDK-4795987 : DefaultTableCellRenderer does not honor 'isEnabled'
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0,1.4.0_02,6
  • Priority: P4
  • Status: Closed
  • Resolution: Won't Fix
  • OS: generic,windows_2000
  • CPU: generic,x86
  • Submitted: 2002-12-18
  • Updated: 2019-12-17
  • Resolved: 2019-12-17
Related Reports
Duplicate :  
Relates :  
Description
Name: jk109818			Date: 12/18/2002


FULL PRODUCT VERSION :
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)
AND
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
DefaultTableCellRenderer.getTableCellRendererComponent()
does not honor (i.e. look at) JTable.isEnabled() of the
containing JTable. When the JTable.isEnabled() returns
false, the DefaultTableCellRenderer should return a
Component that renders itself as 'grayed out'.

Attached source code implements a subclass of
DefaultTableCellRenderer that looks at JTable.isEnabled()
and renderers the last column as gray if the table is
disabled. It only works for 'String columns' and is not
very efficient, but it highlights the issue.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Use JTable.setEnabled(false) for any JTable that uses
the DefaultTableCellRenderer to reproduce the problem.
2.
3.

EXPECTED VERSUS ACTUAL BEHAVIOR :
If the JTable is disabled, TableCellRenderers should render
the cells as 'grayed out'.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Container;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.JScrollPane;
import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.DefaultTableCellRenderer;

public class TestJTable extends JTable {
    
    public TestJTable() {
        
        DefaultTableModel testModel = new DefaultTableModel(2, 4) {
            public Class getColumnClass(int columnIndex) {
                switch (columnIndex) {
                    case 0: return Double.class;
                    case 1: return Boolean.class;
                    case 2: return Integer.class;
                    case 3: return String.class;
                }
                return Object.class;
            }
        };
        
        testModel.setValueAt(new Double(0.0), 0, 0);
        testModel.setValueAt(new Double(1.0), 1, 0);
        testModel.setValueAt(Boolean.FALSE, 0, 1);
        testModel.setValueAt(Boolean.TRUE, 1, 1);
        testModel.setValueAt(new Integer(0), 0, 2);
        testModel.setValueAt(new Integer(1), 1, 2);
        testModel.setValueAt("Zero", 0, 3);
        testModel.setValueAt("One", 1, 3);
        
        setModel(testModel);
        
        testModel.setColumnIdentifiers(new String[]{"Column 0", "Column
1", "Column 2", "Column 3"});
        
        // Only install for String to highlight the problem.
        setDefaultRenderer(String.class, new HonorableDefaultTableCellRenderer
());
        
    }
    
    /**
     * Enables or disables the given Container and all of its children.
     *
     * @param aContainer Container of interest. If null, no action is taken.
     * @param isEnabled true if the Container and its children should
     *        be enabled. false if they should be disabled.
     */
    public static void enableAll(Container aContainer, boolean isEnabled) {
        if (aContainer == null) {
            return;
        }

        // Walk into all children.
        Component[] components = aContainer.getComponents();
        for(int i=0; i<components.length; i++) {
            // If it has children, walk down.
            if (components[i] instanceof Container) {
                // Set it and all its children.
                enableAll((Container)components[i], isEnabled);
            }
            else {
                // This child has no children, just set it.
                components[i].setEnabled(isEnabled);
            }
        }
        
        // Any children have been set. Set it.
        aContainer.setEnabled(isEnabled);
    }
    
    public static void main(String[] args) {
                
        TestJTable table = new TestJTable();
        
        JScrollPane scrollPane = new JScrollPane(table);

        // Disable all Components including the JOptionPane. Problem exists
        // where the JOptionPane is enabled or not.
        TestJTable.enableAll(scrollPane, false);
        
        JOptionPane.showConfirmDialog(null, scrollPane, "Where's the grey out",
                                      JOptionPane.DEFAULT_OPTION);
        System.exit(0);
    }
    
    
    public class HonorableDefaultTableCellRenderer extends
DefaultTableCellRenderer {
        
        public Component getTableCellRendererComponent(JTable table, Object
value,
                                                       boolean isSelected,
boolean hasFocus,
                                                       int row, int column) {

            // Let the super class do most of the work.
            super.getTableCellRendererComponent(table, value, isSelected,
hasFocus, row, column);
            // Honor isEnabled. Causes repaint.
            setEnabled(table.isEnabled());
            return this;
        }
        
    }
}

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

CUSTOMER WORKAROUND :
Subclass DefaultTableCellRenderer and override method
getTableCellRendererComponent() as in the sample source
code.

If this technique is used, subclasses for rendering Double,
Integer, etc. must be created. Additionally, the default
Boolean renderer does not extend DefaultTableCellRenderer
so a Boolean renderer must be created. Also note that the
table headers are not rendered as gray since the default
table header renderer is also a DefaultTableCellRenderer.

Other table, tree, list, etc. cell renderers were NOT
reviewed for a similar issue.
(Review ID: 166624) 
======================================================================
Suggested fix by java.net member leouser:


A DESCRIPTION OF THE FIX :
 BUGIDS:
 4841903 JTable.setEnabled(false) does not alter its visual representation
 4795987 DefaultTableCellRenderer does not honor "isEnabled"

These 2 bug reports are talking about the same thing, but from different perspectives.

FILES AFFECTED: javax.swing.plaf.basic.BasicTableUI
JDK VERSION
jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin

Discusion(embeded in test case as well):
/**
 * BUGIDS:
 * 4841903 JTable.setEnabled(false) does not alter its visual representation
 * 4795987 DefaultTableCellRenderer does not honor "isEnabled"
 * The problem is simple, you disable a table and it doesn't look different.
 * Ive added 2 lines of code to BasicTableUI.paintCell that disables the
 * painting component or enables, dependent upon whether the JTable is
 * enabled or disabled.  Ive chosen not to change the DefaultTableCellRenderer
 * because this decision should be made by the tables UI.  If the developer
 * does not want things to look different(odd though it may be), he can
 * implement the 'same no matter what' look as he sees fit.  This change
 * I believe should be considered 'expected' behavior.
 *
 * TESTING STRATEGY:
 * Hit the Enable/Disable button to see the coloring change in the JTable
 * take effect.
 *
 * FILES AFFECTED: javax.swing.plaf.basic.BasicTableUI
 *
 * JDK VERSION
 * jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
 *
 * test ran succesfully on a SUSE 7.3 Linux distribution
 *
 * Brian Harry
 * ###@###.###
 * Jan 24, 2006
 */

UNIFIED DIFF:
--- /home/nstuff/java6/jdk1.6.0/javax/swing/plaf/basic/BasicTableUI.java	Thu Dec 15 02:17:45 2005
+++ /home/javarefs/javax/swing/plaf/basic/BasicTableUI.java	Tue Jan 24 16:35:57 2006
@@ -2041,6 +2041,8 @@
         else {
             TableCellRenderer renderer = table.getCellRenderer(row, column);
             Component component = table.prepareRenderer(renderer, row, column);
+            if(component.isEnabled() != table.isEnabled())
+                component.setEnabled(table.isEnabled());
             rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
                                         cellRect.width, cellRect.height, true);
         }




JUnit TESTCASE :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * BUGIDS:
 * 4841903 JTable.setEnabled(false) does not alter its visual representation
 * 4795987 DefaultTableCellRenderer does not honor "isEnabled"
 * The problem is simple, you disable a table and it doesn't look different.
 * Ive added 2 lines of code to BasicTableUI.paintCell that disables the
 * painting component or enables, dependent upon whether the JTable is
 * enabled or disabled.  Ive chosen not to change the DefaultTableCellRenderer
 * because this decision should be made by the tables UI.  If the developer
 * does not want things to look different(odd though it may be), he can
 * implement the 'same no matter what' look as he sees fit.  This change
 * I believe should be considered 'expected' behavior.
 *
 * TESTING STRATEGY:
 * Hit the Enable/Disable button to see the coloring change in the JTable
 * take effect.
 *
 * FILES AFFECTED: javax.swing.plaf.basic.BasicTableUI
 *
 * JDK VERSION
 * jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
 *
 * test ran succesfully on a SUSE 7.3 Linux distribution
 *
 * Brian Harry
 * ###@###.###
 * Jan 24, 2006
 */
public class JTTest4841903 implements Runnable{



    public void run(){

	JFrame jf = new JFrame();
	Object[][] data = new Object[10][10];
	Object[] names = new Object[10];
	for(int i = 0; i < 10; i++){
	    names[i] = String.valueOf(i);
	    for(int i2 = 0; i2 < 10; i2++)
                data[i][i2] = i2;

        }
	final JTable jt = new JTable(data, names);
        jt.setEnabled(false);
	JScrollPane jsp = new JScrollPane(jt);
	jf.add(jsp);
	Action toggle = new AbstractAction("Enable/Disable"){

		public void actionPerformed(ActionEvent ae){
		    if(jt.isEnabled())jt.setEnabled(false);
                    else jt.setEnabled(true);

                }


	    };
        JButton jb = new JButton(toggle);
        jf.add(jb, BorderLayout.SOUTH);
        jf.pack();
	jf.setVisible(true);


    }




    public static void main(String ... args){

	SwingUtilities.invokeLater(new JTTest4841903());

    }


}


FIX FOR BUG NUMBER:
4841903,4795987

Comments
EVALUATION Contribution-forum:https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?forumID=1463&messageID=11030
25-01-2006

EVALUATION See also 4841903. ###@###.### 2004-09-24
24-09-2004