I am making a macro program. While CTRL mode is on, the program registers the mouse coordinates when the user clicks. CTRL mode is activated when "CTRL" is pressed and deactivated when it's pressed again. If deactivated, the program asks "Perform actions?" If the response is yes, the program click on the registered coordinates.
I am now trying to make the program write if the user wrote something on CTRL mode. Is this possible? If so, how?
Edit: My explanation was poor so i decided to add an example.
EXAMPLE
I active CTRL mode. Then click on notepad and write "hello". Then I deactivate CTRL and run the actions. The program would click on notepad and write "hello".
I don't think you need this but here is the code:
public class Gui extends JFrame {
private JPanel mousePanel;
private JLabel statusBar;
private JLabel keyBar;
public boolean ctrl;
List<Integer> xList = new ArrayList<Integer>();
List<Integer> yList = new ArrayList<Integer>();
List<KeyEvent> charTyped = new ArrayList<KeyEvent>();
public int[] x;
public int[] y;
public Gui() {
super("Program");
mousePanel = new JPanel();
mousePanel.setBackground(Color.WHITE);
add(mousePanel, BorderLayout.CENTER);
statusBar = new JLabel("No events");
keyBar = new JLabel("No key events");
add(keyBar, BorderLayout.NORTH);;
add(statusBar, BorderLayout.SOUTH);
HandlerClass handler = new HandlerClass();
mousePanel.addMouseListener(handler);
mousePanel.addMouseMotionListener(handler);
this.addKeyListener(handler);
}
public void Click(int x, int y) throws AWTException {
Robot bot = new Robot();
bot.mouseMove(x, y);
bot.mousePress(InputEvent.BUTTON1_MASK);
bot.mouseRelease(InputEvent.BUTTON1_MASK);
}
private class HandlerClass implements MouseListener, MouseMotionListener, KeyListener {
//Mouse Listener
public void mouseClicked(MouseEvent event) {
statusBar.setText(String.format("Clicked at %d, %d", event.getX(), event.getY()));
if(ctrl) {
xList.add(MouseInfo.getPointerInfo().getLocation().x);
yList.add(MouseInfo.getPointerInfo().getLocation().y);
}
}
public void mousePressed(MouseEvent event) {
statusBar.setText(String.format("You are pressing the mouse at %d, %d", event.getX(), event.getY()));
}
public void mouseReleased(MouseEvent event) {
statusBar.setText(String.format("Released at %d, %d", event.getX(), event.getY()));
}
public void mouseEntered(MouseEvent event) {
statusBar.setText(String.format("Mouse entered at %d, %d", event.getX(), event.getY()));
mousePanel.setBackground(Color.RED);
}
public void mouseExited(MouseEvent event) {
statusBar.setText(String.format("Mouse exited at %d, %d", event.getX(), event.getY()));
mousePanel.setBackground(Color.WHITE);
}
//Mouse Motion
public void mouseDragged(MouseEvent event) {
statusBar.setText(String.format("Dragging mouse at %d, %d", event.getX(), event.getY()));
}
public void mouseMoved(MouseEvent event) {
statusBar.setText(String.format("Moving mouse at %d, %d", event.getX(), event.getY()));
}
//Key Listener
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == e.VK_CONTROL && !(ctrl)){
keyBar.setText("CTRL ON");
ctrl = true;
}
else if(e.getKeyCode() == e.VK_CONTROL && ctrl) {
keyBar.setText("CTRL OFF");
ctrl = false;
if(JOptionPane.showOptionDialog(null, "Perform actions?", "", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, null, null) == JOptionPane.YES_OPTION) {
int index = 0;
for(int actionX : xList) {
try {
Click(actionX, yList.get(index));
} catch (AWTException e1) {
e1.printStackTrace();
}
index++;
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
}
On seeing your latest edit, this is probably what you're looking for.
I deleted the other content in my post since I kept getting comments on the old stuff.
Related
If I want to do an action, if a button is pressed I can use a ActionListener. But now if I want to activate more buttons by keeping the mousebutton pressed.
How can I implement this?
Thanks
Add a ChangeListener to the buttons ButtonModel, monitor for a change to the isPressed state.
The trick then is setting up some process which can then add the other components, in this simple example, I've used a Swing Timer, which will add roughly 40 new components a second while the button is pressed
public class TestPane extends JPanel {
private Timer timer = new Timer(25, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
add(new JButton("..."));
revalidate();
repaint();
}
});
public TestPane() {
JButton btn = new JButton("Help");
btn.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
ButtonModel model = (ButtonModel) e.getSource();
if (model.isPressed()) {
timer.start();
} else {
timer.stop();
}
}
});
add(btn);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
Thanks, this works if I press one Button. But if I press one Button and move the mouse with pressed mousebutton to another Button the secound button does nothing
Just so we're clear, I think this is a bad user experience, but that's me
public class Test {
public static void main(String[] args) {
new Test();
}
private boolean pressed = false;
public Test() {
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(makeButton("1"));
add(makeButton("2"));
}
protected JButton makeButton(String text) {
JButton btn = new JButton(text);
MouseAdapter ma = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
pressed = true;
}
#Override
public void mouseReleased(MouseEvent e) {
pressed = false;
}
#Override
public void mouseEntered(MouseEvent e) {
if (pressed) {
JButton btn = (JButton) e.getComponent();
System.out.println("Entered " + btn.getText());
btn.doClick();
}
}
};
btn.addMouseListener(ma);
btn.addMouseMotionListener(ma);
return btn;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
#npinti Now I can do an action for every button over which i hover with my mouse. But if I try to change the implementation, so that the action are only done, if the mouse is also clicked, the action only works if i press a button and over the same button again. `JButton b = new JButton();
if(a==1){
b.setBackground(Color.WHITE);
}else{
b.setBackground(Color.BLACK);
}
b.addActionListener( new ActionListener(){
public void actionPerformed( ActionEvent arg0 ) {
matrix.activate(x,y);
}
});
b.addMouseListener(new MouseListener() {
int pressed =0;
#Override
public void mouseReleased(MouseEvent e) {
pressed =0;
}
#Override
public void mousePressed(MouseEvent e) {
pressed =1;
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
if (e.getComponent().equals(b) && pressed ==1){
b.setBackground(Color.BLACK);
}
}
public void mouseClicked(MouseEvent e) {
pressed =1;
}
});`
Catch mouseEntered on your buttons and if a global boolean pressed is true (set it to true when you press a mouse button and false on release), fire an action with JButton.doClick() which simulates a click event on the button.
Supposedly whenever you press a key, it should access the code, but it doesn't and neither do I or my teacher know why. Here's the code:
class KeyInput implements KeyListener{
Actor player;
Graphics gBuffer;
public KeyInput(Actor player, Graphics gBuffer){
JTextField typingArea = new JTextField(20);
typingArea.addKeyListener(this);
this.player = player;
this.gBuffer = gBuffer;
}
public void keyReleased(KeyEvent e){
}
public void keyTyped(KeyEvent e){
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
player.modActor(1);
gBuffer.drawString("ENTER",150,100);
}
if (key == KeyEvent.VK_RIGHT) {
player.modActor(2);
gBuffer.drawString("ENTER",150,100);
}
if (key == KeyEvent.VK_UP) {
player.modActor(3);
gBuffer.drawString("ENTER",150,100);
}
if (key == KeyEvent.VK_DOWN) {
player.modActor(4);
gBuffer.drawString("ENTER",150,100);
}
}
}
And this is the while that plays during the program:
public void paint(Graphics g){ //main method to be called to play(g);
do{
drawBackground(gBuffer);
gBuffer.setFont(new Font("Calibri",Font.BOLD,20));
gBuffer.setColor(Color.CYAN);
gBuffer.drawString("Score: " + (int)score,18,20);
gBuffer.drawString("Score: " + (int)score,22,20);
gBuffer.drawString("Score: " + (int)score,20,22);
gBuffer.drawString("Score: " + (int)score,20,18);
gBuffer.setColor(Color.BLACK);
gBuffer.drawString("Score: " + (int)score,20,20);
play(gBuffer);
g.drawImage(virtualMem,0,0,this);
if(lose==false){
gBuffer.setFont(new Font("Calibri",Font.BOLD,50));
gBuffer.setColor(Color.CYAN);
gBuffer.drawString("GAME OVER",42,200);
gBuffer.drawString("GAME OVER",38,200);
gBuffer.drawString("GAME OVER",40,202);
gBuffer.drawString("GAME OVER",40,198);
gBuffer.setColor(Color.BLACK);
gBuffer.drawString("GAME OVER",40,200);
gBuffer.drawString("Final Score: " + (int)score,20,260);
}
}while(lose);
}
The key inputs need to move an actor I have, but it doesn't move at all, and yes, I click inside the applets every time. Any idea of whats going on?
EDIT: I have now gave up on keyListener and tried keyBindings, but I'm new with them and probably have something wrong, please help me...
public void init() {
panel = new JPanel();
this.setSize(400,700);
this.setFocusTraversalKeysEnabled(false);
this.addKeyListener(this);
player = new Actor(180,500);
virtualMem = createImage(400,800);
gBuffer = virtualMem.getGraphics();
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "up");
panel.getActionMap().put("up", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
gBuffer.drawString("IT WORKS", 150, 150);
repaint();
}
});
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "down");
panel.getActionMap().put("down", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
gBuffer.drawString("IT WORKS", 150, 150);
repaint();
}
});
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");
panel.getActionMap().put("left", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
gBuffer.drawString("IT WORKS", 150, 150);
repaint();
}
});
panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");
panel.getActionMap().put("right", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
gBuffer.drawString("IT WORKS", 150, 150);
repaint();
}
});
}
The while is still the same (play). When ever I click something it doesn't access the methods either.
I am afraid that maybe that infinite loop inside paint() is interfering with the events management (remember that there is a single thread for those 2 things to be done). Why don't you just fire a repaint() on every significant event (for example, a key press)?
Ok, I've got some code I setup to create a simple little overlay window to use as an alert message for a program I'm working on. Everything works fine the first run through, but trying to run through it again, it freezes the whole thing, forcing me to terminate it via the debugger or task manager. I know I'm doing something wrong, I'm just not sure what, due to my limited experience with Java.
Below is the code I use to setup my window and place it in the lower-right corner above the taskbar:
private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public static JWindow alertWindow() {
JWindow newWin = new JWindow();
JPanel panel = new JPanel();
BufferedImage img = null;
try {
img = ImageIO.read(Main.class.getResource("/images/test.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
JLabel imgLbl = new JLabel(new ImageIcon(img));
panel.add(imgLbl);
newWin.setContentPane(panel);
newWin.pack();
Insets scnMax = Toolkit.getDefaultToolkit().getScreenInsets(newWin.getGraphicsConfiguration());
int taskBar = scnMax.bottom;
int x = screenSize.width - newWin.getWidth();
int y = screenSize.height - taskBar - newWin.getHeight();
newWin.setLocation(x,y);
newWin.setVisible(true);
final PulseWindow pulseWin = new PulseWindow(newWin);
pulseWin.getWindow().addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent click) {
if(SwingUtilities.isRightMouseButton(click)) {
pulseWin.stopPulsing();
pulseWin.destroyPulse();
} else {
System.out.println(pulseWin.isPulsing());
if(pulseWin.isPulsing()) {pulseWin.stopPulsing();}
else {pulseWin.startPulse();}
}
}
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
});
pulseWin.startPulsing();
return newWin;
}
And below is the code I've setup to make it pulse to draw the user's attention:
import javax.swing.JWindow;
public class PulseWindow {
private boolean pulse = true;
private boolean doPulse = true;
private Float floor = 0.50f;
private JWindow win;
public PulseWindow(JWindow win) {
this.win = win;
}
public void startPulsing() {
pulse = true;
boolean decreasing = true;
double inc2 = 0.03;
double current = win.getOpacity();
while(pulse) {
if(doPulse) {
if(decreasing) {
current = current - inc2;
if((float) current <= floor) {
current = floor;
win.setOpacity((float) current);
decreasing = false;
} else {
win.setOpacity((float) current);
}
} else {
current = current + inc2;
if((float) current >= 1.0f) {
current = 1.0;
win.setOpacity((float) current);
decreasing = true;
} else {
win.setOpacity((float) current);
}
}
} else {
current = 1.0;
win.setOpacity(1.0f);
decreasing = true;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
win.setOpacity(1.0f);
}
public void destroyPulse() {
pulse = false;
win.dispose();
}
public boolean isPulsing() { return doPulse; }
public void setFloor(float floor) { this.floor = floor; }
public void stopPulsing() { doPulse = false; }
public void startPulse() { doPulse = true; }
public JWindow getWindow() { return win; }
}
Anyway, like I mentioned, it works fine for the first use, but as soon as you close the window via the right-click then attempt to re-run it later (whether by calling the startPulsing() method or by completely reinitializing the whole class with a new JWindow by calling alertWindow() again), the whole program freezes. Any ideas why this is?
Like I said, I'm still a bit of a newbie to Java, so if you see anything else I'm doing wrong/inefficiently, as well, feel free to point it out so I can do it correctly.
Edit:
I'm starting to think the issue is with JWindows, now. I setup some other code for a different method of displaying the alert and, while it doesn't freeze this time, it doesn't work as intended, either.
public class AlertWindow extends JWindow {
private static Border compound = BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(), BorderFactory.createLoweredBevelBorder());
private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public AlertWindow() {
JPanel panel = new JPanel();
panel.setBorder(compound);
panel.setBackground(Color.RED);
JLabel imgLbl = new JLabel("Enter Alert Msg Here!");
imgLbl.setFont(new Font(null,Font.BOLD,16));
panel.add(imgLbl);
setContentPane(panel);
pack();
this.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent click) {
if(SwingUtilities.isLeftMouseButton(click)) {
scrollOff();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
scrollOn();
}
}
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
});
scrollOn();
}
public void scrollOn() {
Insets scnMax = Toolkit.getDefaultToolkit().getScreenInsets(getGraphicsConfiguration());
int taskBar = scnMax.bottom;
int x = screenSize.width - getWidth();
int yEnd = screenSize.height - taskBar - getHeight();
int yStart = screenSize.height;
setLocation(x,yStart);
setVisible(true);
int current = yStart;
while(current > yEnd) {
current-=2;
System.out.println(current);
setLocation(x,current);
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void scrollOff() {
int x = screenSize.width - getWidth();
int yEnd = screenSize.height;
int yStart = this.getBounds().y;
setLocation(x,yStart);
int current = yStart;
while(current < yEnd) {
current+=2;
setLocation(x,current);
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
setVisible(false);
}
}
Just like the pulsing window issue, it works as intended the first time, then breaks on subsequent uses. In this case, the only thing that breaks is the scrollOn() command. It scrolls on while invisible, then becomes visible once it reaches its destination. The console output of the position clearly shows that it's moving, but you can't see it until it stops moving.
Edit 2:
And back to feeling dumb... I found the issue (actually found it some time ago but forgot to update this...). The issue ended up being that I was only using the runnable and not placing it inside of a new Thread() object. For some reason I was thinking runnable objects created their own new threads, but once I figured out my mistake, it was an easy fix. Obviously I still have a long ways to go in learning Java...
Edit:
Ok, now I'm annoyed... apparently it still breaks if you attempt to run it from an action listener of some kind. My most recent version of the PulseAlert class (below) that calls into the PulseWindow class shown in the original answer further below:
public class PulseAlert {
private static Border compound = BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(), BorderFactory.createLoweredBevelBorder());
private static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public void runAlert() throws InterruptedException {
final PulseWindow pulseWin = new PulseWindow(alertWindow());
pulseWin.getWindow().addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent click) {
if(SwingUtilities.isRightMouseButton(click)) {
pulseWin.stopPulsing();
pulseWin.destroyPulse();
} else if(SwingUtilities.isLeftMouseButton(click) && pulseWin.isPulsing()) {
pulseWin.stopPulsing();
} else if(SwingUtilities.isLeftMouseButton(click) && !pulseWin.isPulsing()) {
pulseWin.startPulsing();
}
}
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
});
try {
pulseWin.startPulse();
} catch (Exception e) {
e.printStackTrace();
}
while(pulseWin.pulserActive()) {
Thread.sleep(100);
}
System.out.println("done with second SW");
}
public static JWindow alertWindow() {
System.out.println("Start");
JWindow newWin = new JWindow();
JPanel panel = new JPanel();
panel.setBorder(compound);
panel.setBackground(Color.RED);
JLabel imgLbl = new JLabel("Enter Alert Msg Here!");
imgLbl.setFont(new Font(null,Font.BOLD,16));
panel.add(imgLbl);
newWin.setContentPane(panel);
newWin.pack();
Insets scnMax = Toolkit.getDefaultToolkit().getScreenInsets(newWin.getGraphicsConfiguration());
int taskBar = scnMax.bottom;
int x = screenSize.width - newWin.getWidth();
int y = screenSize.height - taskBar - newWin.getHeight();
newWin.setLocation(x,y);
newWin.setVisible(true);
return newWin;
}
}
And below is how I can call up the alert window - repeatedly, if I like, as long as it's outside of an action listener.
PulseAlert alertPulse = new PulseAlert();
alertPulse.runAlert();
The above code works flawlessly until placed into an action listener of some kind such as:
trayIcon.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
alertPulse.runAlert();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
});
Once the runAlert() method is called from an action listener, the whole thing freezes like it did previously. Runs perfectly fine until then. Any ideas what is causing this? Is this a bug in Java or am I doing something wrong?
Original Answer:
Ok, I feel pretty dumb, now. All I had to do to fix the issue was place the startPulsing() contents into a new runnable and it all works, and as many times as I need it to.
public void startPulsing() throws Exception {
new Runnable() {
#Override
public void run() {
pulse = true;
win.setVisible(true);
boolean decreasing = true;
double inc = 0.05;
double current = win.getOpacity();
while(pulse) {
if(doPulse) {
if(decreasing) {
current = current - inc;
if((float) current <= floor) {
current = floor;
win.setOpacity((float) current);
decreasing = false;
} else {
win.setOpacity((float) current);
}
} else {
current = current + inc;
if((float) current >= 1.0f) {
current = 1.0;
win.setOpacity((float) current);
decreasing = true;
} else {
win.setOpacity((float) current);
}
}
} else {
current = 1.0;
win.setOpacity(1.0f);
decreasing = true;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
win.setOpacity(1.0f);
}
}.run();
}
I have a class that implements MouseListener (JPanel). When I click on the panel something happens. What I want is some kind of while-loop that loops as long as left mousebutton is pressed down.
#Override
public void mousePressed(MouseEvent e) {
while(e.isPressedDownD) { // <--
//DO SOMETHING
}
}
This obviously doesn't work, but I hope you understand what I'm trying to achieve.
The whole class for those that are interested:
package control;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import model.GridModel;
import view.GUIView;
public class MapListener implements MouseListener{
private GridModel model;
private GUIView view;
private int posX;
private int posY;
public MapListener(GridModel model, GUIView view) {
this.model = model;
this.view = view;
}
#Override
public void mouseClicked(MouseEvent e) {
posX = e.getX();
posY = e.getY();
model.setMouseAtX(posX);
model.setMouseAtY(posY);
view.paintTile();
System.out.println("X: " + posX + " Y: " + posY);
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent e) {
while(e.getModifiers() == MouseEvent.MOUSE_PRESSED) { //Obviously doesn't work
//DO SOMETHING
}
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
As pointed out by other answers, the place to do your work is not in the mouse event listener methods.
Also there is no explicit "mouse pressed" notion in MouseEvent, so you must track that yourself. I have provided an example of how to do this. Also note the MouseEvent.BUTTON1 references, as this is just to track the state of the left mouse button.
This is where you must start to learn about concurrency. For that reason, I've added in a synchronized method as you need to be aware that funny things happen when multiple threads access properties at the same time, and synchronized is a mechanism for keeping this sane. Consider it further reading beyond the scope of this example.
Untested, but this should work:
volatile private boolean mouseDown = false;
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
mouseDown = true;
initThread();
}
}
public void mouseReleased(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
mouseDown = false;
}
}
volatile private boolean isRunning = false;
private synchronized boolean checkAndMark() {
if (isRunning) return false;
isRunning = true;
return true;
}
private void initThread() {
if (checkAndMark()) {
new Thread() {
public void run() {
do {
//do something
} while (mouseDown);
isRunning = false;
}
}.start();
}
}
Why do so many of these answers wrongly assert that there is no explicit "mouse pressed" notion in MouseEvent?
Although the other commenters are correct that the OP should not be doing all that stuff in an event handler, there are other situations in which querying the button state in a mouse listener is useful. In those cases, you actually CAN determine the button down state. For example:
#Override
public void mouseExited(MouseEvent event) // Or any other mouse event handler...
{
int buttonsDownMask = MouseEvent.BUTTON1_DOWN_MASK
| MouseEvent.BUTTON2_DOWN_MASK
| MouseEvent.BUTTON3_DOWN_MASK; // Or whichever buttons you care about...
if ( (event.getModifiersEx() & buttonsDownMask) != 0 )
System.out.println("Hey! Some button is pressed!");
}
Notice in particular the use of the MouseEvent.getModifiersEx() method, along with MouseEvent.BUTTON1_DOWN_MASK and friends.
You could create a new Thread containing your while loop.
You start that Thread when the mouse button is pressed. You stop it when the mouse button is released.
You shouldn't be doing that in an event handler as no more events will be processed until the event handler exits.
What you want to achieve can be done with a separate worker thread. Create the thread from the mousePressed listener, do whatever you want to do in the thread (this should contain the while loop) and make the thread exit when the mouse is released (your mouseReleased listener should notify the thread).
for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ClickListener extends MouseAdapter implements ActionListener {
private final static int clickInterval = (Integer) Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
private MouseEvent lastEvent;
private Timer timer;
public ClickListener() {
this(clickInterval);
}
public ClickListener(int delay) {
timer = new Timer(delay, this);
}
#Override
public void mouseClicked(MouseEvent e) {
/*if (e.getClickCount() > 2) {
return;
}
lastEvent = e;
if (timer.isRunning()) {
timer.stop();
doubleClick(lastEvent);
} else {
timer.restart();
}*/
if (timer.isRunning() && !e.isConsumed() && e.getClickCount() > 1) {
System.out.println("double");
timer.stop();
} else {
timer.restart();
}
}
#Override
public void actionPerformed(ActionEvent e) {
timer.stop();
singleClick(lastEvent);
}
public void singleClick(MouseEvent e) {
}
public void doubleClick(MouseEvent e) {
}
public static void main(String[] args) {
JFrame frame = new JFrame("Double Click Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addMouseListener(new ClickListener() {
#Override
public void singleClick(MouseEvent e) {
System.out.println("single");
}
#Override
public void doubleClick(MouseEvent e) {
System.out.println("double");
}
});
frame.setPreferredSize(new Dimension(200, 200));
frame.pack();
frame.setVisible(true);
}
}
I search the forum and see this codes:
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
System.out.println(" and it's a double click!");
wasDoubleClick = true;
} else {
Integer timerinterval = (Integer) Toolkit.getDefaultToolkit().getDesktopProperty(
"awt.multiClickInterval");
timer = new Timer(timerinterval.intValue(), new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (wasDoubleClick) {
wasDoubleClick = false; // reset flag
} else {
System.out.println(" and it's a simple click!");
}
}
});
timer.setRepeats(false);
timer.start();
}
}
but the code runs incorrectly(Sometime it prints out " and it's a single click!" 2 times . It should print out " and it's a double click!"). Can anybody show me why? or can you give me some better ways to do this?
Thank you!
Sometime it prints out " and it's a single click!" 2 times . It should print out " and it's a double click!").
That is normal. A double click only happens if you click twice within the specified time interval. So sometimes if you don't click fast enough you will get two single clicks in a row.
Integer timerinterval = (Integer) Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
The above line of code determines how fast the double click must be.
For what its worth here is some code I have used to do the same thing. Don't know if its any better or worse than the code you have:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ClickListener extends MouseAdapter implements ActionListener
{
private final static int clickInterval = (Integer)Toolkit.getDefaultToolkit().
getDesktopProperty("awt.multiClickInterval");
MouseEvent lastEvent;
Timer timer;
public ClickListener()
{
this(clickInterval);
}
public ClickListener(int delay)
{
timer = new Timer( delay, this);
}
public void mouseClicked (MouseEvent e)
{
if (e.getClickCount() > 2) return;
lastEvent = e;
if (timer.isRunning())
{
timer.stop();
doubleClick( lastEvent );
}
else
{
timer.restart();
}
}
public void actionPerformed(ActionEvent e)
{
timer.stop();
singleClick( lastEvent );
}
public void singleClick(MouseEvent e) {}
public void doubleClick(MouseEvent e) {}
public static void main(String[] args)
{
JFrame frame = new JFrame( "Double Click Test" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.addMouseListener( new ClickListener()
{
public void singleClick(MouseEvent e)
{
System.out.println("single");
}
public void doubleClick(MouseEvent e)
{
System.out.println("double");
}
});
frame.setSize(200, 200);
frame.setVisible(true);
}
}
public void mouseClicked(MouseEvent evt) {
if (evt.getButton()==MouseEvent.BUTTON1){
leftClick = true; clickCount = 0;
if(evt.getClickCount() == 2) doubleClick=true;
Integer timerinterval = (Integer)Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
timer = new Timer(timerinterval, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(doubleClick){
System.out.println("double click.");
sb = new StringBuffer();
sb.append("Double Click");
clickCount++;
if(clickCount == 2){
clickCount=0;
doubleClick = false;
}
} else {
sb = new StringBuffer();
sb.append("Left Mouse");
System.out.println("single click.");
}
}
});
timer.setRepeats(false);
timer.start();
if(evt.getID()==MouseEvent.MOUSE_RELEASED) timer.stop();
}