简体   繁体   English

WindowListener无法按预期工作

[英]WindowListener does not work as expected

I want my GUI to make some checks when a JOptionPane appears. 我希望我的GUI在出现JOptionPane时进行一些检查。 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: 出于这个原因,我在我的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. 虽然当JFrame没有集中时没有任何反应。 Shouldn't "Focus Lost" be printed each time I switch from JFrame to some other window? 每次从JFrame切换到其他窗口时,是否应该打印“Focus Lost”? Also, will this method be triggered when a JOptionPane is shown? 此外,当显示JOptionPane时是否会触发此方法?

The key to me is that you want a change in the GUI triggered by a change of a String variable. 对我而言,关键在于您希望通过更改String变量触发GUI的更改。 The best way I see to solve this is to make the String variable a bound property by using PropertyChangeListenerSupport. 我看到解决此问题的最佳方法是使用PropertyChangeListenerSupport使String变量成为绑定属性。 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. 通过这种方式,您可以让GUI将PropertyChangeListener附加到包含String变量的类,然后在更改时通知它,从而允许您适当地更新GUI。

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. 如果你走这条路,考虑给观察的类一个SwingPropertyChangeSupport字段,以便在Swing事件线程上通知监听器,并希望避免任何Swing并发问题。

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. 在我看来,所有这一切的关键是使用监听器,以便具有绑定属性的类 - 被监听的字符串 - 不知道GUI,监听器和GUI,同样不知道具有bound属性的类。 They are fully decoupled. 它们完全分离。

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. WindowAdapter是一个便利类,因此您可以创建一个侦听器并为多种类型的事件注册它。 You have only registered it for one set of events, you need to also register it for focus events via: Window.addWindowFocusListener() 您只为一组事件注册了它,您还需要通过以下方式注册焦点事件: 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);

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) 1) JOptionPane / modal JDialog有模态问题,但是如果所有容器都拥有自己的所有者,模态可能是有利的,对于你需要知道的真正的解决方法(我将谈论我该如何测试)

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 2)请充分尊重,我不知道为什么你需要这个,为什么我需要知道的原因,有关于业务规则,你总是需要知道....,如果是在EDT完成

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM