1

When I start some processing, I want to disable the JButtons, JText, Lists, etc. in the GUI, only having one button to stop the processing.

What is a clean way to do this? I was setting component by component with setEnabled(false), but the code was too big.

Can I get all the components in an array and set all inside a for loop? How I do this? There is another way?

Renato Dinhani
  • 35,057
  • 55
  • 139
  • 199
  • Have you considered recursively iterating through the component hierarchy? – Steve Jun 25 '11 at 18:30
  • Maybe like this: `void setDescendantsEnabled(JComponent comp, boolean value){ for (Container cont : comp.getChildren) { cont.setEnabled(value); setDescendantsEnabled((JComponent)cont, value); } }` – Steve Jun 28 '11 at 07:03

3 Answers3

9

You can use the Disabled Glass Pane approach.

Or, use a JOptionPane with a message like "Processing....". When the processing is finished you close the dialog. Read the API for an example of how to create the option pane so that you have access to the actual dialog used. You will need the reference to the dialog so you can close it.

Edit:

See: How to Make Dialogs for examples.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • I can do the "Processing..." because will run until the user click on the "Stop" button. – Renato Dinhani Jun 25 '11 at 18:39
  • If the user clicks the "Stop" button, then the JOptionPane is the way to go. See my edit. – camickr Jun 25 '11 at 18:46
  • Hmmmm...I think it will work, but I don't know if is an proper solution. It's a webcrawler, so it will run for a large time displaying some statistics, so disabling the components will be better than displaying a dialog, I guess. – Renato Dinhani Jun 25 '11 at 18:53
  • 2
    If you don't want the user to interact with the frame while any process is running, then a modal dialog is the proper solution and is much easier than writing recursive code to disable all fields on the frame. So instead of using a JOptionPane you create a custom modal dialog. – camickr Jun 25 '11 at 18:59
  • +1 Also consider [modality](http://download.oracle.com/javase/tutorial/uiswing/misc/modality.html). – trashgod Jun 25 '11 at 19:08
  • No, the user can interact, resize, minimize, do what he wants. I only don't want it click on some configurations(radios, checks, combos) or in the buttons to start the processing when it's already running. – Renato Dinhani Jun 25 '11 at 19:29
  • Sounds to me like you have a design issue. I would suggesst you need a non-modal dialog to start your Web Crawler. This dialog would have the configuration options for the crawling. Then when you start crawling you dispaly a dialog that is modal to the dialog, not the frame. This way you can still interact with other functions of the main frame. – camickr Jun 25 '11 at 20:01
  • This appear to be right and useful, but I used the solution found in this question: http://stackoverflow.com/questions/6495769/how-to-get-all-elements-inside-a-jframe – Renato Dinhani Jun 27 '11 at 23:01
1

you could try this class :

   import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.FocusManager;

public class Blocker extends EventQueue {
    private Component[] restrictedComponents;

    private Vector helperVector;

    private boolean inBlockedState = false;

    private EventQueue sysQ = Toolkit.getDefaultToolkit().getSystemEventQueue();

    private boolean alreadyBlockedOnce = false;

    private static Blocker instance = null;

    public static synchronized Blocker Instance() {
        if (instance == null) {
            instance = new Blocker();
        }
        return instance;
    }

    private Blocker() {
        restrictedComponents = null;
    }

    private void reset() {
        if (inBlockedState) {
            setBlockingEnabled(false);
        }
        restrictedComponents = null;
    }

    public void setRestrictedComponents(Component[] restrictedComponents) {
        reset(); // puts the Blocker into an unblocked state, and clears the
        // restrictedComponents array (see private method below)
        helperVector = new Vector();
        // global Vector variable
        if (restrictedComponents != null) {
            extractAllComponents(restrictedComponents);
        }

        // builds the blockedComponent array
        if (helperVector.size() >= 1) {
            this.restrictedComponents = new Component[helperVector.size()];
            for (int k = 0; k < helperVector.size(); k++) {
                this.restrictedComponents[k] = (Component) helperVector
                        .elementAt(k);

            }
        } else {
            this.restrictedComponents = null;
        }
    }

    private void extractAllComponents(Component[] array) {
        for (int i = 0; i < array.length; i++) {
            if (array[i] != null) {
                helperVector.addElement(array[i]);
                if (((Container) array[i]).getComponentCount() != 0) {
                    extractAllComponents(((Container) array[i]).getComponents());
                }
            }
        }
    }

    private void adjustFocusCapabilities(boolean blocked) {
        if (blocked) {
            for (int i = 0; i < restrictedComponents.length; i++) {
                this.restrictedComponents[i].setEnabled(false);
                if (restrictedComponents[i] instanceof JComponent) {
                    ((JComponent) restrictedComponents[i])
                            .setRequestFocusEnabled(false);
                    ((JComponent) restrictedComponents[i]).setEnabled(false);
                }

                // removes the focus indicator from all components that are
                // capable
                // of painting their focus
                if (restrictedComponents[i] instanceof AbstractButton) {
                    ((AbstractButton) restrictedComponents[i])
                            .setFocusPainted(false);
                    ((AbstractButton) restrictedComponents[i])
                            .setEnabled(false);
                }
            }
        } else {

            for (int k = 0; k < restrictedComponents.length; k++) {
                this.restrictedComponents[k].setEnabled(true);
                if (restrictedComponents[k] instanceof JComponent) {
                    ((JComponent) restrictedComponents[k])
                            .setRequestFocusEnabled(true);
                }
                if (restrictedComponents[k] instanceof AbstractButton) {
                    ((AbstractButton) restrictedComponents[k])
                            .setFocusPainted(true);
                }
            }
        }
    }

    private Component getSource(AWTEvent event) {
        Component source = null;
        // each of these five MouseEvents will still be valid (regardless
        // of their source), so we still want to process them.
        if ((event instanceof MouseEvent)
                && (event.getID() != MouseEvent.MOUSE_DRAGGED)
                && (event.getID() != MouseEvent.MOUSE_ENTERED)
                && (event.getID() != MouseEvent.MOUSE_EXITED)
                && (event.getID() != MouseEvent.MOUSE_MOVED)
                && (event.getID() != MouseEvent.MOUSE_RELEASED)) {
            MouseEvent mouseEvent = (MouseEvent) event;
            source = SwingUtilities.getDeepestComponentAt(mouseEvent
                    .getComponent(), mouseEvent.getX(),

            mouseEvent.getY());
        } else if (event instanceof KeyEvent
                && event.getSource() instanceof Component) {
            source = SwingUtilities.findFocusOwner((Component) (event
                    .getSource()));
        }
        return source;
    }

    private boolean isSourceBlocked(Component source) {
        boolean blocked = false;
        if ((restrictedComponents != null) && (source != null)) {
            int i = 0;
            while (i < restrictedComponents.length
                    && (restrictedComponents[i].equals(source) == false))
                i++;

            blocked = i < restrictedComponents.length;
        }
        return blocked;
    }

    protected void dispatchEvent(AWTEvent event) {
        boolean blocked = false;

        if (inBlockedState) {
            // getSource is a private helper method
            blocked = isSourceBlocked(getSource(event));
        }
        if (blocked
                && (event.getID() == MouseEvent.MOUSE_CLICKED || event.getID() == MouseEvent.MOUSE_PRESSED)) {
            Toolkit.getDefaultToolkit().beep();
        }

        else if (blocked && event instanceof KeyEvent
                && event.getSource() instanceof Component) {
            DefaultFocusManager dfm = new DefaultFocusManager();
            FocusManager.getCurrentManager();
            Component currentFocusOwner = getSource(event);

            boolean focusNotFound = true;
            do {
                dfm.focusNextComponent(currentFocusOwner);
                currentFocusOwner = SwingUtilities
                        .findFocusOwner((Component) event.getSource());
                if (currentFocusOwner instanceof JComponent) {
                    focusNotFound = (((JComponent) currentFocusOwner)
                            .isRequestFocusEnabled() == false);
                }
            } while (focusNotFound);
        } else {
            super.dispatchEvent(event);
        }
    }

    public void setBlockingEnabled(boolean block) {
        // this methods must be called from the AWT thread to avoid
        // toggling between states while events are being processed
        if (block && !inBlockedState && restrictedComponents != null) {

            adjustFocusCapabilities(true);
            // "adjustFocusCapabilities" is a private helper function that
            // sets the focusEnabled & focusPainted flags for the
            // appropriate components. Its boolean parameter signifies
            // whether we are going into a blocked or unblocked state
            // (true = blocked, false = unblocked)

            if (!alreadyBlockedOnce) {

                // here is where we replace the SystemQueue
                sysQ.push(this);
                alreadyBlockedOnce = true;
            }
            inBlockedState = true;
        } else if (!block && inBlockedState) {
            adjustFocusCapabilities(false);
            inBlockedState = false;
        }
    }
}

you can call it with ('this' refers to your JFrame):

Blocker.instance().setRestrictedComponents(this.getComponents());
othman
  • 4,428
  • 6
  • 34
  • 45
0

One more approach would be to use JXLayer (soon to be part of Swing as JLayer) with LockableUI.

This solution requires additional library but it is infinitely more flexible and elegant.

Eugene Ryzhikov
  • 17,131
  • 3
  • 38
  • 60