JavaFX并发:从Service更新多条消息

时间:2016-01-30 07:18:39

标签: java javafx

我们如何从单个服务更新多个控件。现在Service中只有一个Base,其值只能绑定到一个控件,因此只更新。我们如何更新多个控件的值?

我的服务类实例:

Child

这只更新一条消息,即我只能绑定一个标签。有什么办法可以从同一个线程更新多个消息,这样我就可以在我的UI中绑定多个标签了吗?

已编辑 - 根据评论提供更多信息

我的运行是:

updateMessage()

我运行一个线程来改变//run a background thread threadTimeChecker = new Service<Void>() { @Override protected Task<Void> createTask() { return new Task<Void>() { @Override protected Void call() throws Exception { while (!isDone) { DataHelper.setCurrentDate(LocalDate.now()); if(!DataHelper.getOldDate().equals(DataHelper.getCurrentDate())) { DataHelper.setIntIndex(DataHelper.getIntIndex()+1); DataHelper.setOldDate(DataHelper.getCurrentDate()); DataHelper.saveData(); System.out.println("Saved!"); } //Thread.currentThread().sleep(2000); updateMessage(wordString.getValue()); } return null; } }; } }; threadTimeChecker.restart(); //bind string properties to labels word.textProperty().bind(threadTimeChecker.messageProperty()); ,它调用一个监听器,根据索引改变'String Property':

@Override
protected Task<Void> createTask() {
    return new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            //loop run until the program is closed
            while (!isDone) {
                DataHelper.setCurrentDate(LocalDate.now());
                if (!DataHelper.getOldDate().equals(DataHelper.getCurrentDate())) {
                    Platform.runLater(new Runnable(){
                        @Override
                        public void run() {
                            DataHelper.setIntIndex(DataHelper.getIntIndex()+1);
                        }
                    });
                    DataHelper.setOldDate(DataHelper.getCurrentDate());
                    DataHelper.saveData();
                }
                Thread.currentThread().sleep(5000);
            }
            return null;
        }
    };
}

我已经使用这些'String Properties'来绑定三个不同的标签,如:

DataHelper.IntIndex

现在我想做的是使用更多 JavaFX 倾斜 //listener to detect change in index and assign strings of word,meaning, and sentence, accordingly DataHelper.intIndexProperty().addListener( (v, oldValue, newValue) -> { wordString.setValue(DataHelper.getListOfWords().get((int) newValue).get("word")); meaningString.setValue(DataHelper.getListOfWords().get((int) newValue).get("meaning")); sentenceString.setValue(DataHelper.getListOfWords().get((int) newValue).get("sentence")); System.out.print("kjbmmj"); } ); 来实现同样目标。

1 个答案:

答案 0 :(得分:3)

我们只需要更新DataHelper的单个实例,而不是更新多条消息。 DataHelper具有将更新多个标签的内容。例如,让我们考虑在每次服务调用后我们要更新以下标签:

  • wordLabel
  • meaningLabel
  • sentenceLabel

为了简单起见,让我们考虑一下你有一个DataHelper类,它有三个属性词,含义和句子。

private class DataHelper {

   public DataHelper(String word, String meaning, String sentence) {
        this.word.setValue(word);
        this.meaning.setValue(meaning);
        this.sentence.setValue(sentence);
    }

   StringProperty word = new SimpleStringProperty();
   StringProperty meaning = new SimpleStringProperty();
   StringProperty sentence = new SimpleStringProperty();
   // setters and getters
}

我们将服务称为后台任务,每当使用后台任务完成服务时,它都会返回更新的DataHelper。

Service<DataHelper> service = new Service<DataHelper>() {
    @Override
    protected Task<DataHelper> createTask() {
        return new Task<DataHelper>() {
            @Override
            protected DataHelper call() throws Exception {
                i.incrementAndGet(); // Don't worry about i here 
                return new DataHelper("Word " + i, "Meaning " + i, "Sentence " + i);
            }
        };
    }
};

现在,每当我们调用服务器时,我们都会获得一个更新的DataHelper,我们希望在标签上显示。

为了解决这个问题,我们声明了一个变量dataHelper并将其属性绑定到各种标签的textProperty()

DataHelper dataHelper = new DataHelper("Word", "Meaning", "Sentence");
wordLabel.textProperty().bind(dataHelper.wordProperty());
meaningLabel.textProperty().bind(dataHelper.meaningProperty());
sentenceLabel.textProperty().bind(dataHelper.sentenceProperty());

现在您一定想知道,我们将如何更新dataHelper,对吧?嗯,这是最简单的部分。这可以在setOnSucceeded()服务中谨慎处理,其中getValue()会向我们返回DataHelper的新实例,其中 已更新

service.setOnSucceeded(event -> {
    dataHelper.setWord(service.getValue().getWord());
    dataHelper.setMeaning(service.getValue().getMeaning());
    dataHelper.setSentence(service.getValue().getSentence());
});

完成MCVE:

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.concurrent.atomic.AtomicInteger;

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {

        // Properties
        DataHelper dataHelper = new DataHelper("Word", "Meaning", "Sentence");
        AtomicInteger i = new AtomicInteger(0);

        // UI elements
        Label wordLabel = new Label();
        Label meaningLabel = new Label();
        Label sentenceLabel = new Label();
        Button startService = new Button("Start");

        Service<DataHelper> service = new Service<DataHelper>() {
            @Override
            protected Task<DataHelper> createTask() {
                return new Task<DataHelper>() {
                    @Override
                    protected DataHelper call() throws Exception {
                        i.incrementAndGet();
                        return new DataHelper("Word " + i, "Meaning " + i, "Sentence " + i);
                    }
                };
            }
        };

        startService.setOnAction(e -> {
            if(service.getState().equals(Worker.State.READY) || service.getState().equals(Worker.State.SUCCEEDED)) {
                service.restart();
            }
        });

        service.setOnSucceeded(event -> {
            dataHelper.setWord(service.getValue().getWord());
            dataHelper.setMeaning(service.getValue().getMeaning());
            dataHelper.setSentence(service.getValue().getSentence());
        });

        wordLabel.textProperty().bind(dataHelper.wordProperty());
        meaningLabel.textProperty().bind(dataHelper.meaningProperty());
        sentenceLabel.textProperty().bind(dataHelper.sentenceProperty());

        VBox box = new VBox(10, wordLabel, meaningLabel, sentenceLabel, startService);
        box.setAlignment(Pos.CENTER);
        Scene scene = new Scene(box, 200, 200);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private class DataHelper {
        StringProperty word = new SimpleStringProperty();
        StringProperty meaning = new SimpleStringProperty();
        StringProperty sentence = new SimpleStringProperty();

        public DataHelper(String word, String meaning, String sentence) {
            this.word.setValue(word);
            this.meaning.setValue(meaning);
            this.sentence.setValue(sentence);
        }

        public String getMeaning() {
            return meaning.get();
        }

        public StringProperty meaningProperty() {
            return meaning;
        }

        public void setMeaning(String meaning) {
            this.meaning.set(meaning);
        }

        public String getSentence() {
            return sentence.get();
        }

        public StringProperty sentenceProperty() {
            return sentence;
        }

        public void setSentence(String sentence) {
            this.sentence.set(sentence);
        }

        public String getWord() {
            return word.get();
        }

        public StringProperty wordProperty() {
            return word;
        }

        public void setWord(String word) {
            this.word.set(word);
        }
    }

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