How to support ctrl + shift+ numpad keys using java.awt - java

I want to associate ctrl + shift + numpad 7 to an action map. Basically I'm trying to bind my actions to keyboard shortcuts and want the same behavior as of the number keys pressed from top or number keypressed from right numbers of keyboard.
I'm able to map
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK), "Ctrl+4");
but cannot map
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK), "Ctrl+4");
Here is the code that I am trying to execute:
package testmaik;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class KeyBindingsTest {
public static void main(String[] args) {
new KeyBindingsTest();
}
public KeyBindingsTest() {
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 {
private JLabel state;
/**
*
*/
public TestPane() {
setLayout(new GridBagLayout());
state = new JLabel("Nothing here");
add(state);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_1, KeyEvent.CTRL_DOWN_MASK), "Ctrl+1");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_2, KeyEvent.CTRL_DOWN_MASK), "Ctrl+2");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD1, KeyEvent.CTRL_DOWN_MASK), "Ctrl+1");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, KeyEvent.CTRL_DOWN_MASK), "Ctrl+2");
im.put(KeyStroke.getKeyStroke("ctrl 7"), "ctrl+7");
im.put(KeyStroke.getKeyStroke("ctrl shift 7"), "Ctrl+3");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK), "Ctrl+4");
ActionMap am = getActionMap();
am.put("Ctrl+1", new MessageAction("Ctrl+1"));
am.put("Ctrl+2", new MessageAction("Ctrl+2"));
am.put("Ctrl+3", new MessageAction("Ctrl+3"));
am.put("ctrl+7", new MessageAction("ctrl+7"));
am.put("Ctrl+4", new MessageAction("Ctrl+4"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public class MessageAction extends AbstractAction {
private String message;
public MessageAction(String message) {
this.message = message;
}
#Override
public void actionPerformed(ActionEvent e) {
state.setText(message);
}
}
}
}
Please help.

An alternate solution: Try this im your TestPane class and you can catch the event itself:
getRootPane().getContentPane().getToolkit().addAWTEventListener(new AWTEventListener() {
public void eventDispatched(final AWTEvent event) {
if (event.getID() == KeyEvent.KEY_PRESSED) {
final KeyEvent keyEvent = (KeyEvent) event;
switch (keyEvent.getKeyCode()) {
case KeyEvent.VK_NUMPAD7:
if(keyEvent.isControlDown() && keyEvent.isShiftDown()) {
//do Stuff
}
break;
}
}
}
}, AWTEvent.KEY_EVENT_MASK);
I am not sure what's wrong with your event map.

Related

How to check that text was selected in Swing?

I have simple JTextField and KeyListener.
JTextField textField = new JTextField();
textField.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e)
{
}
#Override
public void keyPressed(KeyEvent e)
{
}
#Override
public void keyReleased(KeyEvent e)
{
validateThatTextWasSelectedWithShiftAndArrow();
}
});
How do I check that someone select text with key combination (SHIFT + LEFT or RIGHT ARROW) ?
Swing makes heavy use of the Key Bindings API to make it easy to work with existing functionality. We already know the JTextField is fully capable of performing selection, we just need to be able to plug into it.
The JTextField uses the selection-backward and selection-forward to execute the required functionality when the system dependent key strokes are activated, we just need to inject our code into it.
For this, I wrote a simple ReplaceAction action, which takes the old Action we are interested, and calls two methods, one before and one after the old Action is called. This allows you to inject your required functionality into whatever point is required to achieve whatever functionality you are trying to implement...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MonitorSelection {
public static void main(String[] args) {
new MonitorSelection();
}
public MonitorSelection() {
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() {
setLayout(new GridBagLayout());
JTextField field = new JTextField(10);
add(field);
InputMap im = field.getInputMap(WHEN_FOCUSED);
ActionMap am = field.getActionMap();
Action oldAction = am.get("selection-backward");
am.put("selection-backward", new ReplacedAction(oldAction){
#Override
protected void doAfterReplacedAction() {
System.out.println("Before selection-backward");
}
#Override
protected void doBeforeReplacedAction() {
System.out.println("After selection-backward");
}
});
oldAction = am.get("selection-forward");
am.put("selection-forward", new ReplacedAction(oldAction){
#Override
protected void doAfterReplacedAction() {
System.out.println("Before selection-forward");
}
#Override
protected void doBeforeReplacedAction() {
System.out.println("After selection-forward");
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class ReplacedAction extends AbstractAction {
private Action replaced;
public ReplacedAction(Action replaced) {
this.replaced = replaced;
}
#Override
public void actionPerformed(ActionEvent e) {
doBeforeReplacedAction();
replaced.actionPerformed(e);
doAfterReplacedAction();
}
protected void doBeforeReplacedAction() {
}
protected void doAfterReplacedAction() {
}
}
}

Add key bindings to JButtons that get their actions from action commands?

I found a cool way in another question to create a JButton whose actions are written and viewed in an easy way:
public JButton makeToolbarButton(String title, String actionCommand) {
JButton button = new JButton(title);
button.setActionCommand(actionCommand);
button.addActionListener(this);
return button;
}
The class this method is in implements ActionListener, and the buttons commands are assigned by:
public void actionPerformed(ActionEvent e) {
int action = Integer.parseInt(e.getActionCommand());
switch(action) {
case 1:
System.out.println("This button pressed.");
break;
}
}
And the buttons are made by:
JButton button1 = makeToolbarButton("Button 1", "1");
So my question is: can I add KeyStrokes to a button by this method? I tried something like this (inside of the makeToolbarButton method):
button.getInputMap().put(KeyStroke.getKeyStroke("B"), "button_pressed");
button.getActionMap().put("button_pressed", button.getAction());
But I figure this doesn't work because the action command isn't actually assigning an action to a specific button. Is there a way to add something to the makeToolbarButton() method and a parameter for the KeyStroke to accomplish this?
I think you're missing the point of the Action API. A Action is intended to provide a single, self contained, unit of work. This means that the actionCommand really isn't required, as when the actionListener event is triggered, you know exactly the context in which it's been executed
I'd also avoid using KeyStroke.getKeyStroke(String), as the text is a verbose description of what you want to do (ie pressed B or something, but needless to say, it's a pain to get right)
So, the following demonstrates how you might use Actions and assign them to a button AND a key binding
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ActionTest {
public static void main(String[] args) {
new ActionTest();
}
public ActionTest() {
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() {
add(createButton(new ActionOne(), KeyStroke.getKeyStroke(KeyEvent.VK_1, 0)));
add(createButton(new ActionTwo(), KeyStroke.getKeyStroke(KeyEvent.VK_2, 0)));
}
public JButton createButton(Action action, KeyStroke keyStroke) {
JButton btn = new JButton(action);
btn.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "button_pressed");
btn.getActionMap().put("button_pressed", action);
return btn;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
public class ActionOne extends AbstractAction {
public ActionOne() {
putValue(NAME, "1");
putValue(Action.ACTION_COMMAND_KEY, "Action.one");
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
}
public class ActionTwo extends AbstractAction {
public ActionTwo() {
putValue(NAME, "2");
putValue(Action.ACTION_COMMAND_KEY, "Action.two");
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
}
}
See How to Use Actions for more details

Event handlers and loops

I have a full screen window that plays a simple animation, and I want to make it so that when I press any key, the full screen is restored and the program stops.
The key listener class looks like this:
import java.awt.event.*;
public class key implements KeyListener {
private framerun animation=new framerun();
public void keyPressed(KeyEvent e){}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){
animation.x=false;
}
}
The animation runs in a method, run, with a while loop which looks like this:
public void run(DisplayMode dm){
Screen s=new Screen();
s.setFullScreen(dm, this);
while(true){
try{
System.out.println(x);
Thread.sleep(300);
}catch(Exception e){}
if(!x)
s.RestoreScreen();
repaint();
}
}
PS: x is a boolean with initial value true, initiated in the constructor.
This is the main method:
public static void main(String args []){
DisplayMode dm=new DisplayMode(800, 600, 16,DisplayMode.REFRESH_RATE_UNKNOWN);
framerun f=new framerun();
key k=new key();
f.addKeyListener(k);
f.run(dm);
}
Now this works perfectly if there is no while loop. The full screen closes and the program stop. But with the while loop there is no response when I press a key. The value of x doesn't change to false as expected.
Ideas?
I can't get the DisplayMode switching to work, but it shouldn't make a difference.
Basically, KeyListener is fiddly. It requires the component that it is attached to is focusable and has focus.
The following example basically uses a combination of requestFocusInWindow and setFocusable on a JPanel to try and force focus to the JPanel, so that when a key is typed, the JPanel can respond to it...
import java.awt.Dimension;
import java.awt.DisplayMode;
import java.awt.EventQueue;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
private DisplayMode defaultMode;
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
defaultMode = gd.getDisplayMode();
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// DisplayMode dm = new DisplayMode(800, 600, 16, DisplayMode.BIT_DEPTH_MULTI);
// gd.setDisplayMode(dm);
gd.setFullScreenWindow(frame);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setFocusable(true);
setLayout(new GridBagLayout());
add(new JLabel("Test"));
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
requestFocusInWindow();
}
});
addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
try {
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
// gd.setDisplayMode(defaultMode);
gd.setFullScreenWindow(null);
} catch (Throwable exp) {
exp.printStackTrace();
}
SwingUtilities.windowForComponent(TestPane.this).dispose();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Personlly, I'd recommend using the key bindings API, How to Use Key Bindings, but this focuses on binding a single key to a given action, but overcomes the focus issues related to KeyListener

JPopupMenu not showing on the screen?

So for my school project I am creating a Class Diagram maker. I am 95% done with it and all I need is to make the Jpopup menu appear. In the core I have 3 files. The ApplicationModel which extends the JFrame, ClassDiagram which extends the JPanel and ClassModel which makes the Rectangles (in the picture) appear. The core of the rendering is on Rectangle objects and the text inside the middle and bottom rectangles are surrounded by another invisible rectangle, which is right-clickable.
This is what the program looks like (Minus the paint editting)
Now for the file that handles the clicking is DiagramMouseListener, here is the code for it.
package edu.mville.cs.classdiagram;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
public class DiagramMouseListener extends MouseAdapter
{
ClassDiagram diagram;
Field field;
Method method;
int x;
int y;
ClassModel elementBeingDragged;
JPopupMenu fieldPopupMenu = new JPopupMenu();
JPopupMenu methodPopupMenu = new JPopupMenu();
JMenuItem editFieldNameItem;
JMenuItem createFieldItem;
JMenuItem deleteFieldItem;
JMenuItem editMethodNameItem;
JMenuItem createMethodItem;
JMenuItem deleteMethodItem;
public DiagramMouseListener(ClassDiagram diagram) { this.diagram = diagram; }
public void addPopupMenu()
{
editFieldNameItem = new JMenuItem("Edit Field Name");
createFieldItem = new JMenuItem("New Field");
deleteFieldItem = new JMenuItem("Delete Field");
editMethodNameItem = new JMenuItem("Edit Method Name");
createMethodItem = new JMenuItem("New Method");
deleteMethodItem = new JMenuItem("Delete Method");
methodPopupMenu.add(editMethodNameItem);
methodPopupMenu.add(createMethodItem);
methodPopupMenu.add(deleteMethodItem);
fieldPopupMenu.add(editFieldNameItem);
fieldPopupMenu.add(createFieldItem);
fieldPopupMenu.add(deleteFieldItem);
editFieldNameItem.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
}
});
/*
createFieldItem.addActionListener(this);
deleteFieldItem.addActionListener(this);
editMethodNameItem.addActionListener(this);
createMethodItem.addActionListener(this);
deleteMethodItem.addActionListener(this);
*/
}
#Override
public void mouseClicked(MouseEvent me)
{
if(SwingUtilities.isLeftMouseButton(me) && me.getClickCount() == 2)
{
diagram.doubleClick(me.getPoint());
}
}
#Override
public void mousePressed(MouseEvent e)
{
x = e.getX();
y = e.getY();
DiagramElement elt = diagram.containsPoint(e.getPoint());
if (elt instanceof ClassModel)
{
elementBeingDragged = (ClassModel) elt;
}
}
#Override
public void mouseDragged(MouseEvent e)
{
int dx = e.getX() - x;
int dy = e.getY() - y;
if (elementBeingDragged != null)
{
elementBeingDragged.move(dx, dy);
diagram.repaint();
}
x += dx;
y += dy;
}
#Override
public void mouseReleased(MouseEvent me)
{
elementBeingDragged = null;
DiagramElement de = diagram.containsPoint(me.getPoint());
if (SwingUtilities.isRightMouseButton(me) && me.getClickCount() == 1 && de instanceof Field)
{
if (me.isPopupTrigger())
{
System.out.println("it is");
fieldPopupMenu.show(me.getComponent(), me.getX(), me.getY());
}
}
else if (SwingUtilities.isRightMouseButton(me) && me.getClickCount() == 1 && de instanceof Method)
{
if (me.isPopupTrigger())
{
System.out.println("it is");
methodPopupMenu.show(me.getComponent(), me.getX(), me.getY());
}
}
}
}
At line 118 where it says System.out.println("it is"); It successfully displays the text on console, which tells me the code successfully reached that part, but the popup menu is never displayed when I right click the text (which is inside invisible Rectangles separated by 5 pixels of space).
I tried multiple solutions to this problem. I even looked at the oracle tutorials and other user's examples to see what was wrong with my code. But after countless hours of searching, I failed to fix the problem. Any help would be appreciated. Also if you need more information, I will be glad to provide! Thanks.
Several things;
First off, the popup coordinates should be relative to the component you are triggering the popup on, not the screen coordinates. What is happening is, the API is calculating the screen location of the component and adding the x/y values you pass, which is possibly pushing the popup off the screen
fieldPopupMenu.show(me.getComponent(), me.getX(), me.getY());
Secondly, popups can be triggered on different systems by different events. You should be checking for isPopupTrigger in mousePressed, mouseReleased and even mouseClicked.
Lastly, popups can be triggered by different mouse buttons (and even possibly other conditions), so should only need to check isPopupTrigger
Additionally, you could just use JComponent#setComponentPopupMenu
Updated with setComponentPopupMenu example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PopupMenuTest {
public static void main(String[] args) {
new PopupMenuTest();
}
public PopupMenuTest() {
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 {
private JPopupMenu popupMenu;
public TestPane() {
popupMenu = new JPopupMenu();
popupMenu.add(new JMenuItem("Open..."));
popupMenu.add(new JMenuItem("Save..."));
popupMenu.add(new JMenuItem("Close..."));
popupMenu.add(new JMenuItem("Give Blood..."));
popupMenu.add(new JMenuItem("Give Money..."));
setComponentPopupMenu(popupMenu);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Updated with MouseListener example
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PopupMenuTest {
public static void main(String[] args) {
new PopupMenuTest();
}
public PopupMenuTest() {
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 {
private JPopupMenu popupMenu;
public TestPane() {
popupMenu = new JPopupMenu();
popupMenu.add(new JMenuItem("Open..."));
popupMenu.add(new JMenuItem("Save..."));
popupMenu.add(new JMenuItem("Close..."));
popupMenu.add(new JMenuItem("Give Blood..."));
popupMenu.add(new JMenuItem("Give Money..."));
addMouseListener(new MouseAdapter() {
protected void doPopup(MouseEvent evt) {
if (evt.isPopupTrigger()) {
popupMenu.show(evt.getComponent(), evt.getX(), evt.getY());
}
}
#Override
public void mouseClicked(MouseEvent e) {
doPopup(e);
}
#Override
public void mousePressed(MouseEvent e) {
doPopup(e);
}
#Override
public void mouseReleased(MouseEvent e) {
doPopup(e);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}

Detect when user closes floating toolbar frame

Is possible to capture event when user tries to close floating toolbar window in swing?
Thanks in advance.
There's probably some really awesomely simple solution, but why would you use that?
The best I could come up with (without extending out my own tool bar) was to add an AncestorListener to the toolbar and monitor it's events.
The problem I have this approach, though, is you need to know the main frame you were originally attached to, which may not be convenient.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
public class TestFloatingToolBar {
public static void main(String[] args) {
new TestFloatingToolBar();
}
public TestFloatingToolBar() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final JFrame frame = new JFrame("Test");
final JToolBar tb = new JToolBar();
tb.add(new JButton("Pop"));
tb.setFloatable(true);
tb.addAncestorListener(new AncestorListener() {
#Override
public void ancestorAdded(AncestorEvent event) {
tell();
if (SwingUtilities.getWindowAncestor(tb).equals(frame)) {
System.out.println("...In Main Frame");
} else {
System.out.println("...Maybe floating");
}
}
#Override
public void ancestorRemoved(AncestorEvent event) {
tell();
if (SwingUtilities.getWindowAncestor(tb).equals(frame)) {
System.out.println("...In Main Frame");
} else {
System.out.println("...Maybe floating");
}
}
#Override
public void ancestorMoved(AncestorEvent event) {
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(tb, BorderLayout.NORTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public void tell() {
Exception exp = new Exception();
StackTraceElement[] stackTrace = exp.getStackTrace();
System.out.println(stackTrace[1].getMethodName());
}
}

Categories

Resources