MultiThread handling and stopping midway - java

i'm having trouble stopping a thread in the middle. This is part of my code, in the StoplightThread class I have problems on the first if statement. What it is supposed to do is wait at least 10 secs then allow the user to press the button so they can change the light, if the button is pressed it should stop the running thread in this case Thread.sleep(40000). What happens is when I press the button it changes the light but does not stop the thread. If I press the button while there is still 20secs left it will add 20secs to the 10secs for the yellow light, making it yellow for 30 secs.
Edit: if you are wondering, stoplightCanvas.x == 3 is green, stoplightCanvas.x == 2 is yellow, and stoplightCanvas.x == 1 is red.
class StoplightCanvas extends Canvas implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == cross) {
isPressed = true;
if (x == 3 && canCross)
x = 2;
}
repaint();
}
}
class StoplightThread extends Thread
{
StoplightCanvas stoplightCanvas;
StoplightThread(StoplightCanvas stoplightCanvas) {
this.stoplightCanvas = stoplightCanvas;
}
public void run()
{
if (stoplightCanvas.x == 3){
Thread.sleep(10000);
stoplightCanvas.canCross = true;
Thread.sleep(40000);
if(stoplightCanvas.isPressed)
StoplightThread.interrupt();
} else if (stoplightCanvas.x == 2) {
Thread.sleep(10000);
} else if (stoplightCanvas.x == 1) {
Thread.sleep(60000);
}
} catch (InterruptedException e){}
stoplightCanvas.toggleColor();
stoplightCanvas.repaint();
}
}
}

The way your code is written, the thread is sleeping for 40 seconds; then wakes up and checks for stoplightCanvas.isPressed and sets the interrupt flag...
If you want to interrupt the thread while it's sleeping, you need to interrupt from another thread. The EventDispatchThread is a fine place to do that, so you can either modify your current ActionListener, or create another one that does it.
public void actionPerformed(ActionEvent e)
{
...
stopLightThread.interrupt();
}
If you don't want to expose the button outside stopLightCanvas, then you can roll your own listener support in StopLightCanvas:
class StopLightCanvas extends Canvas implements ActionEventListener {
public static interface StopLightListener extends EventListener {
public void stopLightChanged(int state);
}
// watch out, you may need this to be threadsafe depending on your usage
List<ActionEventListener> myListeners = new LinkedList<StopLightListener>();
public void addStopLightListener(StopLightListener lst) {
myListeners.add(lst);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == cross) {
isPressed = true;
if (x == 3 && canCross)
x = 2;
}
repaint();
for(StopLightListener lst: myListeners) {
lst.stopLightChanged(x);
}
}
...
}
public class StopLightThread extends Thread implements {
StoplightThread(StoplightCanvas stoplightCanvas) {
this.stoplightCanvas = stoplightCanvas;
stopLightCanvas.addStopLightListener(this);
}
...
#Override public void stopLightChanged(int state) {
this.interrupt();
}
}

Related

repeatedly simulating clicks while physically holding mouse button

So my problem is that i want to simulate mouse clicks while the mouse is held down. But the Robot library cant execute the click while the physical button is held down.
This is my code for the click:
public static void click() {
Runnable runnable = () -> {
try {
Robot robot = new Robot();
while (clicking) {
System.out.println("Clicking! " + System.currentTimeMillis());
robot.mousePress(mouseButton ? InputEvent.BUTTON1_DOWN_MASK : InputEvent.BUTTON2_DOWN_MASK);
Thread.sleep(300);
robot.mouseRelease(mouseButton ? InputEvent.BUTTON1_DOWN_MASK : InputEvent.BUTTON2_DOWN_MASK);
}
} catch (Exception ignored) {
System.out.println("Couldn't click");
}
};
new Thread(runnable).start();
}
This is my mouse event listener code:
public class MouseListener implements NativeMouseInputListener {
public void nativeMousePressed(NativeMouseEvent e) {
if (active && !focused && !clicking && e.getButton() == (mouseButton ? 1 : 2)) {
clicking = true;
click();
}
}
public void nativeMouseReleased(NativeMouseEvent e) {
if (active && !focused && e.getButton() == (mouseButton ? 1 : 2)) {
clicking = false;
}
}
}
The print gets executed normally and if i switch the clicks so a left click gets executed when i do a rightclick and that also works but i want it with the same button.
I appreciate your help.

How do I run loops while keeping events running?

I have a question about using events to run loops since doing so seems to lock down the thread. For example I have an nativeMousePressed and nativeMouseReleased event and I am trying to execute some code continuously while the mouse is pressed and then stop when its released. I tried to do this by creating a static boolean variable in another manager class and then setting it to true when the mouse is being pressed and false when the mouse is released. Then I decided to make a while loop that gets called from inside that nativeMousePressed event that uses the boolean value I talked about earlier. The issue is that no events can be called while that while loop is running which means the boolean value when never become false creating an infinite loop. How can I run the while loop while keeping the events running as well?
I assume this has to do with the thread being locked down but I have not worked with stuff like this much and would like some help figuring out how to run both these things in parallel.
public class NativeMouseEvent implements NativeMouseListener {
Program program = new Program();
#Override
public void nativeMouseClicked(org.jnativehook.mouse.NativeMouseEvent e) {
}
#Override
public void nativeMousePressed(org.jnativehook.mouse.NativeMouseEvent e) {
if(e.getButton() == 1 && Controller.threeClicked) {
Controller.fixAim = true;
program.start();
}
}
#Override
public void nativeMouseReleased(org.jnativehook.mouse.NativeMouseEvent e) {
program.interrupt();
Controller.fixAim = false;
}
}
Here is what my second thread is running...
public class Program extends Thread {
public void run() {
while(Controller.fixAim) {
System.out.println("test");
}
}
Here my second attempt which also gives me an error saying that this.program is null.
public class NativeMouseEvent implements NativeMouseListener {
Program program;
#Override
public void nativeMouseClicked(org.jnativehook.mouse.NativeMouseEvent e) {
}
#Override
public void nativeMousePressed(org.jnativehook.mouse.NativeMouseEvent e) {
if(e.getButton() == 1 && Controller.threeClicked) {
Controller.fixAim = true;
if(program != null) {
program = new Program();
program.start();
}
}
}
#Override
public void nativeMouseReleased(org.jnativehook.mouse.NativeMouseEvent e) {
program.interrupt();
program = null;
Controller.fixAim = false;
}
}
Start a tread on mouse down and stop the tread on mouse up. In the thread do circle drawing.
Something like below java code. Note: it is just an example. You need to make changes to make it work in your android environment.
public class Test {
Thread drawTask;
public void mouseDown() {
drawTask = new Thread(()-> {
int i = 0;
try {
for(;;) {
System.out.print("\rDrawing circle " + i++);
Thread.sleep(500);
}
} catch(InterruptedException e) {
System.out.println("finished drawing circle.");
}
});
drawTask.start();
}
public void mouseUp() {
if(drawTask != null) {
drawTask.interrupt();
drawTask = null; //<--- make sure you do this
}
}
public static void main(String[] args) {
Test test = new Test();
Scanner in = new Scanner(System.in);
System.out.println("type anything and press Enter to simulate mouse down/up");
in.next();
test.mouseDown();
in.next();
test.mouseUp();
in.next();
in.close();
}
}

How to continue a thread if a condition is met or rather another thread has ended?

I am new to Java and trying to program a Java 2D Game. Right now, I'm trying to implement that each player rolls one after the other. To implement this, the game loop must wait until the player makes a turn. In this case, wait until the player presses the Enter key to roll the dice. After the player has rolled the game loop should be executed again and then stopped again when it is the next player's turn. I have already tried something like this:
public class Game implements Runnable {
//...
public void run() {
//...
while(running) {
//input();
logic();
update();
draw();
}
}
public synchronized void logic() {
for(Player player : players) {
player.takeTurn();
try { wait(); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
public synchronized void update() {
//...
}
//...
}
public class Player extends GameObject implements KeyListener, Runnable { //GameObject extends JPanel
//...
public void takeTurn() {
isOnTurn = true
this.requestFocusInWindow();
new Thread(this).start();
}
//...
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyChar() == KeyEvent.VK_ENTER) {
//...
isOnTurn = false;
}
}
//...
#Override
public void run() {
while(isOnTurn) {
continue;
}
Game.class.notifyAll();
}
}

repaint() in Thread is making a high usage CPU

I'm using a Thread to scroll text in my application :
public void run() {
super.run();
while (!isInterrupted()) {
if (X >= -getPreferredSize().getWidth()) {
X -= 2;
} else {
decrementMessagesInList(getMessages());
addMessage(getMessages());
prepare();
X = getParentWidth();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
repaint();
}
}
However, see that with sleep my CPU usage is very high, I need to reduce that. Can anyone suggest how to do it ?
If I can make the assumption that your code only needs to scroll the text in response to some event (say a click or drag or something) then you should make your thread go into a wait state then have the code that triggers the update post a notification over to the thread which will then wake up and do the update. Something like this:
Object syncObj = new Object();
public void run() {
while (true) {
try {
syncObj.wait();
if (X >= -getPreferredSize().getWidth()) {
X -= 2;
} else {
decrementMessagesInList(getMessages());
addMessage(getMessages());
prepare();
X = getParentWidth();
}
repaint();
} catch (InterruptedException ie) {
// handle the exception
}
}
}
Then in the code which handles/generates the event that causes a need to scroll
public void onClick(..) {
syncObj.notifyAll();
}
You also need to guard against spurious wake ups of your thread to make sure the event you were waiting for actually happened. See Do spurious wakeups actually happen?.

Java : detect triple-click without firing double-click

I have a JTable in which I want to call a function when a cell is double-clicked and call another function when the cell is triple-clicked.
When the cell is triple-clicked I do not want to call the double-click-function.
What I have right now is (mgrdAlarm is the JTable) :
mgrdAlarm.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent e)
{
System.out.println("getClickCount() = " + e.getClickCount());
if (e.getClickCount()==2)
{
doubleClick();
System.out.println("Completed : doubleClick()");
}
if (e.getClickCount()==3)
{
tripleClick();
System.out.println("Completed : tripleClick()");
}
}
});
When double-clicked the console shows :
getClickCount() = 1
getClickCount() = 2
Completed : doubleClick()
When triple-clicked the console shows :
getClickCount() = 1
getClickCount() = 2
Completed : doubleClick()
getClickCount() = 3
Completed : tripleClick()
When triple-clicked I want the console to show :
getClickCount() = 1
getClickCount() = 2
getClickCount() = 3
Completed : tripleClick()
So I do not want to call the function doubleClick() when the cell is triple-clicked, but I do want to call the function doubleClick() when the cell is double-clicked.
[EDIT]
As all replies suggest the solution seems to be to delay the double-click-action and wait a certain time for the triple-click.
But as discussed here that might lead to a different type of problem :
The user might have set his double-click-time quite long, which might overlap with the timeout of my triple-click.
It is no real disaster if my double-click-action is executed before my triple-click-action, but it does generate some extra overhead, and especially some extra data traffic which I would like to prevent.
As the only solution so far might lead to other problems, which might actually be worse than the original problem, I will leave it as it is right now.
public class TestMouseListener implements MouseListener {
private boolean leftClick;
private int clickCount;
private boolean doubleClick;
private boolean tripleClick;
public void mouseClicked(MouseEvent evt) {
if (evt.getButton()==MouseEvent.BUTTON1){
leftClick = true; clickCount = 0;
if(evt.getClickCount() == 2) doubleClick=true;
if(evt.getClickCount() == 3){
doubleClick = false;
tripleClick = true;
}
Integer timerinterval = (Integer)Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
Timer timer = new Timer(timerinterval, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(doubleClick){
System.out.println("double click.");
clickCount++;
if(clickCount == 2){
doubleClick(); //your doubleClick method
clickCount=0;
doubleClick = false;
leftClick = false;
}
}else if (tripleClick) {
System.out.println("Triple Click.");
clickCount++;
if(clickCount == 3) {
tripleClick(); //your tripleClick method
clickCount=0;
tripleClick = false;
leftClick = false;
}
} else if(leftClick) {
System.out.println("single click.");
leftClick = false;
}
}
});
timer.setRepeats(false);
timer.start();
if(evt.getID()==MouseEvent.MOUSE_RELEASED) timer.stop();
}
}
public static void main(String[] argv) throws Exception {
JTextField component = new JTextField();
component.addMouseListener(new TestMouseListener());
JFrame f = new JFrame();
f.add(component);
f.setSize(300, 300);
f.setVisible(true);
component.addMouseListener(new TestMouseListener());
}
}
The previous answers are correct: you have to account for the timing and delay recognizing it as a double click until a certain amount of time has passed. The challenge is that, as you have noticed, the user could have a very long or very short double click threshold. So you need to know what the user's setting is. This other Stack Overflow thread ( Distinguish between a single click and a double click in Java ) mentions the awt.multiClickInterval desktop property. Try using that for your threshold.
You can do something like that, varying delay time:
public class ClickForm extends JFrame {
final static long CLICK_FREQUENTY = 300;
static class ClickProcessor implements Runnable {
Callable<Void> eventProcessor;
ClickProcessor(Callable<Void> eventProcessor) {
this.eventProcessor = eventProcessor;
}
#Override
public void run() {
try {
Thread.sleep(CLICK_FREQUENTY);
eventProcessor.call();
} catch (InterruptedException e) {
// do nothing
} catch (Exception e) {
// do logging
}
}
}
public static void main(String[] args) {
ClickForm f = new ClickForm();
f.setSize(400, 300);
f.addMouseListener(new MouseAdapter() {
Thread cp = null;
public void mouseClicked(MouseEvent e) {
System.out.println("getClickCount() = " + e.getClickCount() + ", e: " + e.toString());
if (cp != null && cp.isAlive()) cp.interrupt();
if (e.getClickCount() == 2) {
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("Double click processed");
return null;
}
}));
cp.start();
}
if (e.getClickCount() == 3) {
cp = new Thread(new ClickProcessor(new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("Triple click processed");
return null;
}
}));
cp.start();
}
}
});
f.setVisible(true);
}
}
You need to delay the execution of double click to check if its a tripple click.
Hint.
if getClickCount()==2 then put it to wait.. for say like 200ms?
It's exactly the same problem as detecting double-click without firing single click. You have to delay firing an event until you're sure there isn't a following click.
There's a tutorial for this
here
Edit: It fires click events individually though, so you would get:
Single Click THEN
Double Click THEN
Triple Click. So you would still have to do some timing trickery.
The code is:
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Main {
public static void main(String[] argv) throws Exception {
JTextField component = new JTextField();
component.addMouseListener(new MyMouseListener());
JFrame f = new JFrame();
f.add(component);
f.setSize(300, 300);
f.setVisible(true);
component.addMouseListener(new MyMouseListener());
}
}
class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 3) {
System.out.println("triple-click");
} else if (evt.getClickCount() == 2) {
System.out.println("double-click");
}
}
}
Here is what i have done to achieve this, this actually worked fine for me. A delay is necessary to detect the type of click. You can choose it. The following delays if a triple click can be happened within 400ms. You can decrease it to the extent till a consecutive click is not possible. If you are only worrying about the delay, then this is a highly negligible delay which must be essential to carry this out.
Here flag and t1 are global variables.
public void mouseClicked(MouseEvent e)
{
int count=e.getClickCount();
if(count==3)
{
flag=true;
System.out.println("Triple click");
}
else if(count==2)
{
try
{
t1=new Timer(1,new ActionListener(){
public void actionPerformed(ActionEvent ae)
{
if(!flag)
System.out.println("Double click");
flag=false;
t1.stop();
}
});
t1.setInitialDelay(400);
t1.start();
}catch(Exception ex){}
}
}

Categories