Java swing timer: тексты не обновляются



Это первый раз, когда я использую таймер Java swing. Моя цель-обновлять метку один раз в секунду, но при запуске программы возникает ошибка. Чтобы убедиться, что это просто ошибки с ярлыками, я попытался вставить прогрессбар, который должен медленно заполняться, и это сработало. И как я должен поступить?



Это мой основной класс:



package Application;

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class main extends Application {

@Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/Interface/interface.fxml"));
Scene scene = new Scene (root);

primaryStage.setScene(scene);
primaryStage.show();
}

public static void main(String[] args) {
launch(args);
}
}


Вот главный контроллер моего документа fxml:



package Application;

import java.awt.event.ActionListener;
import java.net.URL;
import java.util.ResourceBundle;

import javax.swing.Timer;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;

public class MainController implements Initializable {

@Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub

}

@FXML
Label label;
double count = 0.0;

public void ok(ActionEvent event){
ActionListener action = new ActionListener(){

@Override
public void actionPerformed(java.awt.event.ActionEvent arg0) {
count+=0.1;
label.setText(count+"");
}
};

Timer timer = new Timer(1000, action);
timer.start();
}
}


Вот и все. У меня есть кнопка, которая должна запустить таймер " Таймер" то есть предполагается изменить надпись "label". Метод " ok " вызывается при нажатии кнопки. И, как я уже сказал, он должен запустить таймер.
Но когда я делаю это, я получаю ошибку:




Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue-0
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at Application.MainController$1.actionPerformed(MainController.java:46)
at javax.swing.Timer.fireActionPerformed(Unknown Source)
at javax.swing.Timer$DoPostEvent.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)



Что я могу сделать?

539   1  

1 ответ:

Подобно Swing, существуетспециальный поток, который вам нужно запустить "внутри", чтобы сделать ваши обновления пользовательского интерфейса - поток отправки событий Java FX, который обрабатывает все задачи, связанные с GUI.

Вам нужно использовать Platform.runLater() - здесь.

Другими словами: вам нужно определить Runnable это делает обновление; и затем вы передаете экземпляр этого Runnable в вышеупомянутый runLater().

Ваше сообщение об ошибке в основном говорит вам, что FX не хочет, чтобы вы делали обновления в любом другом потоке!

Кроме того: это не должно иметь прямого значения, но, вероятно, вам лучше использовать java.util.Timer вместо java.Swing.Timer.

EDIT: вам нужно что-то подобное этому; предполагая, что вы хотите, чтобы вещи запускались вашим методом ok ():

public void ok(ActionEvent event){
    final Runnable update = new Runnable() {
       @Override 
       public void run() {
         count+=0.1;
         label.setText(count+"");
        }
    };

   ActionListener delayedAction = new ActionListener(){
     @Override
     public void actionPerformed(java.awt.event.ActionEvent arg0) {
       Platform.runLater(update);
     }
   };

   new Timer(1000, delayedAction).start();
}

    Platform.runLater(update);
}

Вышесказанное делает:

A) создайте управляемый объект, который обновит ваш элемент пользовательского интерфейса

Б) использовать "известные" качели таймера вызов, что Runnable, используя нужную платформу.runLater() вызов

Это должно работать, но может потребовать некоторой тонкой настройки (код не компилируется и не тестируется).

Comments

    Ничего не найдено.