How to get notifications when the title bar of a window is clicked / clicked

I am working on an auto-dropdown suggestion box (Google for example) using JWindow (not JPopupMenu). My JWindow dropdown is not customizable or modal (the textbox needs to keep focus while the user is typing).

I would like to close the dropdown when the user clicks on the mouse anywhere outside of the dropdown menu or if the application loses focus or is minimized or the escape key is pressed (basically like JPopupMenu).

It works for me , but I can't figure out how to get an event when the user clicks the title bar of the main frame (which causes the main frame to come out before the dropdown).

I am afraid there is no event for this as I am not getting anything from this listener:

Toolkit.getDefaultToolkit().addAWTEventListener(myTestListener, Integer.MAX_VALUE);

      

How does JPOPupMenu achieve this behavior?

EDIT: Added SSCCE:

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

public class SSCCE
{
  public static void main(String[] args) throws Exception
  {
    final JFrame frame = new JFrame();

    JButton button = new JButton("open popup");
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e)
      {
        openPopup(frame);
      }
    });

    frame.setLayout(new FlowLayout());
    frame.add(button);
    frame.setSize(400, 400);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }

  private static void openPopup(JFrame frame)
  {
    final JWindow popupWindow = new JWindow();
    popupWindow.setFocusable(false);
    popupWindow.setSize(400, 400);
    popupWindow.setLocation(frame.getX() + 200, frame.getY() + 200);
    ((JComponent) popupWindow.getContentPane()).setBorder(new MatteBorder(1, 1, 1, 1, Color.RED));
    popupWindow.setVisible(true);

    AWTEventListener awtEventListener = new AWTEventListener() {
      @Override
      public void eventDispatched(AWTEvent e)
      {
        System.out.println(e.toString());

        if(e instanceof MouseEvent
            && ((MouseEvent) e).getID() == MouseEvent.MOUSE_PRESSED //
            || e instanceof FocusEvent
            && ((FocusEvent) e).getID() == FocusEvent.FOCUS_LOST //
            || e instanceof ComponentEvent
            && ((ComponentEvent) e).getID() == ComponentEvent.COMPONENT_MOVED
            && e.getSource() != popupWindow //
            || e instanceof ComponentEvent && ((ComponentEvent) e).getID() == ComponentEvent.COMPONENT_RESIZED
            && e.getSource() != popupWindow//
            || e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_STATE_CHANGED //
            || e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_ACTIVATED //
            || e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_DEACTIVATED //
            || e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_GAINED_FOCUS //
            || e instanceof WindowEvent && ((WindowEvent) e).getID() == WindowEvent.WINDOW_LOST_FOCUS //
            || e instanceof KeyEvent && ((KeyEvent) e).getKeyCode() == KeyEvent.VK_ESCAPE //
        )
        {
          popupWindow.setVisible(false);
          Toolkit.getDefaultToolkit().removeAWTEventListener(this);
        }
      }
    };

    Toolkit.getDefaultToolkit().addAWTEventListener(awtEventListener, 0xFFFFFFFF);
  }
}

      

+3


source to share


3 answers


First, start by looking at the documentation Toolkit#addAWTEventListener

Parameters:
listener - event listener.
eventMask - bitmask of event types to receive

eventMask

is the bit mask of the event ID you want to receive. Ok, this is less impressive, but what does it mean, you have to pass or a registered list of event IDs you are interested in that have been reported ...

Now the question arises, what events are we interested in and how we get the identifier ...

Well, AWTEvent

contains a list of event IDs that work with Toolkit

, AWTEvent.WINDOW_FOCUS_EVENT_MASK

and might even AWTEvent.FOCUS_EVENT_MASK

be useful.



Toolkit.getDefaultToolkit().addAWTEventListener(myTestListener, 
        AWTEvent.WINDOW_FOCUS_EVENT_MASK | 
        AWTEvent.FOCUS_EVENT_MASK);

      

For example...

import java.awt.AWTEvent;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.FocusEvent;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestFocus {

    public static void main(String[] args) {
        new TestFocus();
    }

    public TestFocus() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
                @Override
                public void eventDispatched(AWTEvent event) {
                    if (event instanceof WindowEvent) {
                        System.out.println("WindowEvent");
                        WindowEvent evt = (WindowEvent) event;
                        if (evt.getID() == WindowEvent.WINDOW_GAINED_FOCUS) {
                            System.out.println("I got you babe");
                        } else if (evt.getID() == WindowEvent.WINDOW_LOST_FOCUS) {
                            System.out.println("Don't leave me!");
                        }
                    } else if (event instanceof FocusEvent) {
                        System.out.println("FocusEvent");
                    }
                }
            }, AWTEvent.WINDOW_FOCUS_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
        }

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

    }

}

      

They will tell you when the focus state change occurs, then you will need to check with KeyboardFocusManager#getFocusOwner

and / or KeyboardFocusManager#getGlobalFocusedWindow

to determine if your window has focus or not.

Equally, you can just try KeyboardFocusManager#addPropertyChangeListener

and track changes in KeyboardFocusManager

...

+1


source


If that windowActivated()

doesn't work for you, then as a last resort, you can always set the JFrame as unecorated and create your own title bar. It will no longer look like its native title, but you will have more control, including the ability to add a mouse listener.



myFrame.setUndecorated(true);

      

0


source


Not really an answer to my question, but still an important detail: I forgot to pass my own frame to the JWindow popup constructor. This will at least prevent the popup from hiding behind the main frame when the main frame title button is clicked.

0


source







All Articles