不断更新TextArea

时间:2015-01-12 09:56:07

标签: concurrency javafx textarea task

我正在编写一个使用youtube-dl创建进程的程序。该进程有两个InputStream s(inputStream和errorStream),我想将它们重新路由到文本区域。

我一直试图在不锁定JavaFX线程的情况下更新TextArea。它正在工作,但我觉得它非常低效,因为它创建了大量的只附加一行的Task对象。我已经重新创建了我在下面使用的代码,使用List<String>代替BufferedReader来简化问题。

当我按下按钮时,它将创建两个线程,每个列表一个,带有UpdateTask。然后UpdateTask创建一个WriteTask,将它提供给Platform.runLater(),再将它放在JavaFX线程上。

当然必须有更好的方法来做到这一点?

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;

public class ConcurrentTest extends VBox{

    TextArea output;
    TextArea error;
    Button start;
    TextField writable;

    public ConcurrentTest(){
        // Init components
        output = new TextArea();
        output.setEditable(false);
        error = new TextArea();
        error.setEditable(false);
        // Init button
        start = new Button("Print stuff");
        start.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent arg0) {
                List<String> outputLines = Arrays.asList("A", "B", "C", "D");
                List<String> errorLines = Arrays.asList("A", "B", "C", "D");;

                Thread outputThread = new Thread(new UpdateTask<String>(output, outputLines));
                outputThread.setDaemon(true);
                outputThread.start();

                Thread errorThread = new Thread(new UpdateTask<String>(error, errorLines));
                errorThread.setDaemon(true);
                errorThread.start();
            }
        });
        writable = new TextField();
        writable.setPromptText("Write while some text areas are getting updated.");

        // Add components
        this.getChildren().addAll(output, error, start, writable);
    }

    // UPDATE TASK CLASS
    public class UpdateTask<V> extends Task<V>{

        TextArea target;
        Iterator<String> it;

        public UpdateTask(TextArea target, List<String> lines){
            this.target = target;
            it = lines.iterator();
        }

        @Override
        protected V call() throws Exception {
            while(it.hasNext()){
                Thread.sleep(1500);     // Time to type something to test
                Platform.runLater(new WriteTask<String>(target, it.next()));
            }
            return null;
        }

    }

    // WRITE TASK CLASS
    public class WriteTask<V> extends Task<V>{

        TextArea target;
        String line;

        public WriteTask(TextArea target, String line) {
            this.target = target;
            this.line = line;
        }

        @Override
        protected V call() throws Exception {
            target.appendText(line + "\n");
            return null;
        }
    }
}

对于整个程序,启动程序使用main:

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

public class ConcurrentTestLauncher extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            Parent root = new ConcurrentTest();
            Scene scene = new Scene(root);
            primaryStage.setTitle("Concurrent FX Test");
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

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

0 个答案:

没有答案