Tuesday, July 1, 2008

JTextArea setEnabled strangeness (Java Swing)

NetBeans 6.1 automatically wraps a JScrollPane around a JTextArea, and handles all the details of setting it up nicely. But, if you need to work with all your components at once (i.e. to tick the "setEnabled" property on each), you'll find the following code works on everything but the JTextAreas (and probably all other nested components):
for(Component component : ProjectPanel.getComponents()) {
component.setEnabled(false);
}
I haven't found a good way around this yet, as the following addition to the loop fails as well:
//use reflection to get the class type
if(component.getClass().equals(JScrollPane.class)) {
JScrollPane scrollPane = (JScrollPane)component;

for(Component subComponent : scrollPane.getComponents()) {
subComponent.setEnabled(false);
}
}
Debugging reveals that the the JTextArea isn't seen as a component here (things like the scroll bar and viewport are, though). getComponents() doesn't loop over children, so maybe this does work two or three levels deeper, but that's getting a bit ridiculous.

Until I figure out a better way, I'm setting the values explicitly using the following method:
textArea.setEnabled(false);
textArea.setBackground(UIManager.getColor("TextArea.disabledBackground"));
The "setBackground" method is needed here (at least on Windows XP using the "Classic" theme), as the background isn't automatically set to the disabled color when setEnabled is set to "true". Most other components automatically handle this for you. This also means when you re-enable it, you need to set it back to the default enabled color:
textArea.setBackground(UIManager.getColor("TextArea.background"));
BTW, I found a good article on using UIManager here that explains how to use and manipulate UI settings.

In any case, I found an official Java bug report from 1998 concerning what appears to be the exact enabled/disabled problem I ran into - the bug's status is "6-Fix Understood, request for enhancement". Though the suggested fix actually didn't work for me...

1 comment:

predii said...

You could just traverse through the whole tree of a Container with a recursive method. That way the JTextArea (or any other component) can be embedded in a Container at arbitrary depth.
An example that gets you all the components of a Container into a List you provide:


public void getAllComponents(Container c, List l) {
if (c.getComponentCount() == 0) return;
Component[] components = c.getComponents();
for (int i = 0; i < components.length; i++) {
Container element = (Container)components[i];
getAllComponents(element, l);
l.add(element);
}
}


p.s.: can't use blockquote tags? o_O