Im really new to Java and Libgdx
I have created an interface entitled LevelQuizDialog in which the buttons will fire an event, and I want to have a 3 second delay before firing that event.
here's the code:
//fire event on button click
WrongBtn.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
CheckBtn.clearListeners();
if(checker != answer )
{
removeActor(title);
addActor(title2);
}
if(checker == answer)
{
removeActor(title);
addActor(title3);
}
// this is the delay I had a problem with...
float delay = 3; // seconds
Timer.schedule(new Task(){
#Override
public void run() {
fire(new MessageEvent(ON_CLOSE));
}
}, delay);
}
});
}
I had followed a lot of tutorials in com.badlogic.gdx.utils.Timer
but I had a lot of errors..
I got an error in the Timer.schedule(new Task()
saying Timer is not applicable for arguments
thanks for anyone who can help.
A portable LibGDX solution could be to use gdx-ai library which comes with a Message api that allow you to post delayed messages using a specialized event bus :
https://github.com/libgdx/gdx-ai/wiki/Message-Handling#dispatching-a-message
messageDispatcher.dispatchMessage(
delay, // Immediate message if <= 0; delayed otherwise
sender, // It can be null
recipient, // It can be null, see the "Multiple Recipients" section below
messageType, // Any user-defined int code
extraInfo, // Optional data accompanying the message; it can be null
needsReturnReceipt); // Whether the sender needs the return receipt or not
may be this can help
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
fire(new MessageEvent(ON_CLOSE));
}
}, delayMillis);
Related
I have a JButton that starts a countdown timer when pressed. When I press the button, it begins, and when I press it again (Button will say "Stop"), it stops. However when I press it again to start the time again I get an error saying:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.
Here is my code:
final static Timer t = new Timer();
static void startTimer(JButton b) {
t = new Timer(); // Solved: I needed to create a new Timer object.
t.scheduleAtFixedRate(new TimerTask() {
double timeleft = calcShutterSpeed;
#Override
public void run() {
String s = secondsToMinutes(timeleft);
time.setText(s);
timeleft--;
if (timeleft < 0) {
t.cancel();
b.setText("START TIMER");
b.setForeground(Color.BLACK);
}
}
}, 0, 1000);
}
static void stopTimer() {
t.cancel();
}
/**
* Creates the timer if "Start" is pressed.
*
* #param b
*/
static void timer(JButton b) {
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// If start button is pressed, change text to display stop
if (b.getText() == "START TIMER") {
startTimer(b);
b.setText("STOP TIMER");
b.setForeground(Color.RED);
}
// If stop button is pressed, cancel timer and change text to start
else if (b.getText() == "STOP TIMER") {
stopTimer();
b.setText("START TIMER");
b.setForeground(Color.BLACK);
}
}
});
}
Any tips or suggestions that can fix this problem would be much appreciated. Thanks in advance!
EDIT: Really really simple fix for the curious. The fix is in the code.
I think that the "cancel" method on timer still keeps scheduled task with a cancel status.
The call to "purge" method, directly after the cancel should clean the queue and maybe solve this issue.
Lets say I have a ImageView that executes at a click of a Button:
final ImageView ball = new ImageView(v.getContext());
ball.setImageResource(R.drawable.ball_1);
gameConstraintLayout.addView(ball);
When I click that button, it first off makes the ball appears , creates and runs another thread that tell itself to sleep 1000 milliseconds sleep(long millis) then removes the ball by calling ConstrainLayout.removeView(view)
Here is the full minimal code:
final ImageView ball = new ImageView(v.getContext());
currentBullet.setImageResource(R.drawable.ball_1);
gameConstraintLayout.addView(ball);
ballAppears.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
final ImageView ball = new ImageView(v.getContext());
currentBullet.setImageResource(R.drawable.ball_1);
gameConstraintLayout.addView(ball);
Thread thread = new Thread() {
#Override
public void run() {
try {
sleep(1000);
contraintLayout.removeView(ball)
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
});
Problem is;
The ball appears on screen, the other thread successfully sleeps for 1000 milliseconds, but, It crashes when It tries to remove the ball from the constraint layout in the other thread.
Logcat:
android.view.ViewRootImpl$CalledFromWrongThreadException: **Only the original thread that created a view hierarchy can touch its views**.
at android.support.constraint.ConstraintLayout.removeView(ConstraintLayout.java:645)
at com.mobilegames.***.******.GameActivity$1$1.run(GameActivity.java:51)
The code that causes the problem is:
gameConstraintLayout.removeView(ball_1);
AS it seems,I cant access the Constraint layout from the other thread but, I can still change the X and the Y of the ball.
I even tried running that piece of code in the UI theard runOnUIThread(...), but to no avail.
Here is the runONUIThread code:
shootTank.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
final ImageView currentBullet = new ImageView(v.getContext());
currentBullet.setImageResource(R.drawable.bullet_model1);
gameConstraintLayout.addView(currentBullet);
Thread thread = new Thread() {
#Override
public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
gameConstraintLayout.removeView(currentBullet);
}
});
}
};
thread.start();
}
});
Any possible solutions? Keep in mind that I change the X and Y's of the ball after every second.
AND YES, I did check other Questions. The answer in those ones said to simply run it on the UI thread, but of course I already tried that. If i run the sleep(long millis) into the UI thread, obliviously, the whole app would be irresponsible.
(This is not the full app; it was broken down into a much more simpler and understandable Question. I end up changing the ball's X and Y in the separate thread, but that inst what is causing the problem. Please tell me in comments if editing is necessary)
Sorry for small grammar mistakes
Use handler to perform your actions with some delay. For example:
Handler h = new Handler();
h.postDelayed(new Runnable() {
public void run() {
gameConstraintLayout.removeView(currentBullet);
}
}, 1000); // here 1000 is delay in milliseconds (1sec)
First of all, i'm trying to make a puzzle game with the same concept as this game,
LINK: http://www.youtube.com/watch?v=-b2LunJPXC0 (the title of the game is Siren Fantasia)
Where in the user will hold a single piece of item from the gameboard and the objects that is surrounding it will be rotated clockwise until the user releases it.
I want to imitate that, When the user holds the button, the action will continuously loop until the user releases it.
Heres a sample of the code that i have already made:
float delay = 2f;
button.addListener(new ClickListener() {
#Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
if(pointer == 0) {
Timer.schedule(new Task(){
#Override
public void run() {
int counter = 0;
do{
Timer.schedule(new Task() {
#Override
public void run() {
button2.setVisible(false);
}
}, delay);
Timer.schedule(new Task() {
#Override
public void run() {
button2.setVisible(true);
}
}, delay);
}while( counter >= 1 );
}
}, buttonDelay);
}
return false;
}
});
And the output ain't the one that i wanted it to be. When i hold button, the button2 doesn't set to visible(false) and visible(true). But when i kept holding it over and over again, it would sometimes work.
I really need help.
Thank you.
I created a handler, to imitate timer task.
because TimerTask was acting differently on different tablets.
so I created this handler method.
in timer there was a method timerTask.cancel();
but how to stop this handler
it keeps on running even after the application is exited.
as you can see logs running even after back press.
Handler handler = new Handler();
public void recursivelycallHandler(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
recursivelycallHandler();
}
}, 100);
}
There are 3 methods to do that ..
handler.removeCallbacks(Runnable r);
handler.removeCallbacksAndMessages(null);
handler.removeMessages(int what)
In your case first two seem feasible .. add any of the above method in ondestroy or on a listener to backpress..
By putting any condition
Handler handler = new Handler();
int i = 0;
Runnable myRunnable = new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
if(i>5)
handler.removeCallback(myRunnable);
else{
i++;
handler.postDelayed(myRunnable, 100); // here is self calling
}
}
};
}
handler.postDelayed(myRunnable, 100);
Its recursive method but you can call the same Runnable object in run() instead of recursive method and remove that object when based on specific situation/condition
You can store flag (boolean var) to detect if you need to call for your handler and before exit app change this flag to false and stop calling handler.
you can do something like this below:
public void recursivelycallHandler(){
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d("handler is running", "true" + System.currentTimeMillis());
if(YOUR_CONDITION){
recursivelycallHandler();
}
}
}, 100);
}
Hope you got my point.
feel free to comment.
just add isFinished to your run method:
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (isFinished())
return;
Log.d("handler is running", "true" + System.currentTimeMillis());
recursivelycallHandler();
}
}, 100);
I'm actually new to Java and SWT, so my question might sound dumb.
I've looked over the intrnet (and stackoverflow) but all the answers and examples are too complex for a noob like me.
I have a class, call it Admin. When I click a button, it launches a method in another class(Handler).
In Admin I have a progress bar, that should increase with the
operation in Handler.
I don't know how much time the operations in
Handler takes, but I know I have 9 of them.
I would like, somehow,
to inform Admin when each method has finished.
What I have so far: (non relevant parts omitted)
Admin.java:
ProgressBar bar = new ProgressBar(this, SWT.SMOOTH);
Button btn = new Button(this, SWT.NONE);
btn.setText("Update");
btn.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
btn.setEnabled(false);
thread.start();
}
});
Handler handler = new Handler();
final Thread thread = new Thread(){
public void run() {
handler.run();
for(int i=0; i<=10; i++) {
final int value = i;
try {
Thread.sleep(800);
} catch (Exception e) { }
display.asyncExec(new Runnable(){
public void run() {
bar.setSelection(value);
}
});
}
}
};
Handler.java:
public class Handler implements Runnable{
void m1() {...}
void m2() {...}
...
void m9() {...}
public void run()
{
m1();
m2();
...
m9();
}
With this implementation, the call to handler.run() works fine, and the progress bar is filling, but of course they are not "corelated" in any way.
I will appreciate your wisdom!
Thank you very much!
The highly coupled way of solving this, is to have the Handler take a ProgressBar as input in the constructor, and after m1() finishes, it updates the progress to 1/9 and so on. A better (more decoupled) way to do it, is that you can "listen" to Handler, and that Handler fires an event with its progress after each method finishes. Then you can update in the Admin.java.
I will ask you to consider using ProgressMonitorDialog from JFace if adding this library to your application is not much of a problem. Your code then would look something like below:
ProgressMonitorDialog dialog = new ProgressMonitorDialog(parent);
dialog.run(true, true, new IRunnableWithProgress() {
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
monitor.beginTask("my work", 9);
m1();
monitor.worked(1);
m2();
monitor.worked(1);
...
m9();
monitor.done;
}
});
You can also send the monitor instance into your m* methods for even detailed reporting. Have a look at SubProgressMonitor for dividing each one of your initial 9 ticks further before sending them into each m* method.
But this means that your progress bar is a new dialog which might not be acceptable to you so in that case the first answer suits your needs.