I'm currently working on my first GUI program, and there's one issue I do not know how to solve - I've provided a minimal (non-compilable) example below.
The problem is that, in some cases, if the delete key is pressed shortly after the mouse click which should change activeElement, the key action is executed before activeElement has been changed to the new value. How can I ensure that the code in actionPerformed waits for activeElement to be changed by mouseClicked?
public class Problem extends JPanel implements MouseListener{
Element activeElement = null;
public Problem(){
super();
this.addMouseListener(this);
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,0),"test");
am.put("test",new AbstractAction(){
#Override
public void actionPerformed(ActionEvent ae){
if(activeElement!=null){
doSomethingWith(activeElement);
repaint();
}
}
});
}
#Override
public void mouseClicked(MouseEvent me){
activeElement = getElementByCoordinates(me.getX(),me.getY());
}
private Element getElementByCoordinates(int x, int y){
[...]
}
private void doSomethingWith(Element e){
[...]
}
}
mouseClicked is called after you have pressed and the released the mouse in (nearly) the same location. If you type your key before releasing the mouse, the InputMap will be triggered before mouseClicked is called.
To register a mouse press before the key is pressed, regardless of whether the mouse button has been released, place your code in mousePressed rather than mouseClicked.
Related
How would I programmatically click a Swing JButton in a way that would register all the relevant action/mouse events and be visible to the user (i.e. they'd see the button being pressed as if they actually clicked it)?
The button is in the same application I'm running; I'm not trying to control a button in another application. I suppose I could directly inject events into the queue, but I'd prefer to avoid that approach if possible, and doing it that way wouldn't show a visible click.
I see the java.awt.Robot class offers methods to move the mouse and click the mouse, but not to make it click a particular button.
Have you tried using doClick()?
If doClick() is not what you want, you can move the mouse really to the button and press it:
public void click(AbstractButton button, int millis) throws AWTException
{
Point p = button.getLocationOnScreen();
Robot r = new Robot();
r.mouseMove(p.x + button.getWidth() / 2, p.y + button.getHeight() / 2);
r.mousePress(InputEvent.BUTTON1_MASK);
try { Thread.sleep(millis); } catch (Exception e) {}
r.mouseRelease(InputEvent.BUTTON1_MASK);
}
Even though the asker was satisfied with button.doClick(), I was looking for something like what happens after setting a mnemonic, i.e. with button.setMnemonic(KeyEvent.VK_A). You can actually hold down ALT + A without anything happening (except the visual change). And upon release of the key A (with or without ALT), the button fires an ActionEvent.
I found that I can get the ButtonModel (see Java 8 API) with button.getModel(), then visually press the button with model.setPressed(true); model.setArmed(true); (both are changed by mnemonics), and visually release the button by setting both to false. And when model.setPressed(false) is called while the button is both pressed and armed, the button fires an ActionEvent automatically (calling model.setArmed(false) only changes the button visually).
[Quote from ButtonModel Java API documentation]
A button is triggered, and an ActionEvent is fired, when the mouse is released while the model is armed [...]
To make the application react to key presses when the button is visible (without the containing window or the button needing to be the focus owner, i.e. when another component in the window is focussed) I used key bindings (see the Official Java Tutorial).
Working code: Press SHIFT + A to visually press the button (in contrast to pressing ALT with the key after the mnemonic is set with button.setMnemonic()). And release the key to print the action command ("button") on the console.
// MnemonicCode.java
import javax.swing.*;
import java.awt.event.*;
public class MnemonicCode extends JFrame
{
public MnemonicCode(int keyCode)
{
JButton button = new JButton("button");
getContentPane().add(button);
addMnemonicToButton(button,keyCode);
button.addActionListener(new ActionListener () {
public void actionPerformed(ActionEvent e)
{
System.out.println(e.getActionCommand());
}
});
pack();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) throws Exception
{
MnemonicCode bp = new MnemonicCode(KeyEvent.VK_A);
}
void addMnemonicToButton(JButton button,int keyCode)
{
int shiftMask = InputEvent.SHIFT_DOWN_MASK;
// signature: getKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)
KeyStroke keyPress = KeyStroke.getKeyStroke(keyCode,shiftMask,false);
KeyStroke keyReleaseWithShift = KeyStroke.getKeyStroke(keyCode,shiftMask,true);
// get maps for key bindings
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = button.getActionMap();
// add key bindings for pressing and releasing the button
inputMap.put(keyPress,"press"+keyCode);
actionMap.put("press"+keyCode, new ButtonPress(button));
inputMap.put(keyReleaseWithShift,"releaseWithShift"+keyCode);
actionMap.put("releaseWithShift"+keyCode, new ButtonRelease(button));
///*
// add key binding for releasing SHIFT before A
// if you use more than one modifier it gets really messy
KeyStroke keyReleaseAfterShift = KeyStroke.getKeyStroke(keyCode,0,true);
inputMap.put(keyReleaseAfterShift,"releaseAfterShift"+keyCode);
actionMap.put("releaseAfterShift"+keyCode, new ButtonRelease(button));
//*/
}
class ButtonPress extends AbstractAction
{
private JButton button;
private ButtonModel model;
ButtonPress(JButton button)
{
this.button = button;
this.model = button.getModel();
}
public void actionPerformed(ActionEvent e)
{
// visually press the button
model.setPressed(true);
model.setArmed(true);
button.requestFocusInWindow();
}
}
class ButtonRelease extends AbstractAction
{
private ButtonModel model;
ButtonRelease(JButton button)
{
this.model = button.getModel();
}
public void actionPerformed(ActionEvent e)
{
if (model.isPressed()) {
// visually release the button
// setPressed(false) also makes the button fire an ActionEvent
model.setPressed(false);
model.setArmed(false);
}
}
}
}
You could always simulate it by firing an action event with it as the source.
http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionEvent.html
To fire it, create the action event above, and whatever listener you want just call
ActionEvent e = new ActionEvent(myButton,1234,"CommandToPeform");
myListener.actionPerformed(e);
From: http://download.oracle.com/javase/6/docs/api/javax/swing/JButton.html
/**
* Click a button on screen
*
* #param button Button to click
* #param millis Time that button will remain "clicked" in milliseconds
*/
public void click(AbstractButton button, int millis) {
b.doClick(millis);
}
Based on #Courteaux's answer, this method clicks the first cell in a JTable:
private void clickFirstCell() {
try {
jTable1.changeSelection(0, 0, false, false);
Point p = jTable1.getLocationOnScreen();
Rectangle cellRect = jTable1.getCellRect(0, 0, true);
Robot r = new Robot();
Point mouse = MouseInfo.getPointerInfo().getLocation();
r.mouseMove(p.x + cellRect.x + cellRect.width / 2,
p.y + cellRect.y + cellRect.height / 2);
r.mousePress(InputEvent.BUTTON1_MASK);
try {
Thread.sleep(50);
} catch (Exception e) {
}
r.mouseRelease(InputEvent.BUTTON1_MASK);
r.mouseMove(mouse.x, mouse.y);
} catch (AWTException ex) {
}
}
How would I programmatically click a Swing JButton in a way that would register all the relevant action/mouse events and be visible to the user (i.e. they'd see the button being pressed as if they actually clicked it)?
The button is in the same application I'm running; I'm not trying to control a button in another application. I suppose I could directly inject events into the queue, but I'd prefer to avoid that approach if possible, and doing it that way wouldn't show a visible click.
I see the java.awt.Robot class offers methods to move the mouse and click the mouse, but not to make it click a particular button.
Have you tried using doClick()?
If doClick() is not what you want, you can move the mouse really to the button and press it:
public void click(AbstractButton button, int millis) throws AWTException
{
Point p = button.getLocationOnScreen();
Robot r = new Robot();
r.mouseMove(p.x + button.getWidth() / 2, p.y + button.getHeight() / 2);
r.mousePress(InputEvent.BUTTON1_MASK);
try { Thread.sleep(millis); } catch (Exception e) {}
r.mouseRelease(InputEvent.BUTTON1_MASK);
}
Even though the asker was satisfied with button.doClick(), I was looking for something like what happens after setting a mnemonic, i.e. with button.setMnemonic(KeyEvent.VK_A). You can actually hold down ALT + A without anything happening (except the visual change). And upon release of the key A (with or without ALT), the button fires an ActionEvent.
I found that I can get the ButtonModel (see Java 8 API) with button.getModel(), then visually press the button with model.setPressed(true); model.setArmed(true); (both are changed by mnemonics), and visually release the button by setting both to false. And when model.setPressed(false) is called while the button is both pressed and armed, the button fires an ActionEvent automatically (calling model.setArmed(false) only changes the button visually).
[Quote from ButtonModel Java API documentation]
A button is triggered, and an ActionEvent is fired, when the mouse is released while the model is armed [...]
To make the application react to key presses when the button is visible (without the containing window or the button needing to be the focus owner, i.e. when another component in the window is focussed) I used key bindings (see the Official Java Tutorial).
Working code: Press SHIFT + A to visually press the button (in contrast to pressing ALT with the key after the mnemonic is set with button.setMnemonic()). And release the key to print the action command ("button") on the console.
// MnemonicCode.java
import javax.swing.*;
import java.awt.event.*;
public class MnemonicCode extends JFrame
{
public MnemonicCode(int keyCode)
{
JButton button = new JButton("button");
getContentPane().add(button);
addMnemonicToButton(button,keyCode);
button.addActionListener(new ActionListener () {
public void actionPerformed(ActionEvent e)
{
System.out.println(e.getActionCommand());
}
});
pack();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) throws Exception
{
MnemonicCode bp = new MnemonicCode(KeyEvent.VK_A);
}
void addMnemonicToButton(JButton button,int keyCode)
{
int shiftMask = InputEvent.SHIFT_DOWN_MASK;
// signature: getKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)
KeyStroke keyPress = KeyStroke.getKeyStroke(keyCode,shiftMask,false);
KeyStroke keyReleaseWithShift = KeyStroke.getKeyStroke(keyCode,shiftMask,true);
// get maps for key bindings
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = button.getActionMap();
// add key bindings for pressing and releasing the button
inputMap.put(keyPress,"press"+keyCode);
actionMap.put("press"+keyCode, new ButtonPress(button));
inputMap.put(keyReleaseWithShift,"releaseWithShift"+keyCode);
actionMap.put("releaseWithShift"+keyCode, new ButtonRelease(button));
///*
// add key binding for releasing SHIFT before A
// if you use more than one modifier it gets really messy
KeyStroke keyReleaseAfterShift = KeyStroke.getKeyStroke(keyCode,0,true);
inputMap.put(keyReleaseAfterShift,"releaseAfterShift"+keyCode);
actionMap.put("releaseAfterShift"+keyCode, new ButtonRelease(button));
//*/
}
class ButtonPress extends AbstractAction
{
private JButton button;
private ButtonModel model;
ButtonPress(JButton button)
{
this.button = button;
this.model = button.getModel();
}
public void actionPerformed(ActionEvent e)
{
// visually press the button
model.setPressed(true);
model.setArmed(true);
button.requestFocusInWindow();
}
}
class ButtonRelease extends AbstractAction
{
private ButtonModel model;
ButtonRelease(JButton button)
{
this.model = button.getModel();
}
public void actionPerformed(ActionEvent e)
{
if (model.isPressed()) {
// visually release the button
// setPressed(false) also makes the button fire an ActionEvent
model.setPressed(false);
model.setArmed(false);
}
}
}
}
You could always simulate it by firing an action event with it as the source.
http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionEvent.html
To fire it, create the action event above, and whatever listener you want just call
ActionEvent e = new ActionEvent(myButton,1234,"CommandToPeform");
myListener.actionPerformed(e);
From: http://download.oracle.com/javase/6/docs/api/javax/swing/JButton.html
/**
* Click a button on screen
*
* #param button Button to click
* #param millis Time that button will remain "clicked" in milliseconds
*/
public void click(AbstractButton button, int millis) {
b.doClick(millis);
}
Based on #Courteaux's answer, this method clicks the first cell in a JTable:
private void clickFirstCell() {
try {
jTable1.changeSelection(0, 0, false, false);
Point p = jTable1.getLocationOnScreen();
Rectangle cellRect = jTable1.getCellRect(0, 0, true);
Robot r = new Robot();
Point mouse = MouseInfo.getPointerInfo().getLocation();
r.mouseMove(p.x + cellRect.x + cellRect.width / 2,
p.y + cellRect.y + cellRect.height / 2);
r.mousePress(InputEvent.BUTTON1_MASK);
try {
Thread.sleep(50);
} catch (Exception e) {
}
r.mouseRelease(InputEvent.BUTTON1_MASK);
r.mouseMove(mouse.x, mouse.y);
} catch (AWTException ex) {
}
}
In my animation one of elements is moving oval. There are two ways to control it. The first is setting x,y position by mouse listener and the second is Key Listener. During first using animation both methods work. But after using stop (clear) button mouse listener doesn't work, but Key method is still working.
Code stop method:
void clear() {
waves.clear();
xz_list.clear();
yz_list.clear();
time_list.clear();
f_list.clear();
time=0;
timer.stop();
repaint();
}
MouseListener method:
void SourcePosition(double v, String d) {
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
{
x_o = e.getX();
y_o = e.getY();
repaint();
}
}
});
}
Generally this is application showing Doppler Effect. Start button make setting data from interface, disable interface and start animation and chart. Stop button uses clear() method and enable interface.
I'm trying to get the mouse position while pressing the mouse button but it doesn't work.
I'm extending the MouseAdapter and as stated at the Javadoc the mouseMove() is invoked when the mouse cursor has been moved onto a component but no buttons have been pushed.
This is an example class I have created to show you my problem:
public class TestMouse extends MouseAdapter{
int x,y;
boolean pressed;
public void mousePressed(MouseEvent e){
pressed = true;
}
public void mouseReleased(MouseEvent e){
pressed = false;
}
/*
Invoked when the mouse is not pressed only.
*/
public void mouseMoved(MouseEvent e){
x = e.getX();
y = e.getY();
}
/*
I want something like that.
*/
public void mousePressedAndMoved(MouseEvent e){
....
}
}
That's the problem with MouseAdapter, since it's a abstract class and not an interface (MouseMotionListener is the one you need), it gives empty implementations for all the possible events just to avoid you from being forced to override them all, this also implies that you could miss some of these events if you don't read docs.
If you look carefully at documentation though, you will see that you have
public void mouseDragged(MouseEvent e)
that you can override to listen exactly to what you need.
How would I programmatically click a Swing JButton in a way that would register all the relevant action/mouse events and be visible to the user (i.e. they'd see the button being pressed as if they actually clicked it)?
The button is in the same application I'm running; I'm not trying to control a button in another application. I suppose I could directly inject events into the queue, but I'd prefer to avoid that approach if possible, and doing it that way wouldn't show a visible click.
I see the java.awt.Robot class offers methods to move the mouse and click the mouse, but not to make it click a particular button.
Have you tried using doClick()?
If doClick() is not what you want, you can move the mouse really to the button and press it:
public void click(AbstractButton button, int millis) throws AWTException
{
Point p = button.getLocationOnScreen();
Robot r = new Robot();
r.mouseMove(p.x + button.getWidth() / 2, p.y + button.getHeight() / 2);
r.mousePress(InputEvent.BUTTON1_MASK);
try { Thread.sleep(millis); } catch (Exception e) {}
r.mouseRelease(InputEvent.BUTTON1_MASK);
}
Even though the asker was satisfied with button.doClick(), I was looking for something like what happens after setting a mnemonic, i.e. with button.setMnemonic(KeyEvent.VK_A). You can actually hold down ALT + A without anything happening (except the visual change). And upon release of the key A (with or without ALT), the button fires an ActionEvent.
I found that I can get the ButtonModel (see Java 8 API) with button.getModel(), then visually press the button with model.setPressed(true); model.setArmed(true); (both are changed by mnemonics), and visually release the button by setting both to false. And when model.setPressed(false) is called while the button is both pressed and armed, the button fires an ActionEvent automatically (calling model.setArmed(false) only changes the button visually).
[Quote from ButtonModel Java API documentation]
A button is triggered, and an ActionEvent is fired, when the mouse is released while the model is armed [...]
To make the application react to key presses when the button is visible (without the containing window or the button needing to be the focus owner, i.e. when another component in the window is focussed) I used key bindings (see the Official Java Tutorial).
Working code: Press SHIFT + A to visually press the button (in contrast to pressing ALT with the key after the mnemonic is set with button.setMnemonic()). And release the key to print the action command ("button") on the console.
// MnemonicCode.java
import javax.swing.*;
import java.awt.event.*;
public class MnemonicCode extends JFrame
{
public MnemonicCode(int keyCode)
{
JButton button = new JButton("button");
getContentPane().add(button);
addMnemonicToButton(button,keyCode);
button.addActionListener(new ActionListener () {
public void actionPerformed(ActionEvent e)
{
System.out.println(e.getActionCommand());
}
});
pack();
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) throws Exception
{
MnemonicCode bp = new MnemonicCode(KeyEvent.VK_A);
}
void addMnemonicToButton(JButton button,int keyCode)
{
int shiftMask = InputEvent.SHIFT_DOWN_MASK;
// signature: getKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)
KeyStroke keyPress = KeyStroke.getKeyStroke(keyCode,shiftMask,false);
KeyStroke keyReleaseWithShift = KeyStroke.getKeyStroke(keyCode,shiftMask,true);
// get maps for key bindings
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = button.getActionMap();
// add key bindings for pressing and releasing the button
inputMap.put(keyPress,"press"+keyCode);
actionMap.put("press"+keyCode, new ButtonPress(button));
inputMap.put(keyReleaseWithShift,"releaseWithShift"+keyCode);
actionMap.put("releaseWithShift"+keyCode, new ButtonRelease(button));
///*
// add key binding for releasing SHIFT before A
// if you use more than one modifier it gets really messy
KeyStroke keyReleaseAfterShift = KeyStroke.getKeyStroke(keyCode,0,true);
inputMap.put(keyReleaseAfterShift,"releaseAfterShift"+keyCode);
actionMap.put("releaseAfterShift"+keyCode, new ButtonRelease(button));
//*/
}
class ButtonPress extends AbstractAction
{
private JButton button;
private ButtonModel model;
ButtonPress(JButton button)
{
this.button = button;
this.model = button.getModel();
}
public void actionPerformed(ActionEvent e)
{
// visually press the button
model.setPressed(true);
model.setArmed(true);
button.requestFocusInWindow();
}
}
class ButtonRelease extends AbstractAction
{
private ButtonModel model;
ButtonRelease(JButton button)
{
this.model = button.getModel();
}
public void actionPerformed(ActionEvent e)
{
if (model.isPressed()) {
// visually release the button
// setPressed(false) also makes the button fire an ActionEvent
model.setPressed(false);
model.setArmed(false);
}
}
}
}
You could always simulate it by firing an action event with it as the source.
http://download.oracle.com/javase/6/docs/api/java/awt/event/ActionEvent.html
To fire it, create the action event above, and whatever listener you want just call
ActionEvent e = new ActionEvent(myButton,1234,"CommandToPeform");
myListener.actionPerformed(e);
From: http://download.oracle.com/javase/6/docs/api/javax/swing/JButton.html
/**
* Click a button on screen
*
* #param button Button to click
* #param millis Time that button will remain "clicked" in milliseconds
*/
public void click(AbstractButton button, int millis) {
b.doClick(millis);
}
Based on #Courteaux's answer, this method clicks the first cell in a JTable:
private void clickFirstCell() {
try {
jTable1.changeSelection(0, 0, false, false);
Point p = jTable1.getLocationOnScreen();
Rectangle cellRect = jTable1.getCellRect(0, 0, true);
Robot r = new Robot();
Point mouse = MouseInfo.getPointerInfo().getLocation();
r.mouseMove(p.x + cellRect.x + cellRect.width / 2,
p.y + cellRect.y + cellRect.height / 2);
r.mousePress(InputEvent.BUTTON1_MASK);
try {
Thread.sleep(50);
} catch (Exception e) {
}
r.mouseRelease(InputEvent.BUTTON1_MASK);
r.mouseMove(mouse.x, mouse.y);
} catch (AWTException ex) {
}
}