I have a javafx Progressbar in my UI and then I have a for loop.
In every iteration of the for loop this happens:
progressVal += 5.0;
progress.setProgress(progressVal);
And after the whole loop, this happens:
progress.setProgress(100);
I now have recognized that the UI controls are only refreshed after the method has finished, so the progress bar wont update until the end and than would be set to 100 imidiatly.
So is it possible so somehow force the UI update, even when the method isn`t finished completly? Or how else could I do this?
If what you do in your loop takes a long time and should not be executed on the JavaFX application thread, (which it probably does or you probably wouldn't have this question), then you should probably run the loop in a Task, on a different thread, updating the task's progress as the loop progresses and binding the progress bar's value to the task's progress.
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class ProgressFeedback extends Application {
private static final double EPSILON = 0.0000005;
#Override
public void start(Stage stage) throws Exception {
final Task<Void> task = new Task<Void>() {
final int N_ITERATIONS = 100;
#Override
protected Void call() throws Exception {
for (int i = 0; i < N_ITERATIONS; i++) {
updateProgress(i + 1, N_ITERATIONS);
// sleep is used to simulate doing some work which takes some time....
Thread.sleep(10);
}
return null;
}
};
final ProgressBar progress = new ProgressBar();
progress.progressProperty().bind(
task.progressProperty()
);
// color the bar green when the work is complete.
progress.progressProperty().addListener(observable -> {
if (progress.getProgress() >= 1 - EPSILON) {
progress.setStyle("-fx-accent: forestgreen;");
}
});
// layout the app
final StackPane layout = new StackPane(progress);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
final Thread thread = new Thread(task, "task-thread");
thread.setDaemon(true);
thread.start();
}
public static void main(String[] args) {
launch(args);
}
}
what if the task makes call to a method that does only a single job , and do not want it to be called again and again?
Then remove the loop and invoke updateProgress through multiple calls within the job as the job progresses. The loop is only present in this sample for demonstration purposes and because this is what the original question specifically asked about.
For example lets say your job has 3 stages: fetch from database, perform calculation and accumulate results. Each stage taking an estimated 30 percent, 60 percent and 10 percent of total time respectively, then you can do something like this within the call() body of your task:
updateProgress(0, 1.0);
Data data = db.fetchData(query);
updateProgress(0.3, 1.0);
ProcessedData processed = calculator.process(data);
updateProgress(0.9, 1.0);
Result result = accumulator.reduce(processed);
updateProgress(1.0, 1.0);
Quotation from Java Doc:
The actual progress of the ProgressIndicator. A negative value for progress indicates that the progress is indeterminate. A positive value between 0 and 1 indicates the percentage of progress where 0 is 0% and 1 is 100%. Any value greater than 1 is interpreted as 100%.
That means in simple words, you must divide you value with 100, or you just increment the value by 0.05 instead of 0.5.
Happy Coding,
Kalasch
My friend show me example of using that. You could do this:
Platform.runLater(new Runnable() {
#Override public void run() {
bar.setProgress(counter/1000000.0);
}
});
And the refresh progress bar is in other Thread
Related
I have a problem with implementation of my Game of Life in Java.
In GUI I have buttons which decide of inicial state of the game (oscilator, glider etc), then using Action Listener I set the first board and show it.
Then I have a function that count neighbours of my cell and set colors of my cells.
But I have a problem when I want to repeat game n times, because I don't know how to set time interval.
At this moment I don't see every step of game, but just the last one.
Below is my ActionListener:
private ActionListener buttonsListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == button1)area = setButton1(getBoardWidth(), getBoardHeight());
if (source == glider) area = setGlider(getBoardWidth(), getBoardHeight());
if (source == oscilator) area = setOscilator(getBoardWidth(), getBoardHeight());
setBoard(area, board);
}
};
Function setBoard() takes array of ints with 0 and 1, and convert it to JButton[][] array with colors.
I tried to use Overrided method run() that include startTheGame() function, which checks neighbourhood and set array of ints. I need to do this multiple times but I can't set time intervals.
#Override
public void run() {
startTheGame(area);
setBoard(area, board);
}
You should use this timer schedule.
So you have to define a custom TimerTask like this:
import java.util.TimerTask;
public class UserTimerTask extends TimerTask{
#Override
public void run() {
startTheGame(area);
setBoard(area, board);
}
}
And then wrapping your code like this:
// daemon means, background. If every task is a demon task, the VM will exit
Bolean isDaemon = false;
Timer timer = new Timer("nameOfThread",isDaemon);
TimerTask task = new UserTimerTask();
// Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay
// both parameters are in milliseconds
timer.schedule(task,0,1000);
I have problem with updating JavaFX UI - I want to update line chart and some labels on my scene when it's already shown.
My task is to do some calculations (calling function in other class which returns dataseries) and add updated series to the chart.
The following code (which is in a loop) may present what i want to do:
//double x - x value of the point i want to add to my chart
//double y - y value of the point i want to add to my chart
//string s - some result from function
mySeries.getData().add(new XYChart.Data(x, y));
someLabel.setText(s);
My program freezes and give only final solution after some time, but i want to see the points on the chart exactly after they're added, not at the end of the execution. If the process is too quick, i would like to add Thread.sleep(1000) before adding the next point to the chart.
I know it has something to do with threads, concurrency and tasks, but i wasn't able to find a solution yet. I tried to use some code I found here but still I don't know the correct answer.
Every user action, e.g. click a button, will notify your action listener within the UI thread. Logic in the UI thread should be as fast as possible. I think you are reacting on a user event and then execute a long running task in the UI thread. Try to put your code in a background thread. Further you need to put the UI updates back again in the UI thread. You can do this with "Platform.runLater(...)".
Something like this:
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(createChart());
primaryStage.setScene(scene);
primaryStage.setHeight(800);
primaryStage.setWidth(1200);
primaryStage.show();
}
private Parent createChart() {
LineChart<Number, Number> lc = new LineChart<>(new NumberAxis(), new NumberAxis());
XYChart.Series<Number, Number> series = new XYChart.Series<>();
lc.getData().add(series);
new Thread(() -> {
try {
Thread.sleep(5000);
for (int i = 0; i < 15; i++) {
int finalI = i;
Platform.runLater(() -> series.getData().add(new XYChart.Data<>(1 + finalI, 1 + finalI)));
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
return lc;
}
}
Hello!
I am trying to display a text on the Screen (with Java), but I want it to be delayed, like, every 0.1 seconds, a letter of the text would appear on the screen. It's like Pokemons dialogs. Here's what I am talking about: https://www.youtube.com/watch?v=yUS1IcC5CBY
I don't want the fade and the acceleration of the text, I just want the text to appear letter-by-letter. Also, I would like the text to be a String. Please, can you help me?
Thanks a lot in advance!
You can use two methods:
One is Thread.sleep(), which is shown above:
private static String message = "Your Message";
private static JLable label = new JLabel();
private static String labelMessage = "";
for(int i = 0; i < message.length(); i++){
labelMessage += Character.toString(message.charAt(i));
label.setText(labelMessage);
try{
Thread.sleep(howManyMillisecondsYouShouldWait);//if you want to do it every .1
//seconds, just wait 100 milliseconds.
}catch(InterruptedException e){
Thread.currentThread().interrupt();
}
}
that will forever print it to the screen every 100 milliseconds. However, the only trouble with using Thread.sleep is (and I somehow just learned this the other day, even though I've been programming for a long while) it is not always accurate. It may sleep 100 ms, it may sleep 150, etc. Secondly, a slower computer may take longer to sleep through it.
The other method which you will use more often (probably) is to check the actual time of your system and see if it's been long enough since you last printed it to the screen, like this:
private static long timeOfLastWrite;//at what time did you last update the text?
private static long deltaTimeSinceLastWrite;//how long has it been since you last updated the text?
private static long timeOfFirstWrite;//when did you start?
private static long deltaTimeSinceFirstWrite;//how long has it been since you started?
private static String message = "Your Message";
private static JLabel label = new JLabel();
private static String labelMessage = "";
//print once here:
timeOfFirstWrite = System.currentTimeMillis();
timeOfLastWrite = System.currentTimeMillis();//every time you print to the screen, make
//sure that you make note of it by setting the timeOfLastWrite variable equal to the current time.
labelMessage += Character.toString(message.chatAt(0));
while(!labelMessage.equals(message)){
deltaTimeSinceLastWrite = System.currentTimeMillis() - timeOfLastWrite;
if(deltaTimeSinceLastWrite >= 100){
timeOfLastWrite = System.currentTimeMillis();
deltaTimeSinceFirstWrite = System.currentTimeMillis() - timeOfFirstWrite;
int currentIndexOfChain = (int) deltaTimeSinceFirstWrite / 100;
if(currentIndexOfChain >= message.length()){
currentIndexOfChain = message.length() - 1;
}
labelMessage = message.substring(0, currentIndexOfChain + 1);
label.setText(labelMessage);
}
}
This method isn't even slightly necessary for a program so simple as writing text to the screen 10 times a second. However, it's good to get into the practice of it. You'll learn that if you create a character and tell him to move 10 pixels, Thread.sleep(100), and move again and etc... that on a slower computer, the character will move slower. However, if you tell it to wait until a certain amount of time has passed according to your computer's time, if the user lags out and it takes 200 milliseconds before it tells the character to move again, you can account for that by simply making him move twice as far -- I think it's called framerate independence.
If I did anything wrong with the delta time management please let me now. Again, I just learned about this the other day even though I've been programming for awhile, so don't worry about it too much if you're just now learning to program.
And that's how you make an incredibly long (possibly too long) answer to an incredibly simple question. I hope you benefit from this response.
I'm unable to use Thread.sleep(x) or wait(): java.lang.InterruptedException; must be caught or declared to be thrown
try {
Thread.sleep(100);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
You may use this code for doing so. Simply put a thread to print the text onto a jLabel.
new Thread(new Runnable() {
#Override
public void run() {
String x="";
String txt="Hello this is a sample text. Let us see how this works.";
for(int i=0;i<txt.length();i++){
try {
jLabel1.setText(x=x+txt.charAt(i));
Thread.sleep(100);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}).start();
How about this?
import javax.swing.Timer;
import java.awt.event.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class DelayText
{
public String example = "As you can see, this sentence is being printed out a character at a time.";
public String transfer = "";
public Timer t;
public int i = 0;
public JFrame f;
public JLabel l;
public DelayText()
{
f = new JFrame("Example");
l = new JLabel();
f.add(l);
f.setSize(450, 200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
TimerListener tl = new TimerListener();
t = new Timer(100, tl);
t.start();
}
public static void main(String[] args)
{
DelayText d = new DelayText();
}
private class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(i < example.length())
{
transfer += (example.charAt(i));
l.setText(transfer);
i++;
}
if(i >= example.length())
{
t.stop();
}
}
}
}
I am using the timer to create a delay between each character outputted on the JFrame. I noticed a lot of these other ones were a bit more complex, thought this might make things a bit easier to understand.
I made CountDown.java file and try to add in my Word-trouble.java file (which is main applet) as CountDown ct = new CountDown();
but it is not showing timer in main applet.
Here is coding:
package pack.urdu;
import java.awt.*; //windows toolkit
import java.applet.*; //applet support
public class CountDown extends Applet implements Runnable{
int counter; Thread cd;
public void start() { // create thread
counter = 60; cd = new Thread(this); cd.start();
}
public void stop() { cd = null;}
public void run() { // executed by Thread
while (counter>0 && cd!=null) {
try{Thread.sleep(1000);} catch (InterruptedException e){}
--counter; repaint(); //update screen
}
}
public void paint(Graphics g) {
g.drawString(String.valueOf(counter),25,75);
}
}
You are making a mistake that I see a lot of programmers make: you are mixing up the calculation of elapsed time, with the calculation of the refresh time. If the duration of sleep takes long than a second because of thread contention, your timer will drift.
Instead of tracking a counter that increments every second, just record the start time:
long startTime = System.currentTimeMillis();
Then later, your paint method becomes:
public void paint(Graphics g) {
int elapsedSeconds = (int)(System.currentTimeMillis()-startTime)/1000
g.drawString(String.valueOf(elapsedSeconds),25,75);
}
This method can be called as often, and as many times as you like, and it will always display the correct elapsed seconds. There is no need to increment anything at any specified time.
The only other thing you have to do is to arrange that the screen gets refreshed. (I like to say that you only have to refresh the screen when the user looks at it :-) but since we don't know that we need to refresh more often). The mechanism for this may depend upon the graphic library. One lazy idea is to refresh ten times a second and the screen will be right most of the time.
If you do want to have a thread that sends repaint events, you should have those events sent just at the time that timer clicks over to a new value, and thereby send only one per second. This is done with:
while (stillRunning) {
long elapsedTime = System.currentTimeMillis() - startTime;
long timeTillNextDisplayChange = 1000 - (elapsedTime % 1000);
Thread.sleep(timeTillNextDisplayChange);
repaint();
}
Note that you do not sleep 1000ms! If your system is performing well, this will be very close to 1000ms, but slightly less than that to account for (1) the thread startup delay, possibly caused by thread contention, and (2) the processing time for this loop (which is quite small). In any case, calculating the sleep in this way will prevent timer drift, and assure that your display updates just as the seconds value changes.
See an extended discussion of Common Misunderstandings of Timers on my website.
in c++ or c programming language, we know to change the cordinate we use gotoxy(x,y) and we can use looping and sleep to change the cordinate and making animation. like this;
for(x = 20; x < 25; x++){
gotoxy(x,20); cout << "*"
}
but my queston is how about in JAVAFX 2.0 programming? i'm using netbeans 7.2.
thanks for your any help.
Use the JavaFX Animation Package.
There are numerous examples in the JavaFX Animation Tutorial, as Andy pointed out in his comment.
And there is a cute example of a running horse animation loop.
The key is that you don't sleep the JavaFX application thread and you have to release control of the JavaFX thread back to the JavaFX system each time you update something and want it rendered. The JavaFX animation classes take care of these things for you so that you don't have to worry about it. If you just loop like you do in the sample code from your question, JavaFX will just render the scene once after your loop has completed and you will never see anything happen.
Here is a fairly boring example which uses a Timeline to emulate the c++ code in your question to move a dot a pixel every 400 milliseconds.
import java.util.Date;
import javafx.animation.*;
import javafx.application.Application;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
/** Simple JavaFX Animation Sample. */
public class AnimationSample extends Application {
private int x = 20;
private String status = "";
private final Circle dot = new Circle(20, 20, 3);
private final TimeCounter counter = new TimeCounter();
public static void main(String[] args) throws Exception { launch(args); }
#Override public void start(final Stage stage) throws Exception {
final Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, new EventHandler() {
#Override public void handle(Event event) {
refreshScene();
}
}),
new KeyFrame(Duration.millis(400))
);
timeline.setCycleCount(Timeline.INDEFINITE);
stage.setScene(new Scene(new Group(dot), 50, 50));
stage.show();
counter.reset();
timeline.play();
}
private void refreshScene() {
gotoxy(x, 20);
status = "*****".equals(status) ? "*" : status + "*";
System.out.println(String.format("%7d", counter.elapsed()) + " ms " + x + " " + status);
if (x == 24) {
x = 20;
} else {
x++;
}
}
private void gotoxy(int x, int y) {
dot.setCenterX(x);
dot.setCenterY(y);
}
class TimeCounter {
private long start = new Date().getTime();
void reset() { start = new Date().getTime(); }
long elapsed() { return new Date().getTime() - start; }
}
}
There are three different options in JavaFX, depending on your needs.
The most basic one is AnimationTimer. It's equivalent to Swing's Timer. It simply contains a handle method which is called on every frame, and passed current time as argument. You probably want some internal bookkeeping so that you do not do expensive calculations every time handle is called.
Transition has an interpolate(frac) method, which gets called with values of frac between 0.0 and 1.0. It's up to you to do all UI changes you want to, based on the frac value. Both Transition and Timeline extend Animation, so you can set stuff like cycle duration, whether the Transition is reversed at end, etc.
Timeline is the most complex one. You define arbitrary amount of KeyFrames (think of states) that contain wanted properties of different Nodes, and the Timeline will do all the work for you interpolating how to animate the change between the provided values. For example, you can give a keyframe where x property of a Node is 0, and another where it's 100, and Timeline will do the animating for you.
Have look at using a Timeline Animation. It is a key component of animation in JavaFX and
is used to establish when, and in what sequence, key parts of an animation occur.
Here is an example