I want to make an option in my application that if you click a button a counter will start and it will count (like 0++) and show the number until user stops it, so far I have this non working code
if (v == btn3) {
counter = 0;
scoreText.setBackgroundColor(Color.RED);
new Thread(new Runnable() {
public void run() {
while (counter < 1000 ) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}
}
}).start();
scoreText.setText(Integer.toString(counter));
}
Currently when i press the button, the text field only turns red and is set to 0, but I can't make it count
In my opinion setText method is outside loop. It could update text view after loop ends. Move it somewhere inside loop.
This should work as per your needs
if (v == btn3) {
counter = 0;
scoreText.setBackgroundColor(Color.RED);
new Thread(new Runnable() {
public void run() {
while (counter < 1000 ) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
scoreText.setText(Integer.toString(counter));
}
});
counter++;
}
}
}).start();
}
There is a a class called CountDownTimer which provides some useful functionality. In particular it provides an onTick() method with which you could update your text field at a desired interval.
You would need to create a CountDownTimer to count indefinitely, which you can do by restarting the timer in its onFinish() method, like in this question. But if you set the CountDownTimer for long enough, you probably would never need to restart it.
Something like this...
new CountDownTimer(<REALLY_BIG_NUMBER>, 500) {
int counter = 0;
public void onTick(long millisUntilFinished) {
scoreText.setText(counter++);
}
public void onFinish() {
start();
}
}.start();
Related
I have a ListView<String> list. I can easily get the next item in the ListView with a button using this code:
public void toNext(){
list.getSelectionModel().selectNext();
}
But if I want to go through the ListView automatically with a button, it won't work. I tried the following code:
public void play(){
try {
for (int i = 0; i < list.getItems().size() ; i++) {
list.getSelectionModel().select(i);
Thread.sleep(500);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
This code doesn't select the different strings in the list but just skips to the last string after the given waittime. How can I get it to select each string in the list with a delay of 500 ms?
Consider using an animation:
Timeline animation = new Timeline(
new KeyFrame(Duration.millis(500), e -> list.getSelectionModel().selectNext()));
list.getSelectionModel().select(0);
animation.setCycleCount(list.getItems().size()-1);
animation.play();
Advantages to this approach include
It is lightweight, and doesn't involve creating a new thread of execution. It simply hooks into the existing FX Application Thread and pulse mechanism.
The code is cleaner.
It has additional built-in API, so it is much easier to stop or pause the animation than it would be if you created a new thread to manage this.
The problem is, your loop completely runs in FxApplicationThread.
So, the UI won't update during the loop.
Better would be something like:
public void play(){
Thread t = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < lijst.getItems().size(); i++) {
final int idx = i;
Platform.runLater(new Runnable() {
#Override
public void run() {
lijst.getSelectionModel().select(idx);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
});
t.start();
}
You have to wrap the call that makes the UI update in the UI thread otherwise all the updates are done in one bunch at the end, hence it jumps to the end of the list.
public void play(){
try {
for (int i = 0; i < list.getItems().size() ; i++) {
final int index = i;
Platform.runLater(() -> {
list.getSelectionModel().select(index)
});
Thread.sleep(500);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public void myMethod()
{
if (capture.isOpened()) {
while (true) { //This is The main issue.
capture.read(webcam_image);
if (!webcam_image.empty()) {
webcam_image = my_panel.detect(webcam_image);
temp = my_panel.matToBufferedImage(webcam_image);
my_panel.setimage(temp);
my_panel.repaint();
System.out.print("."); // It should prints "." but the above code doesn't works.
} else {
System.out.println(" --(!) No captured frame -- Break!");
break;
}
}
}
}
This is invoking code of the above method...
actually it's an ActionEvent which can be fire on menu is clicked.
if (e.getActionCommand().equals("goLive")) {
System.out.println("Live...");
myMethod();
}
I know actually it's problem of the infinite while loop but here I need to put this condition at any cost.
The exact solution for this type of problem is Timer class. We can overcome this issue using the following code.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
myMethod();
}
}, 0);
Thanks google, oracle and java doc
Assuming that myMethod is called by an event listener (actionPerformed), the infinite loop is blocking the event dispatch thread.
You can avoid this by using SwingWorker or executing your loop on another thread:
public void myMethod()
{
if (capture.isOpened()) {
new Thread(new Runnable() { //Create a new thread and pass a Runnable with your while loop to it
#Override public void run() {
while (true) {
capture.read(webcam_image);
if (!webcam_image.empty()) {
webcam_image = my_panel.detect(webcam_image);
temp = my_panel.matToBufferedImage(webcam_image);
SwingUtilities.invokeLater(new Runnable() { //The following lines affect the GUI and must be executed on the event dispatch thread, so they should be wrapped inside a Runnable
#Override public void run() {
my_panel.setimage(temp);
my_panel.repaint();
}
}
try{
Thread.sleep(xxx); //consider waiting for a moment (e.g. 16ms)
} catch(InterruptedException e) { ... }
System.out.print(".");
} else {
System.out.println(" --(!) No captured frame -- Break!");
break;
}
}
}
}).start(); //Let the thread loop in the background
}
}
I have a thread that call's MainActivies method that sets text value of EditText but it fails.
MyRunnable is like that:
public class MyRunnable implements Runnable {
MainActivity mController;
public SoundTrigger(MainActivity pController) {
mController = pController;
}
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
if(i % 100) {
mController.triggered(i);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
In MainActivity class my triggered method like this:
public void triggered(int nNum) {
EditTextInstance.setText(nNum+"");
}
but it fails. All i need is printing a real time data that is created by a background thread on an edittext component.
make it like this:
#Override
public void run() {
for (int i = 0; i < 10000; i++) {
if(i % 100) {
mController.runOnUiThread(new Runnable() {
public void run() {
mController.triggered(i);
}
});
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Explanation: you were previously changing an UI element from a Non-UI thread and this is not good. This code should work, BUT it is still not the recommended way to approach the problem. You should use something like a AsyncTask where you have a template method for 'background' operation (non-ui thread operation) and the 'onPostExecute' which already executes on the UI thread.
another additional note: NEVER call Thread.sleep(); on the UI Thread (a.k.a. Main thread)
I'm trying to learn Threads in Swing.
I have a Frame with a JProgressBar (progress), five JButtons (Start, Suspend, Resume, Cancel, Close), and a JLabel (label1).
The frame opens. Only Start is enabled. Start calls my class Progressor:
Updated Again Once and For All
Progressor progressor; //declared as class variable, initialized new in constructor and again in overridden done method
Here's the ButtonListener class:
public class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == jbStart) {
progressor.execute();
label1.setText("Progressing ...");
jbCancel.setEnabled(true);
jbResume.setEnabled(true);
jbSuspend.setEnabled(true);
jbClose.setEnabled(true);
}
if(e.getSource() == jbCancel) {
progressor.cancel(true);
label1.setText("Progress Canceled");
}
if (e.getSource() == jbSuspend) {
label1.setText(progressor.suspendProgress());
}
if (e.getSource() == jbResume) {
label1.setText(progressor.resumeProgress());
}
if (e.getSource() == jbClose) {
dispose();
}
}
}//buttonlistener
Here's the SwingWorker class:
public class Progressor extends SwingWorker<Void, Integer> {
private volatile boolean suspend = false;
private Object lock = new Object();
#Override
protected Void doInBackground() {
for (int i = 0; i <= 10; i++) {
checkForSuspend();
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
publish(i);
}
return null;
}
#Override
protected void process(List<Integer> list) {
int value = list.get(list.size() - 1);
progress.setValue(value);
}
public void checkForSuspend() {
synchronized (lock) {
while (suspend) {
try {
lock.wait();
} catch (InterruptedException ie){
}
}
}
}//checkForSuspend
#Override
protected void done() {
label1.setText("All Done. Press close to exit");
progressor = new Progressor();
}
public synchronized String suspendProgress() {
suspend = true;
return "Progress suspended ...";
}
public synchronized String resumeProgress() {
synchronized (lock) {
suspend = false;
lock.notify();
return "Progress resumed ...";
}
}
}//Progressor class
Everything works except the cancel doesn't doesn't actually cancel the thread (the progress bar continues).
Should I suspend it before canceling?
This How to Pause and Resume a Thread in Java from another Thread question looks very similar to yours and has some nice examples in the answers.
As for your own code and why it does not work:
You create a new progressor on every click. You should be using and controlling one, instead of creating new ones every time.
When suspending your progressor finishes work instead of suspending. As the above question states - you should be looking at the flag at some points of your computation and acting on it. Example:
while (!cancel) {
if (!suspended) {
for (int i = 1; i <= 10; i++) {
Thread.sleep(1000);
publish(i);
}
}
}
The above code will suspend when it next reaches 10 (unless you resumed it before that), and finish when you press cancel (Cancel needs to be added as an extra flag in the obvious manner).
Your thread should run inside a while loop that looks for a boolean to change value from another object, then simply change the state with setPause(true/false) when you click the button:
while(true){
if(object_everyone_can_reference.getPause()){
Thread.sleep(1000);
}
}
I'm using a button to start a background service in my app. This is the code I'm using:
#Override
public void actionPerformed(ActionEvent action) {
if (action.getActionCommand().equals("Start")) {
while (true) {
new Thread(new Runnable() {
public void run() {
System.out.println("Started");
}
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
This does update the service every second, which it what I want. Problem is it freezes the rest of the application. How do I implement it so that that doesn't happen?
The following is likely to cause your application to pause:
while (true) {
...
}
Try removing those lines.
Edit: as per comment, to make the newly-launched thread fire every second, move the sleep and while loop inside the run() method:
if (action.getActionCommand().equals("Start")) {
new Thread(new Runnable() {
public void run() {
while (true) {
System.out.println("Started"); }
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
You're calling this method in the Thread that updates the GUI, and this you're pausing the GUI refresh. Spawn a new thread and execute that there.
an infinite loop ??
while (true) {.....}
how you supposed to get out of here -
add an print statement inside loop and you will come to know that you have been stuck here after button click
Ok I got it. Here's what I should have done:
#Override
public void actionPerformed(ActionEvent action) {
if (action.getActionCommand().equals("Start")) {
new Thread(new Runnable() {
public void run() {
while (true) {
System.out.println("Started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}