2016-12-03 184 views
1

我一直在尝试使用场景生成器使用JavaFX创建一个计时器,但是我一直在创建线程时遇到了一些问题。每当我点击开始按钮,应用程序就会落后,永远不会真正更新文本。我一直在尝试使用Platform.runLater(),但正如前面提到的,一切都落后了,因此。JavaFX计时器线程问题

这里是控制定时器,链接到特定的按钮上FXML文件的方法:

@FXML 
private void startTimer(){ 
    System.out.println("started"); 
    stopWatch.startTimer(); 

} 

@FXML 
private void pauseTimer(){ 
    stopWatch.pauseTimer(); 
} 

@FXML 
private void stopTimer(){ 
    System.out.println("stopped"); 
    stopWatch.stopTimer(); 
} 

@FXML 
public void updateTimer(long dT){ 

    //System.out.println(((dT/6000)%1000)+":"+String.valueOf((dT/1000)%1000)+","+String.valueOf((dT)%1000)); 
    Platform.runLater(() ->{ 
     timer.setText(String.valueOf(dT/1000)); 
    }); 
} 

这里是StopWatch.java类:

package sled.timer.address.model; 

import sled.timer.address.view.PersonOverviewController; 

public class StopWatch implements Runnable{ 

private Thread runThread; 
public boolean running = false; 
public boolean paused = false; 


private long summedTime = 0; 

PersonOverviewController personOverviewController; 

String time = ""; 

public void count(){ 

} 
public StopWatch(PersonOverviewController personOverviewController){ 
    this.personOverviewController = personOverviewController; 

} 
public void startTimer(){ 
    running = true; 
    paused = false; 

    runThread = new Thread(this); 
    runThread.start(); 
} 

public void pauseTimer(){ 
    paused = true; 
} 

public void stopTimer(){ 
    running = false; 
    paused = false; 
} 
@Override 
public void run() { 
    // TODO Auto-generated method stub 
    long startTime = System.currentTimeMillis(); 
    while(running && !paused){ 
     personOverviewController.updateTimer(summedTime + (System.currentTimeMillis() - startTime)); 
    } 
    if(paused) 
     summedTime += System.currentTimeMillis() - startTime; 

    else 
     summedTime = 0; 

} 

public long getSummedTime(){ 
    return summedTime; 
} 

任何帮助表示赞赏。

回答

0

您不限制线程的更新频率。通过这种方式,您可以发布很多Runable以便执行应用程序线程,因此几乎没有时间执行事件处理和布局,从而使您的应用程序以这种方式运行。

此外,您不会同步对布尔标志的访问,也不会使它们成为volatile,这意味着值更改不一定对其他线程可见。

相反,你应该确保没有更多的更新张贴直到最后Runnable已经启动:

private final Object updaterLock = new Object(); 
private final boolean updating = false; 
private final long value; 

public void updateTimer(long dT) { 
    synchronized (updaterLock) { 
     value = dT; 
     if (!updating) { 
      updating = true; 
      Platform.runLater(() -> { 
       synchronized (updaterLock) { 
        updating = false; 
        timer.setText(Long.toString(value/1000)); 
       } 
      }); 
     } 
    } 
} 
public class StopWatch implements Runnable{ 

    ... 

    public volatile boolean running = false; 
    public volatile boolean paused = false; 

但是考虑使用the AnimationTimer class做更新。此课程的更新频率有限。