I have a Java application whose basic UI consists of two JFrames: a client area, and a tool palette which should always appear above the client area. To achieve this, the tool palette is set to alwaysOnTop(true), which works quite nicely in all cases save one exclusive to Windows: when a modal JDialog is popped, clicking on the client area and/or the palette (both of which are blocked) causes the palette to fall behind the client area. Once the modal dialog is closed, the palette reappears, but its "always on top-ness" has been lost: clicking the client area obscures the palette.
Here's a minimal, single source file demonstration:
// FloatingPaletteExample.java
// 4/11/2012 sorghumking
//
// Demo of a Windows-only issue that has me puzzled: When a modal dialog is
// opened, and user clicks in blocked JFrames (sequence depends on ownership of
// modal dialog: follow the instructions in modal dialog to see the problem
// behavior), the floating tool palette loses its "always on top-ness".
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class FloatingPaletteExample {
public static void main( String [] args ) {
final JFrame clientAreaJFrame = new JFrame( "client JFrame" );
clientAreaJFrame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent windowevent ) {
clientAreaJFrame.dispose();
System.exit( 0 );
}
});
clientAreaJFrame.setSize( 800, 600 );
clientAreaJFrame.setVisible( true );
final JFrame floatingToolFrame = new JFrame("tool JFrame");
final JCheckBox ownerCheckbox = new JCheckBox("Owned by tool frame (otherwise, null owner)");
JButton popModalButton = new JButton("Open Modal Dialog");
popModalButton.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFrame owner = ownerCheckbox.isSelected() ? floatingToolFrame : null;
JDialog modalDialog = new JDialog(owner, "Modal Dialog", true);
final String labelText = ownerCheckbox.isSelected() ? "Click anywhere in the client JFrame." :
"Click the tool JFrame, then anywhere in the client JFrame";
modalDialog.add(new JLabel(labelText));
modalDialog.pack();
modalDialog.setLocation(100, 100);
modalDialog.setVisible(true);
}
});
floatingToolFrame.add(popModalButton, BorderLayout.NORTH);
floatingToolFrame.add(ownerCheckbox, BorderLayout.SOUTH);
floatingToolFrame.pack();
floatingToolFrame.setLocationRelativeTo(clientAreaJFrame);
floatingToolFrame.setAlwaysOnTop(true);
floatingToolFrame.setVisible(true);
}
}
I tried floatingToolFrame.setFocusableWindowState(false), which according to the doc is "the standard mechanism for an application to identify to the AWT a Window which will be used as a floating palette or toolbar", but the behavior remains the same.
I did find a workaround: call floatingToolFrame.setAlwaysOnTop(false) prior to popping the modal dialog, and call floatingToolFrame.setAlwaysOnTop(true) after it's closed. However, it seems ridiculous to require this wrapping anytime a modal dialog is opened. Yes, I could subclass JDialog and derive all my dialogs from said subclass to do this behind the scenes, but again, why is this necessary?
Any ideas on how to resolve this without the workaround? Is my approach to creating an always-on-top palette completely misguided? (One more note: this appears to be the opposite of the problem described here: Java 6, JFrame stuck alwaysontop).
Any thoughts would be much appreciated!