Java Tips Weblog

  • Blog Stats

    • 2,569,183 hits
  • Categories

  • Archives

Disabled Panel

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);
frame.add(disabledPanel);
...
disabledPanel.setEnabled(false);

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:

DisabledPanel

Hopefully one of the two approaches will meet your needs.

Get The Code

DisabledPanel.java
OverlapLayout.java
SwingUtils.java

See Also

Overlap Layout
Swing Utils
Disabled Glass Pane

6 Responses to “Disabled Panel”

  1. André Uhres said

    Related reading: Enabling/Disabling Swing Containers

  2. nr said

    Hi,

    That’s cool stuff but I have a side-effect using it.

    The events dispatched from the DisabledEventQueue fail the verification of SwingUtilities.isEventDispatchThread()… That causes my RepaintManager to behave incorrectly and eventually, some use of the Foxtrot workers will fail too (foxtrot.sourceforge.net).

    So I think that using a custom EventQueue isn’t correct. The static map isn’t a good thing too, removing components on windowClosed doesn’t cover all cases, use of weak keys should be preferred (for exemple if the DisabledPanel is programmatically removed from it’s hierarchy).

    The only way I think would be to disable (or wrap) the keyStrokes and reactivate them when enabled=true.

    What do you think ?
    Regards,
    Nat

  3. ilja kolodyazhnyy said

    DisabledPanel doesn’t work on child elements

  4. Sérgio Michels said

    If you have two panels, the first enabled and the second disabled you still can navigate from the first to the second, but just in the first element.

  5. Yakir said

    Taking in account the comments above me, this is still one of the best Swing solutions I’ve encountered. You saved me days of work.
    Great work! and thank you.

Leave a reply to ilja kolodyazhnyy Cancel reply