Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Window Focus Listener Event Order

796262Jul 14 2010 — edited Jul 19 2010
Hey all,

The low-level goal: I'm trying to differentiate between when the user brings a JFrame to the front and when the program brings the JFrame to the front. The program should only do a certain action when the WindowEvent was a result of user action.

The low-level attempted solution: Before programatically bringing the JFrame to the front, I remove its WindowFocusListener that detects when the window has been brought to the front via user action. I then bring the window to the front, then re-add the WindowFocusListener.

The low-level problem: WindowEvents are still detected by the WindowFocusListener when I programmatically bring the JFrame to the front, even though I'm removing the listener directly before bringing the JFrame to the front.

The SSCCE:
import java.awt.event.*;*
*import javax.swing.*;

public class DoubleFramesTest {

	WindowFocusListener wflB;

	public DoubleFramesTest(){

		final JFrame frameA = new JFrame("Frame A"){
			@Override
			public void setVisible(boolean visible){
				System.out.println("In setVisible for "  +getTitle()+  ".");
				super.setVisible(visible);
			}
		};
		final JFrame frameB = new JFrame("Frame B"){
			@Override
			public void setVisible(boolean visible){
				System.out.println("In setVisible for "  +getTitle()+  ".");
				super.setVisible(visible);
			}
		};

		frameA.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frameB.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		final WindowFocusListener wflA = new WindowFocusListener(){
			@Override
			public void windowGainedFocus(WindowEvent e) {

				System.out.println("In listener for Frame A.");

				//setting visible should no longer call this focus listener
				System.out.println("Removing listener from Frame B");
				frameB.removeWindowFocusListener(wflB);

				System.out.println("Bringing Frame B to front.");
				frameB.setVisible(true);

				//maybe invoking later will make sure the listener
				//is added after any focus events are done
				try {
					SwingUtilities.invokeLater(new Runnable(){
						public void run(){
							System.out.println("Adding listener to Frame B");
							frameB.addWindowFocusListener(wflB);
						}
					});
				} 
				catch (Exception e1) {
					e1.printStackTrace();
				}
			}
			public void windowLostFocus(WindowEvent e) {}
		};

		wflB = new WindowFocusListener(){
			@Override
			public void windowGainedFocus(WindowEvent e) {
				System.out.println("In listener for Frame B.");
				System.out.println("THIS SHOULD ONLY HAPPEN IF YOU CLICKED FRAME B!\n");
			}
			public void windowLostFocus(WindowEvent e) {}
		};

		frameA.setSize(175, 100);
		frameB.setSize(175, 100);

		frameA.setLocation(100, 100);
		frameB.setLocation(300, 100);

		frameB.setVisible(true);
		frameA.setVisible(true);

		//invoke later so the first setVisible calls
		//are done before the listeners are added
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				//window listener added after visible
				//so it doesn't handle the first show event
				System.out.println("Adding listener to Frame A.");
				frameA.addWindowFocusListener(wflA);
				System.out.println("Adding listener to Frame B.\n");
				frameB.addWindowFocusListener(wflB);
			}
		});
	}

	public static void main(String [] args){
		try {
			SwingUtilities.invokeLater(new Runnable(){
				public void run(){
					new DoubleFramesTest();
				}
			});
		} 
		catch (Exception e) {
			e.printStackTrace();
		}
	}
}
To see the problem: Simply run the program. Click Frame B. You bringing the JFrame to the front is detected, and the resulting action is performed (in this case, simply a print statement). Good so far. Now click Frame A. Frame B is programmatically brought to the front, but its WindowFocusListener is triggered despite being removed! This actually doesn't always happen, but it's almost every time Frame A gains the focus.

I've added some print statements to figure out the order of things, but I still don't understand how the event is being triggered after the WindowFocusListener is removed. I thought it had something to do with events being posted to the EDT after the WindowFocusListener was added, but I thought the invokeLater() would take care of that. No dice.

I appreciate anybody's help on this one. And if there's an easier way to differentiate between user action and program action, I'm all ears.

PS- I'm using setVisible(true) to bring the JFrame to the front instead of toFront() because that's what works in the window manager I'm using (it also seems to work fine in Windows XP). Some OS / window managers apparently treat window front-ness and focus differently, but hopefully this works for anybody trying to take a look.

PPS- I also tried simply setting a boolean before and after programatically bringing the JFrame to the front and checking against it in the JFrame's listener, but I got similar results.




And in case you were curious (skip this part if you aren't, in fact, curious):

The high-level goal: I have multiple programs running in separate JVMs, communicating via a comm port. When the user brings one of the programs' windows to the front, the rest of the programs should send their windows to the front as well. For now, I'm not overly worried about overlap (except where it is exacerbated by the problem below).

The high-level solution: Using a WindowFocusListener, a program detects when its JFrame is brought to the front. It then sends a message via the comm port to the other programs telling them to send their JFrames to the front as well.

The high-level solution detail: When a program receives a signal telling it to bring its window to the front, it does three things:
1- Remove the JFrame's WindowFocusListener responsible for sending messages to the other programs. This is to avoid detecting the window coming to the front based on the signal instead of user action.
2- Call JFrame.setVisible(false) immediately followed by JFrame.setVisible(true). JFrame.toFront() doesn't work on the OS / window manager I'm using, so this is how I'm bringing the windows to the front.
3- Add the JFrame's WindowFocusListener back so that further user action will be detected.

The high-level problem: Despite my removing the WindowFocusListener before bringing a window to the front, the WindowFocusListener is still being triggered due to message-driven (as opposed to user-driven) events. This causes the programs to ping-pong the messages back and forth, effectively crashing all of the programs.
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Aug 16 2010
Added on Jul 14 2010
18 comments
355 views