WindowListener does not work as expected

为君一笑 提交于 2019-12-03 18:11:30

问题


I want my GUI to make some checks when a JOptionPane appears. Because I can't find any other way, I though I can do those each time the application window loses focus(its just checking a string). For that reason I added the following code on my JFrame:

appFrame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowLostFocus(WindowEvent e) {
                System.out.println("Focus Lost");

            }
            @Override
            public void windowClosing(WindowEvent e) {
                //some other stuff here that work
            }
});

The window closing listener works fine. Although when the JFrame isn't focused nothing happens. Shouldn't "Focus Lost" be printed each time I switch from JFrame to some other window? Also, will this method be triggered when a JOptionPane is shown?


回答1:


I'm not going to go into why you are doing what you are doing, but it is not working as you expect for the following reason:

WindowAdapter is a convenience class so you can create one listener and register it for multiple types of events. You have only registered it for one set of events, you need to also register it for focus events via: Window.addWindowFocusListener()

WindowAdapter adapter = new WindowAdapter() {
        @Override
        public void windowLostFocus(WindowEvent e) {
            System.out.println("Focus Lost");
        }
        @Override
        public void windowClosing(WindowEvent e) {
            //some other stuff here that work
        }
    };
appFrame.addWindowListener(adapter);
appFrame.addWindowFocusListener(adapter);



回答2:


The key to me is that you want a change in the GUI triggered by a change of a String variable. The best way I see to solve this is to make the String variable a bound property by using PropertyChangeListenerSupport. This way you can have the GUI attach a PropertyChangeListener to the class that holds the String variable and then be notified when it changes allowing you to update the GUI appropriately.

If you go this route, consider giving the observed class a SwingPropertyChangeSupport field so that the listeners will be notified on the Swing event thread and hopefully avoid any Swing concurrency issues.

Here's a brief example:

import java.awt.Dimension;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;

public class ShowPropertyChangeSupport {
   @SuppressWarnings("serial")
   private static void createAndShowGui() {
      final MainGUI mainGui = new MainGUI("Title");
      final ObservedClass observedClass = new ObservedClass();
      observedClass.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {
            if (pcEvt.getPropertyName().equals(ObservedClass.BOUND_PROPERTY)) {
               mainGui.setTitle(pcEvt.getNewValue().toString());
            }
         }
      });

      mainGui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      mainGui.pack();
      mainGui.setLocationRelativeTo(null);
      mainGui.setVisible(true);

      int timerDelay = 6000; // every 6 seconds
      new Timer(timerDelay, new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent arg0) {
            String result = JOptionPane.showInputDialog(mainGui,
                  "Please enter a String", "Set GUI title", JOptionPane.PLAIN_MESSAGE);
            if (result != null) {
               observedClass.setBoundProperty(result);
            }
         }
      }){{setInitialDelay(1000);}}.start();
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

// ** note that I don't like extending JFrame,
// but will do this for sake of example simplicity
class MainGUI extends JFrame {
   public MainGUI(String title) {
      super(title);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(400, 300);
   }

}

class ObservedClass {
   public static final String BOUND_PROPERTY = "bound property";
   private String boundProperty = "";
   private SwingPropertyChangeSupport spcSupport = new SwingPropertyChangeSupport(
         this);

   public SwingPropertyChangeSupport getSpcSupport() {
      return spcSupport;
   }

   public void setSpcSupport(SwingPropertyChangeSupport spcSupport) {
      this.spcSupport = spcSupport;
   }

   public String getBoundProperty() {
      return boundProperty;
   }

   public void setBoundProperty(String boundProperty) {
      String oldValue = this.boundProperty;
      String newValue = boundProperty;
      this.boundProperty = newValue;
      spcSupport.firePropertyChange(BOUND_PROPERTY, oldValue, newValue);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      spcSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      spcSupport.removePropertyChangeListener(listener);
   }

}

The key to all this in my mind is to use the listener so that the class with the bound property -- the String being listened to -- has no knowledge of the GUI, the listener, and the GUI, likewise has no knowledge of the class with the bound property. They are fully decoupled.




回答3:


1) JOptionPane / modal JDialog have got modality issue, but modality could be advantage if all containers have got own owner, for real workaround you need to know (I'll talking about how can I do test that)

  • numbers of Window[], and if isDisplayable(), then you can use follows

  • you can get SwingUtilities#getAccessibleIndexInXxx can returns AccessibleState

  • KeyboardFocusManager (very interesting methods for multi-touch) returns getXxxFocusXxx methods

  • Focus, FocusSubsystem is pretty asynchronous,

2) Please, with due respect, I don't know why you needed that, for why reasons I need to know about that, there is about business rules, you always need to know ...., and if is done on EDT

  • Focus, FocusSubsystem is pretty asynchronous,


来源:https://stackoverflow.com/questions/10198936/windowlistener-does-not-work-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!