Multithreading JavaFX中实时图形和其余元素的并发性?

Multithreading JavaFX中实时图形和其余元素的并发性?,multithreading,javafx,javafx-2,real-time-data,Multithreading,Javafx,Javafx 2,Real Time Data,这是我使用JavaFX的第一步,我试图用JavaFX创建一个简单的桌面应用程序,它模拟一种实时的条形图,每秒刷新一次,添加代表每个传感器状态的条形图部分(关闭、不工作、正常工作…)。我必须实现一些按钮/文本字段/菜单项,以便向传感器和应用程序发送信息 因此,在将画布添加到场景之前,我使用了一个从start()方法调用的方法,在这里我每秒调用一个TimerTask来绘制图形,效果很好。这样,当我尝试将此画布设置在边框窗格的中心时,并将其他元素添加到窗格的另一部分时,它们的工作会受到时间任务延迟的影

这是我使用JavaFX的第一步,我试图用JavaFX创建一个简单的桌面应用程序,它模拟一种实时的条形图,每秒刷新一次,添加代表每个传感器状态的条形图部分(关闭、不工作、正常工作…)。我必须实现一些按钮/文本字段/菜单项,以便向传感器和应用程序发送信息

因此,在将画布添加到场景之前,我使用了一个从start()方法调用的方法,在这里我每秒调用一个TimerTask来绘制图形,效果很好。这样,当我尝试将此画布设置在边框窗格的中心时,并将其他元素添加到窗格的另一部分时,它们的工作会受到时间任务延迟的影响,即使此时间任务可能由不同的线程执行

如何在不同的线程中将实时绘图与应用程序的其余部分分开??我应该使用另一个不同于“TimerTask”的类吗

代码如下所示:

@Override
public void start(Stage primaryStage) {
    this.primaryStage = primaryStage;
    BorderPane bp = new BorderPane();
    Group root = new Group();

    // create a canvas node
    Canvas canvas = new Canvas();

    // bind the dimensions when the user resizes the window.
    canvas.widthProperty().bind(primaryStage.widthProperty());
    canvas.heightProperty().bind(primaryStage.heightProperty());

    // obtain the GraphicsContext (drawing surface)
    final GraphicsContext gc = canvas.getGraphicsContext2D();

    //Invoke the real time graph drawing
    draw(gc);

    // add the single node onto the border pane
    bp.setCenter(canvas);
    MenuBar bar = new MenuBar();
    Menu sensorsMenu = new Menu("Sensors");
    bar.getMenus().add(sensors);
    for(int i=0; i<nDetect; i++){
        sensorsMenu.getItems().add(new CheckMenuItem("Sensor " + (i+1)));
    }
    //add the menu bar to top
    bp.setTop(bar);
    root.getChildren().add(bp);

    Scene scene = new Scene(root);
    primaryStage.setScene(scene);
    primaryStage.show();
}

public void draw(GraphicsContext gc){
    c = new SerialPortConection();

    c.establishConnection("COM1", 2400, 8, 1, 1);
    LinkedList<String> resp = null;

        .
        .
        .

    timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            javafx.application.Platform.runLater(new Runnable() {
            @Override
            public void run() {
                //Send request to sensor
                try {
                    resp = c.sendStatusRequest();
                } catch (WrongFormatException ex) {
Logger.getLogger(Sensor.class.getName()).log(Level.SEVERE, null, ex);
                }
                //Update sensor status
                for(int i=0; i<nSensors; i++){
                    sensors.get(i).update(resp.get(37+i));
                }

                //Draw sensors status
                for(int i=0; i<nSensors; i++){
                    sensors.get(i).draw(gc);
                }
                //Paint axis
                .
                .
                .
            }
        });
        }
    }, 0, 1000);
}
@覆盖
公共无效开始(阶段primaryStage){
this.primaryStage=primaryStage;
BorderPane bp=新的BorderPane();
组根=新组();
//创建画布节点
画布=新画布();
//用户调整窗口大小时绑定尺寸。
canvas.widthProperty().bind(primaryStage.widthProperty());
canvas.heightProperty().bind(primaryStage.heightProperty());
//获取图形上下文(绘图表面)
final GraphicsContext gc=canvas.getGraphicsContext2D();
//调用实时图形绘制
抽签(gc);
//将单个节点添加到边框窗格中
设置中心(画布);
菜单栏=新菜单栏();
菜单传感器菜单=新菜单(“传感器”);
bar.getMenus().add(传感器);

对于(int i=0;i你可以看看这个答案:

使用
TimerTask
可以。您应该使用计时器线程(后台线程)调用外部服务的请求,并使用JFX线程更新图形:

    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            // call external service in the background thread
            resp = c.sendStatusRequest();
            javafx.application.Platform.runLater(new Runnable() {
            @Override
            public void run() {
                // update the graphics in the JFX thread
            }
        });
        }
    }, 0, 1000);

什么是resp和传感器?“resp”是串行端口请求的响应(作为表示每个字节值的十六进制字符串列表)。“传感器”是每个传感器的列表,“传感器”是一个不同颜色的矩形列表,表示传感器随时间的不同状态(有“传感器”类和“rectangle”类,但由于“drawing”工作正常,我想他们可以不讨论这个主题)然后
resp=c.sendStatusRequest();
可能需要一些时间来执行,因为它会等待请求。不是吗?如果是,您可能希望将其从
平台中删除。runLater()
,因为您在等待响应时阻塞了UI线程。通过将其放入
平台.runLater
,它将在同一UI线程中执行,而不是在不同的线程上执行。确切地说,大约650-700ms才能获得响应,我不知道平台的这个问题。runLater()1.谢谢你的答复这不是问题,而是工作原理。