Java - cannot bring the window to front - java

I am trying to execute the following code:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (frame.getExtendedState() == Frame.ICONIFIED)
frame.setExtendedState(Frame.NORMAL);
frame.getGlassPane().setVisible(!frame.getGlassPane().isVisible());
frame.toFront();
frame.repaint();
}
});
Unfortunately this does not bring it to the front from behind other windows... Any solutions?

Per the API documentation for setExtendedState:
If the frame is currently visible on the screen (the
Window.isShowing() method returns true), the developer should examine
the return value of the WindowEvent.getNewState() method of the
WindowEvent received through the WindowStateListener to determine that
the state has actually been changed.
If the frame is not visible on the screen, the events may or may not
be generated. In this case the developer may assume that the state
changes immediately after this method returns. Later, when the
setVisible(true) method is invoked, the frame will attempt to apply
this state. Receiving any WindowEvent.WINDOW_STATE_CHANGED events is
not guaranteed in this case also.
However, there is also a windowDeiconified callback you can hook into on WindowListener:
SwingUtilities.invokeLater(new Runnable() {
private final WindowListener l = new WindowAdapter() {
#Override
public void void windowDeiconified(WindowEvent e) {
// Window now deiconified so bring it to the front.
bringToFront();
// Remove "one-shot" WindowListener to prevent memory leak.
frame.removeWindowListener(this);
}
};
public void run() {
if (frame.getExtendedState() == Frame.ICONIFIED) {
// Add listener and await callback once window has been deiconified.
frame.addWindowListener(l);
frame.setExtendedState(Frame.NORMAL);
} else {
// Bring to front synchronously.
bringToFront();
}
}
private void bringToFront() {
frame.getGlassPane().setVisible(!frame.getGlassPane().isVisible());
frame.toFront();
// Note: Calling repaint explicitly should not be necessary.
}
});

I found that the following workaround for toFront() on a JDialog works on Windows 7 (haven't tested other platforms yet):
boolean aot = dialog.isAlwaysOnTop();
dialog.setAlwaysOnTop(true);
dialog.setAlwaysOnTop(aot);
Paul van Bemmelen

Related

Why does my JFrame move to the background after closing modal JDialog

Edit: Updated question including a MRE and an answer can be found here.
I'm pretty lost after stumbling across this issue and finding no way to resolve it myself.
Description:
I have an application which has a Java Swing GUI. All the communication to the GUI is done via custom Events, mostly created by the main program, which are then processed by a Controller to control the GUI.
One event I have will trigger the Controller to open a custom Modal JDialog which acts just as a "please wait while the stuff in the background is being processed". So after the background task is finished, an Event will trigger the Dialog to dispose, to make the main GUI frame accessible again.
The issue:
When the Dialog is disposed, the main Frame will magically be set to the background. Not minimized, not completely in the background of all open windows, but actually in the background of the last open window. I'm completely lost on how and why this happens.
The important parts of the Controller class look vaguely like this:
class Controller {
private ModalWaitDialog dialog;
private JFrame frame;
private void createMainFrame() {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
// create frame
frame = new JFrame();
// make the frame visible
frame.setVisible(true);
}
});
}
private void showWaitPopup(String msg) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
modalWaitDialog = new ModalWaitDialog(frame, message);
modalWaitDialog.showDialog();
}
});
}
// after this was executed, my frame will be set in the background
private void endWaitPopup() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (modalWaitDialog != null) {
modalWaitDialog.dispose();
modalWaitDialog = null;
}
}
});
}
}
I know this is not a MCVE, but maybe somebody knows how and why this happens.
Edit:
I added a WindowFocusListener to the Frame and added some print statements to the endWaitPopup, and called invokeAndWait to further see what is happening. The following is the result:
private void endWaitPopup() {
System.out.println("In EndWaitPopup");
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
System.out.println("EndWaitPopup... run started");
// implement as if it could be called if no wait popup is available
if (modalWaitDialog != null) {
System.out.println("Disposing the modal dialog");
modalWaitDialog.dispose();
modalWaitDialog = null;
}
System.out.println("End of EndWaitPopup");
}
});
} catch (InvocationTargetException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Output:
In EndWaitPopup
+++Focus of Frame lost+++
EndWaitPopup... run started
Disposing the modal dialog
End of EndWaitPopup

Why are the Window/Component Listeners invoked differently when setVisible(false) and dispose() are called?

The difference I see is (running on JDK 1.7):
setVisible(false), invokes componentHidden but not windowClosed (The API states only on dispose() so it's OK even if it irritates me)
but
dispose(), invokes windowClosed but not componentHidden
Short running example code (MCVE):
public class JDialogTest extends JDialog {
private static final long serialVersionUID = 1L;
public JDialogTest(JFrame owner){
super(owner,ModalityType.APPLICATION_MODAL);
init();
}
private void init() {
this.getContentPane().setLayout(new GridLayout(1,2));
JButton btnVisible = new JButton("Set visible false");
btnVisible.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JDialogTest.this.setVisible(false);
}
});
JButton btnDispose = new JButton("Dispose");
btnDispose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JDialogTest.this.dispose();
}
});
this.getContentPane().add(btnVisible);
this.getContentPane().add(btnDispose);
this.pack();
}
public static void main(String[] args) {
//A fake frame to test JDialog
JFrame fakeFrame = new JFrame("Fake Frame");
fakeFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fakeFrame.getContentPane().setLayout(new BorderLayout());
JButton btnOpen = new JButton("Open Dialog");
fakeFrame.getContentPane().add(btnOpen,BorderLayout.CENTER);
fakeFrame.pack();
fakeFrame.setLocationRelativeTo(null);
//Generate the test dialog
final JDialogTest dialog = new JDialogTest(fakeFrame);
dialog.addComponentListener(new ComponentAdapter() {
#Override
public void componentShown(ComponentEvent e) {
System.out.println("Component Shown");
}
#Override
public void componentHidden(ComponentEvent e) {
System.out.println("Component Hidden");
}
});
dialog.addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
System.out.println("Window open");
}
#Override
public void windowClosed(WindowEvent e) {
System.out.println("Window closed");
}
});
dialog.setLocationRelativeTo(null);
btnOpen.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.setVisible(true);
}
});
fakeFrame.setVisible(true);
}
}
NOTE: The example features a JDialog, but I see same behavior in JFrame, to test simple attach the listeners to the fakeFrame, and add similar buttons. (avoided in MVCE to keep it Minimal)).
I have considered this post:
JDialog setVisible(false) vs dispose()
In answers seems that is should be no difference, use dispose()...
API DOCUMENTATION:
Window.setVisible(boolean b), Window.dispose(), ComponentListener.componentHidden(ComponentEvent e), WindowListener.windowClosed(WindowEvent e)
Why do I care: Naturally out of curiosity, but also since I use buttons to close the window (invoking dispose()) and the interface can also be closed by the top/right window close icon and alt+F4 (invoking setVisible(false)!?). Hence no one of the above listener can be used. Only the HierarchyListener will catch them both and this seems counter intuitive.
EDIT: The question is scoped as "why is it like this"? What is the purpose?". I was expecting dispose() to invoke both! I can't find any clues in the API documentation for why not.
the interface can also be close by top/right window close icon alt+F4 (invoking setVisible(false)!?)
This is determined by the default close operation. You can set it with setDefaultCloseOperation. The default is HIDE_ON_CLOSE, which is why you get a componentHidden invocation. If you set it to DISPOSE_ON_CLOSE then you will get a windowClosed invocation instead. Setting to the latter will allow you to only register for those event types.
Regardless, hiding and disposing do different things. Disposing releases the resources used while hiding doesn't. Also, hiding the last window will not exit the JVM while disposing it will.
As for the technical side of event dispatching, there are a lot of intricacies. While disposing the window does call its hiding method, the dispatching of events is done after operations are done. This means that the EDT can dispatch events "after the fact". Since the window is closed, it does not dispatch the hiding event.
I came accross this question while struggling with the behaviour described. My handler for componentHidden were not called although a ComponentEvent(COMPONENT_HIDDEN) was scheduled to the dialog's event queue by setVisible(false).
My dialog is modal and the caller invokes dispose explicitely after the dialog is closed and returns from setVisible(true). Probably this is a "race condition" between the dialog's event queue und the application's event queue. My work around therefore is on the caller's side:
SwingUtilities.invokeLater(myDialog::dispose);
This should postpone the disposal of the dialog until its event queue is exhausted; componentHidden is called in this setting.

Java Swing, restore from system tray not working in Linux

I am creating an application in Java and I would like that when you minimize to an icon, the application will have to "hide" in the system tray.
The code I use is this: (the significant part of the code)
myFrame = new JFrame();
myFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowIconified(WindowEvent e) {
PutTray();
}
#Override
public void windowDeiconified(WindowEvent e) {
System.out.println("Deiconified");
}
});
This is a "PutTray" function:
private void PutTray()
{
try
{
tray.add(trayIcon); // Initialized elsewhere
myFrame.setVisible(false);
} catch (AWTException e) {
System.err.println(e);
}
}
To restore (via option in the pop-up menu when you press the icon minimized):
MenuItem show = new MenuItem("Show");
show.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myFrame.setVisible(true);
myFrame.setState(JFrame.NORMAL);
tray.remove(trayIcon);
}
});
The code works perfectly on Windows 8, but it does not work on Linux (Kali Linux and even Ubuntu).
Why Windows yes and Linux no?
EDIT:
On Linux, after you press the command to show the application, it appears for a very small moment, and then minimizes again. Basically is triggered the event "windowDeiconified" and immediately after the event "windowIconified" without taking the time to do something else and then the application is shown in the system tray.
As Dan Getz suggests, I also thought the order of setVisible and setState should be inverted since the javadoc for setState says:
If the frame is not visible on the
* screen, the events may or may not be
* generated.
but this didn't help.
The one thing that did help though was replacing setVisible(false) with dispose(). They are similar in that you can use setVisible(true) to reopen a disposed window. You can read more about it here: JDialog setVisible(false) vs dispose()
I'll try to find an explanation and come back with it :)
SSCCE to simulate OP problem:
public class Test {
private JFrame myFrame;
public Test() {
myFrame = new JFrame();
myFrame.setVisible(true);
myFrame.setSize(300, 300);
myFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowIconified(WindowEvent e) {
PutTray();
}
});
}
private void PutTray() {
myFrame.setVisible(false); //replace with dispose(); and it's ok
Timer t = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent actionEvent) {
myFrame.setVisible(true);
}
});
t.setRepeats(false);
t.start();
}
public static void main(String[] args) {
new Test();
}
}
I think you are getting it wrong!
Maybe you are confused about deiconified and visibility
windowIconified()
will be called when we click minimize button
and
windowDeiconified()
is called when we restore it from taskbar and not system tray!
In order to restore from system tray you need to use this
trayIcon.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
window.setVisible(true);
}
});
Basically i don't think the difference between dispose() & setVisible() will bother you in this specific problem
Still, my recommendation is to use setVisible() here

JProgressBar indeterminate thread

I have a problem while creating a JProgressBar which is set to indeterminate.
The following code is my implementation of the JProgressBar and is called/constructed from another class:
public class Progress implements Runnable
{
private JFrame frameProgress;
private JProgressBar progressBar;
public Progress(String title, String message)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e)
{
GlobalVariables.LOGGING_logger.error("Error instatiating progress bar.",
e);
}
UIManager.put("ProgressBar.selectionForeground", Color.black);
UIManager.put("ProgressBar.selectionBackground", Color.black);
this.frameProgress = new JFrame(title);
this.frameProgress.setIconImage(GlobalVariables.GUI_icon.getImage());
this.frameProgress.setSize(300, 60);
this.frameProgress.setLocation(16, 16);
this.progressBar = new JProgressBar();
this.progressBar.setStringPainted(true);
this.progressBar.setString(message);
this.progressBar.setIndeterminate(true);
this.frameProgress.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frameProgress.add(this.progressBar);
this.frameProgress.setResizable(false);
this.frameProgress.setVisible(true);
}
public void start()
{
new Thread(this).start();
}
public void close()
{
this.frameProgress.dispose();
this.frameProgress = null;
this.progressBar = null;
}
#Override
public void run()
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
// do nothing, because progress bar is indeterminate
}
});
}
}
The caller of this JProgressBar is the following code snippet:
Progress p = new Progress("bla", "blub");
p.start();
boolean successfull = xmlWriter.writeCommonSettingsFromGUI(this);
p.close();
And now i want, while the xmlWriter.writeCommonSettingsFromGUI(this); is doing something, that the JProgressBar is shown to the user and is working while the algorithm is running.
How can I achieve this? I don't know so much about threading and searched in many other forums, but I don't found any answer for my question.
Please help me and thank you in advance ;)
EDIT:
The Progress JFrame opens up with no content for that time, the algorithm is running.
You are probably facing concurrency issues with Swing. Assuming that the following code runs on the EDT (Event Dispatching Thread):
Progress p = new Progress("bla", "blub");
eventually, this will open a JFrame with a progress bar in it.
I would consider using a JDialog instead of a JFrame
I would not force the size of the JFrame, but rather call pack()
Then, still running on the EDT (and thus blocking all UI-events such as repaint, mouse clicks, etc...), you call p.start() which starts a new Thread() which will invoke run() which itself calls
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
// do nothing, because progress bar is indeterminate
}
});
This basically won't do anything except push an additional event on the EventQueue and it will run after all currently pending events. This event will run... "nothing" since your Runnable is just empty. The new Thread dies almost immediately. So all this code is useless.
Still pursuing on the EDT, you call boolean successfull = xmlWriter.writeCommonSettingsFromGUI(this); (btw, "successful" ends with only one 'l'). This will continue on blocking the EDT, preventing repaints from occurring and preventing the JProgressBar from painting itself. Eventually you will dispose the JFrame but since all this code is running on the EDT, the user will not see much of the progress bar and the UI will look frozen.
Consider reading the Swing tag wiki (especially the very last part with 3 important links).
Using a SwingWorker should help you out in this.

How do I close a JDialog and have the Window Event Listeners be notified?

Is there a way to close a JDialog through code such that the Window event listeners will still be notified? I've tried just setting visible to false and disposing, but neither seem to do it.
Closing a window (with dispose()) and hiding it (with setVisible(false)) are different operations, and produce different events -- and closing it from the operating system is yet another different operation that produces yet a different event.
All three will produce windowDeactivated to tell you the window's lost focus, but dispose() will then produce windowClosed, while closing from the OS will first produce windowClosing. If you want to handle both of these the same way, you can set the window to be disposed when closed:
window.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
In general, setVisible(false) implies that you might want to use the window again, so it doesn't post any window events (apart from windowDeactivated). If you want to detect the hiding of a window, you need to use a ComponentListener;
window.addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent e) {
System.out.println("componentHidden()");
}
})
Note though that this will pretty much only work for explicit setVisible() calls. If you need to detect hiding more generally, you can use a HierarchyListener, but it's probably more trouble than it's worth.
window.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
System.out.println("valid: " + window.isValid());
System.out.println("showing: " + window.isShowing());
}
});
Note that when you dispose a window you'll get a couple of HierarchyEvents, first for hiding and then for invalidation, but when you hide it with setVisible() it's still valid, so you won't get the invalidation.
I don't seem to have your problem. When I use the code below windowDeactivated() is called for either setVisible( false ) or dispose() and windowClosed() is also called for dispose().
ClosingDialog.java:
public class ClosingDialog extends JDialog {
public ClosingDialog(Frame owner, String title, boolean modal) {
super(owner, title, modal);
JPanel contentPanel = (JPanel) this.getContentPane();
JButton setVisButton = new JButton("setVisible( false )");
setVisButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ClosingDialog.this.setVisible(false);
}
});
JButton disposeButton = new JButton("dispose()");
disposeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ClosingDialog.this.dispose();
}
});
contentPanel.setLayout(new FlowLayout());
contentPanel.add(setVisButton);
contentPanel.add(disposeButton);
this.addWindowListener(new WindowListener() {
public void windowActivated(WindowEvent e) {
System.out.println("windowActivated");
}
public void windowClosed(WindowEvent e) {
System.out.println("windowClosed");
}
public void windowClosing(WindowEvent e) {
System.out.println("windowClosing");
}
public void windowDeactivated(WindowEvent e) {
System.out.println("windowDeactivated");
}
public void windowDeiconified(WindowEvent e) {
System.out.println("windowDeiconified");
}
public void windowIconified(WindowEvent e) {
System.out.println("windowIconified");
}
public void windowOpened(WindowEvent e) {
System.out.println("windowOpened");
}
});
this.setSize(300, 300);
}
}
Dispatch a windowClosing event to the Window. Check out the ExitAction example from the Closing an Application entry.
Untested suggestion:
Have you tried getWindowListeners() and then iterating around to fire windowClosed() to each of the WindowListeners?
EDIT: the above suggestion is wrong. Keeping it for posterity.
I'm afraid calling dialog.dispose() works fine for me in my simple example.
I wanted to fire a windowClosing event from the code (just as if the user clicked the X), because I have an extra close button in the JDialog and want the same WindowListener (that I implemented using a WindowAdapter) to be run when the X is clicked and when the button is clicked. Running dispose() only fires windowClosed, not windowClosing, and I want a message to appear before the window is closed, for confirmation. I also didn't manage to fire windowClosing via JDialog's method processWindowEvent since it is protected.
Here is how I got it working though:
WindowAdapter adapter = (WindowAdapter)jdialog.getWindowListeners()[0];
adapter.windowClosing(new WindowEvent((Window)jdialog, WindowEvent.WINDOW_CLOSING));
Hope that helps someone.

Categories

Resources