Posted by Rob Camick on August 2, 2009
A previous entry discussed a DisabledGlassPane which allows you to disable key and mouse events for an entire frame. There may be times when you need to disable key and mouse events for a given Container only. Unfortunately you can’t just invoke setEnabled(false) on the container to disable the contained components. So we need another approach.
When disabling a container the following features should be present. Each component on the container should:
- be painted differently so it looks disabled
- not be able to recieve focus
- not respond to mouse events
- not respond to key events
I can think of two different approaches that should satisfy the above requirements.
The easiest approach would be to use recursion to iterate through all the components of a container and individually disable each component. This approach can be applied to any container at run time and is easy to implement. Its main drawback is that not every component is painted differently when disabled. A JTable would be an example of this.
A more involved approach would be to use a “glass pane” to paint over top of all the components so they look like they are disabled. Of course with this approach the components are not actually disabled, so code needs to be added to simulate the disabled behaviour. The disadvantage to this approach is that a special component needs to be created to support a glass pane at a container level and therefore a design time decision must be made as to which container may need this support.
The DisabledPanel class provides solutions for both of the above approaches.
The first approach of disabling individual components is handled by using two static methods:
- DisabledPanel.disable(…) – will iterate through each component on the container and disable it. Each component that is disabled will be remembered so that is can later be enabled.
- DisabledPanel.enable(…) – will enable only those components on the container that where disabled by invoking the disable method.
For the glass pane approach, the DisabledPanel is used as a wrapper panel. The container you want to disable is used to create an instance of a DisabledPanel which in turn is added to the frame. The DisabledPanel uses the OverlapLayout, presented in the last blog entry, to layout the container and its glass pane. When the panel is disabled, the glass pane is made visible. Behind the scenes focus traversal, mouse events and key events will be ignored.
Ignoring focus traversal and mouse events was easy. Key events were a much bigger problem. Swing components can use Key Bindings, so even when a component doesn’t have focus, Actions mapped to a specific KeyStroke can be invoked. I managed to get around this by creating a custom EventQueue. Before a KeyStroke is dispatched to a component it is checked to see if it is bound to a component on a DisabledPanel. If so, it is ignored, otherwise it is dispatched normally.
Using a DisabledPanel is straight forward:
JPanel somePanel = new JPanel();
DisabledPanel disabledPanel = new DisabledPanel(somePanel);
When a container is disabled it would look like this, although you are free to change the background color of the glass pane and therefore the disabled look:
Hopefully one of the two approaches will meet your needs.