Layering Multiple Glasspane's in a Root Container

Layering multiple GlassPane's in a Root Container

Look at http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html for an explanation on Root panes and what the Glass pane actually is.

The glass pane is just a convenient way to add a component which has the size of the Root Pane, and which blocks all input events. This allows you to catch any interaction with your components to create a "Please wait..." screen.

There is only a single glass pane per root container. You cannot layer glass panes.

You can replace the contents of the glass pane by something else if you want to layer something over the current glass pane. You can also set a JPanel as a glass pane, which allows you to layout multiple components in the glass pane.

Usually, you should only use the glass pane to block user input (and, if necessary, display some kind of "please wait" message). Can you provide a use case of why you want to put glass panes on top of one another?

Showing GlassPane before entering loop

GUI just freezes for a moment, before result is displayed. Removing last line in that loop (glassPane.setVisible(false);) results in showing glassPane after the method is done (when GUI unfreezes).

this is common issue about Event Dispath Thread, when all events in EDT are flushed to the Swing GUI in one moment, then everything in the method if (item.equals(button)) { could be done on one moment,

but your description talking you have got issue with Concurency in Swing, some of code blocking EDT, this is small delay, for example Thread.sleep(int) can caused this issue, don't do that, or redirect code block to the Backgroung taks

Is there a simple way to show that glassPane before GUI freezes, or I need to use some advanced knowledge here? (threads?)

this question is booking example why SwingWorker is there, or easier way is Runnable#Thread

  • methods implemented in SwingWorker quite guarante that output will be done on EDT

  • any output from Runnable#Thread to the Swing GUI should be wrapped in invokeLater()

easiest steps from Jbuttons Action could be

  • show GlassPane

  • start background task from SwingWorker (be sure that listening by PropertyChangeListener) or invoke Runnable#Thread

  • in this moment ActionListener executions is done rest of code is redirected to the Backgroung taks

  • if task ended, then to hide GlassPane

  • create simple void by wrapping setVisible into invokeLater() for Runnable#Thread

  • in the case that you use SwingWorker then you can to hide the GlassPane on proper event from PropertyChangeListener or you can to use any (separate) void for hidding the GlassPane

best code for GlassPane by @camickr, or my question about based on this code

I want my JLayeredPane to catch all events

It is impossible to intercept events by adding a simple component as a layer in terms of JLayeredPane. It seems that a lot of developers are not aware of this. Events are usually dispatched directly to the deepest child component containing the coordinates of a mouse event or to the focused component in case of a key event ignoring the parents, not to speak layers that are not even parents of the target component.

Thankfully there was a component added in Java 7 which does the complicated trick for you, JLayer, not to confuse with JLayeredPane.

Here is an example of how to use it:

JFrame f=new JFrame("Disabling via JLayer");
final JLayer<JTree> layer = new JLayer<JTree>(new JTree(), new LayerUI<JTree>() {
@Override
public void eventDispatched(AWTEvent e, JLayer<? extends JTree> l) {
if(e instanceof InputEvent) ((InputEvent)e).consume();
}
@Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f));
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, c.getWidth(), c.getHeight());
g2d.dispose();
}
});
f.setContentPane(layer);
layer.setLayerEventMask(~0);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);

Painting over the top of components in Swing?

This is what I'm already doing (on a much simpler level obviously), and Swing paints the rectangle underneath the components added to it.

This is one case where you should override the paint() method of the panel and not the paintComponent() method. Then the custom painting will be done AFTER all the child components have been painted.

Add a JPanel to a Graphics Panel and making the JPanel Transparent except for objects

I want this JPanel to be transparent so that the Graphics Panel
underneath is Visible but the JButtons do not turn transparent as
well.

an OverlayLayout JPanel will do what you descibe.

Java paintComponent override differences between versions 5 and 6

Create a copy of the Graphics context in the paintComponent function. This will fix the problem.

public void paintComponent( Graphics g )
{
super.paintComponent( g );
Graphics2D g2 = (Graphics2D) g.create();
...
}

Swing goes into the wait state after locking unlocking through glasspane

I got the issue resolved.

This answer helped me a lot. java swing clear the event queue Infact the key concept is same.

So for the code part I modified the modules with the

lockWindow

private void lockWindow(final Window window) {
if (window instanceof RootPaneContainer
&& ((RootPaneContainer) window).getRootPane() != null
&& !lockedWindows.containsKey(window)) {
java.util.Timer timer = null;
try {

//don't do invalidate, invalidate as the first step
//((RootPaneContainer) window).getContentPane().invalidate();

// Create an object to store original details for the locked window.
LockedWindow lockedWindow = new LockedWindow();
lockedWindows.put((RootPaneContainer) window, lockedWindow);

lockedWindow.originalGlassPane = ((RootPaneContainer) window).getGlassPane();

//okk may be glasspane only in integrated scenario is causing the issue
//comment it and check, we are still putting it in the map above but its doing nothing
/*
// Remember the original glass pane and visibility before locking.

//okk is this the only issue? What should be the originalGlassPane first time? null?
lockedWindow.originalGlassPane = ((RootPaneContainer) window).getGlassPane();
System.err.println("Original galss pane : " + ((RootPaneContainer) window).getGlassPane());

lockedWindow.wasVisible = ((RootPaneContainer) window).getContentPane().isVisible();

// Add a LockedGlassPane to the window.
LockedGlassPane lgp = new LockedGlassPane();
lgp.setVisible(true); //hide the contents of the window
((RootPaneContainer) window).setGlassPane(lgp);

//don't do this stuff too
((RootPaneContainer) window).getContentPane().setVisible(false);

lgp.setVisible(true); //redisplays the lock message after set as glassPane.
*/
LockedGlassPane lgp = new LockedGlassPane();
((RootPaneContainer) window).setGlassPane(lgp);
timer = switchToBusyCursor(window);

try {
Thread.sleep(3000);
} catch (InterruptedException e) {
//do nothing
System.err.println("Am I interrupted?");
}
//okk the above thing worked, it doesnt lock naturlly, now try if setting visible code is an issue?
//great this thing works so this also is not an issue, only galsspane in SiteManager is
lockedWindow.wasVisible = ((RootPaneContainer) window).getContentPane().isVisible();

((RootPaneContainer) window).getContentPane().repaint();

// Minimize the window (if requested), while keeping a record of
// which windows have been minimized so that they can be restored
// later when the TimeoutTarget is unlocked.

//don't do this stuff too - as unlock is not working investigating that
if (window instanceof Frame) {
Frame frame = (Frame) window;
// Remember the original minimized state of the window.
lockedWindow.minimized = (frame.getExtendedState() & Frame.ICONIFIED) != 0;
if (lockMinimized) {
frame.setExtendedState(Frame.ICONIFIED);
}
}

//
//Note required now, but keeping in case the requirement changes again.
//
// Prevent the window from being closed while this target is
// locked.
// lockedWindow.windowListeners = window.getWindowListeners();
// for (WindowListener wl : lockedWindow.windowListeners) {
// window.removeWindowListener(wl);
// }
//if (window instanceof JFrame) {
// JFrame jframe = (JFrame) window;
// lockedWindow.originalDefaultCloseOperation = jframe.getDefaultCloseOperation();
// jframe.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
//} else if (window instanceof JDialog) {
// JDialog jdialog = (JDialog) window;
// lockedWindow.originalDefaultCloseOperation = jdialog.getDefaultCloseOperation();
// jdialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
//}
} catch (Exception e) {
System.err.println(getThreadPrefix() + " Failed to lock window." + e.getLocalizedMessage());
} finally {
switchToNormalCursorEventThread(window, timer);
}
}
}

unlockWindow

private void unlockWindow(RootPaneContainer window) {
try {
LockedWindow lockedWindow = lockedWindows.get(window);
//System.err.println(getThreadPrefix() + " Unlocking window::: " + lockeWindow.isDisplayable());
if (lockedWindow != null && ((Frame) window).isDisplayable()) {
System.err.println(getThreadPrefix() + "Unlocking..." + lockedWindow);
// Restore the original glasspane for the window

//okk may be glasspane only in integrated scenario is causing the issue
//comment it and check, we are still putting it in the map above but its doing nothing

//okk is this the only issue? What should be the originalGlassPane first time? null?
if (lockedWindow.originalGlassPane != null) {
System.err.println(getThreadPrefix() + "Reset original glass pane.");
window.setGlassPane(lockedWindow.originalGlassPane);
//lockedWindow.originalGlassPane.setVisible(true);
}

//make content pane visible again.
//(window).getContentPane().setVisible(lockedWindow.wasVisible);

//okk try this
//(window).getContentPane().setVisible(true);
//(window).getRootPane().invalidate();

//okk the above thing worked, it doesnt lock naturlly, now try if setting visible code is an issue?
//great this thing works so this also is not an issue
(window).getContentPane().setVisible(lockedWindow.wasVisible);

(window).getRootPane().repaint();

// Restore (un-minimize) the window if it wasn't minimized before
// the lock.
//do this tuff anyways
if (!lockedWindow.minimized && window instanceof Frame) {
((Frame) window).setExtendedState(((Frame) window).getExtendedState()
& ~Frame.ICONIFIED);
}

// Restore the original default close operation from before the
// lock, which will normally allow the window to be closed.

//dont do listeneres??
if (window instanceof Window) {
if (lockedWindow.windowListeners != null) {
for (WindowListener wl : lockedWindow.windowListeners) {
System.err.print("windowlistener is not null " + wl);
((Window) window).addWindowListener(wl);
}
}
if (window instanceof JFrame) {
((JFrame) window)
.setDefaultCloseOperation(lockedWindow.originalDefaultCloseOperation);
} else if (window instanceof JDialog) {
((JDialog) window)
.setDefaultCloseOperation(lockedWindow.originalDefaultCloseOperation);
}
}

//try this too
//((RootPaneContainer)window).setGlassPane(null);

//lockedWindows.remove(window);
//stopEventTrap
stopEventTrap((Frame)window);
System.err.println(getThreadPrefix() + " Window has been unlocked");
}
} catch (Exception e) {
System.err.println(getThreadPrefix() + " Failed to unlock window. " + e.getLocalizedMessage());
}

}

Added these new methods taken from above answer with modifications as p[er my use case

public static java.util.Timer switchToBusyCursor(final Window frame) {
startEventTrap(frame);
java.util.TimerTask timerTask = new java.util.TimerTask() {

public void run() {
startWaitCursor(frame);
}

};
final java.util.Timer timer = new java.util.Timer();
timer.schedule(timerTask, DELAY_MS);
return timer;
}

public static void switchToNormalCursorEventThread(final Window window, final java.util.Timer timer) {

Runnable r = new Runnable() {

public void run() {
switchToNormalCursor(window, timer);
}

};

javax.swing.SwingUtilities.invokeLater(r);

}

public static void switchToNormalCursor(final Window window, final java.util.Timer timer) {
timer.cancel();
stopWaitCursor(window);
//stopEventTrap(window);
}

private static void startWaitCursor(Window window) {
((RootPaneContainer) window).getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
((RootPaneContainer) window).getGlassPane().addMouseListener(mouseAdapter);
((RootPaneContainer) window).getGlassPane().setVisible(true);
}

private static void stopWaitCursor(Window window) {
((RootPaneContainer) window).getGlassPane().setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.DEFAULT_CURSOR));
//((RootPaneContainer) window).getGlassPane().removeMouseListener(mouseAdapter);
//((RootPaneContainer) window).getGlassPane().setVisible(false);
}

private static void startEventTrap(Window window) {
((RootPaneContainer) window).getGlassPane().addMouseListener(mouseAdapter);
((RootPaneContainer) window).getGlassPane().setVisible(true);
}

private static void stopEventTrap(Window window) {
java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue();
((RootPaneContainer) window).getGlassPane().removeMouseListener(mouseAdapter);
((RootPaneContainer) window).getGlassPane().setVisible(false);
}

private static final java.awt.event.MouseAdapter mouseAdapter = new java.awt.event.MouseAdapter() {
};

I have also taken threaddumps and analysed them as @trashgod said. I found that was correct too, IMHO, nothing blocking / wrong there. Though yes, AWTEventQueue-0 was at the same code point always.



Related Topics



Leave a reply



Submit