点击 JFrame 窗口外自动关闭窗口

3

我这里有一个相当基础的JFrame,我想让窗口在用户点击窗口外部时自动关闭。是否可以通过某种方式检测到窗口外的点击来使窗口关闭?

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ExampleJFrame {

    public static void main(String[] args) {
        JFrame frame = new JFrame("How can I make this window close when I click outside it?");
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        JLabel jlbempty = new JLabel("");
        jlbempty.setPreferredSize(new Dimension(200, 200));
        frame.getContentPane().add(jlbempty, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);
    }
}

1
希望这与我的问题相关:https://dev59.com/iVbTa4cB1Zd3GeqP-F4z - Anderson Green
实际上,那个问题包含了你所需要的确切答案... - Radu Murzea
这种方法并不适用于所有情况,但是你可以在框架失去焦点后关闭它。 - Name
一旦检测到失去焦点,关闭窗口就很容易了。 - John Dvorak
2
自动关闭JFrame窗口,当点击窗口外部时。请问为什么?这不是一个非常用户友好的设计。 - David Kroukamp
@DavidKroukamp 我正在尝试创建一个右键上下文菜单,当用户在上下文菜单外单击时自动关闭 - 这就是上下文菜单应该表现的方式。我计划在另一个使用node-webkit编写的应用程序中使用此上下文菜单。 - Anderson Green
1个回答

9
检测框外的点击很困难,因为它可能是任何Java无法访问的其他应用程序上的点击。
您可以尝试使用下面所示的FocusListener
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

public class AutoCloseFrameDemo {
  public static void main( String[] args ) {
    final JFrame frame = new JFrame( "Test" );
    frame.addFocusListener( new FocusListener() {
      private boolean gained = false;
      @Override
      public void focusGained( FocusEvent e ) {
        gained = true;
      }

      @Override
      public void focusLost( FocusEvent e ) {
        if ( gained ){
          frame.dispose();
        }
      }
    } );
    frame.add( new JLabel( "testlabel" ) );

    frame.pack();
    frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
    frame.setVisible( true );
  }
}

这对于这个简单的用例可以工作。但是如果您将例如JTextField放入框架中并且文本字段获得焦点,还不确定会发生什么。如果这导致JFrame也失去焦点,那么您的应用程序将变得无用。 编辑 一个更加健壮的解决方案可能是将监听器附加到KeyboardFocusManager
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
import java.awt.BorderLayout;
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;

public class AutoCloseFrameDemo {
  public static void main( String[] args ) {
    final JFrame frame = new JFrame( "Test" );

    KeyboardFocusManager.getCurrentKeyboardFocusManager().
        addVetoableChangeListener( "focusedWindow",
                                   new VetoableChangeListener() {
                                     private boolean gained = false;

                                     @Override
                                     public void vetoableChange( PropertyChangeEvent evt ) throws PropertyVetoException {
                                       if ( evt.getNewValue() == frame ) {
                                         gained = true;
                                       }
                                       if ( gained && evt.getNewValue() != frame ) {
                                         frame.dispose();
                                       }
                                     }
                                   } );

    frame.add( new JTextField( 10 ), BorderLayout.NORTH );
    frame.add( new JTextField( 10 ), BorderLayout.SOUTH );

    frame.pack();
    frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
    frame.setVisible( true );
  }
}

这样可以在框架中不同的文本字段之间切换焦点。


1
您可以使用 WindowListener#windowDeactivated 或 WindowFocusListener#windowLostFocus。 - MadProgrammer
@MadProgrammer 是的,我同意,但是当你拥有JDialog时必须要小心(无论如何,你都必须小心FocusListener)。 - Guillaume Polet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接