Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从服务线程更新JavaFXGUI_Java_Multithreading_Javafx - Fatal编程技术网

从服务线程更新JavaFXGUI

从服务线程更新JavaFXGUI,java,multithreading,javafx,Java,Multithreading,Javafx,如何从JavaFX服务中安全地更新JavaFXGUI上的小部件。我记得在使用Swing进行开发时,我使用“稍后调用”和其他各种Swing worker实用程序来确保在Java事件线程中安全地处理对UI的所有更新。下面是一个处理数据报消息的简单服务线程的示例。缺少的位是解析数据报消息和更新相应UI小部件的位置。正如您所看到的,服务类非常简单 我不确定是否需要使用简单的绑定属性(如消息),或者是否应该将小部件传递给StatusListenerService的构造函数(这可能不是最好的做法)。有人能给

如何从JavaFX服务中安全地更新JavaFXGUI上的小部件。我记得在使用Swing进行开发时,我使用“稍后调用”和其他各种Swing worker实用程序来确保在Java事件线程中安全地处理对UI的所有更新。下面是一个处理数据报消息的简单服务线程的示例。缺少的位是解析数据报消息和更新相应UI小部件的位置。正如您所看到的,服务类非常简单

我不确定是否需要使用简单的绑定属性(如消息),或者是否应该将小部件传递给StatusListenerService的构造函数(这可能不是最好的做法)。有人能给我一个很好的类似的例子,我会从中工作

public class StatusListenerService extends Service<Void> {
    private final int mPortNum;

    /**
     *
     * @param aPortNum server listen port for inbound status messages
     */
    public StatusListenerService(final int aPortNum) {
        this.mPortNum = aPortNum;
    }

    @Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                updateMessage("Running...");
                try {
                    DatagramSocket serverSocket = new DatagramSocket(mPortNum);
                    // allocate space for received datagrams
                    byte[] bytes = new byte[512];
                    //message.setByteBuffer(ByteBuffer.wrap(bytes), 0);
                    DatagramPacket packet = new DatagramPacket(bytes, bytes.length);                    
                    while (!isCancelled()) {                    
                        serverSocket.receive(packet);
                        SystemStatusMessage message = new SystemStatusMessage();
                        message.setByteBuffer(ByteBuffer.wrap(bytes), 0);                         
                    }
                } catch (Exception ex) {
                    System.out.println(ex.getMessage());
                }
                updateMessage("Cancelled");
                return null;
            } 
        };
    }
}
公共类StatusListenerService扩展服务{
私有最终整数mPortNum;
/**
*
*@param aPortNum服务器侦听入站状态消息端口
*/
公共状态ListenerService(最终int aPortNum){
this.mPortNum=aPortNum;
}
@凌驾
受保护的任务createTask(){
返回新任务(){
@凌驾
受保护的Void调用()引发异常{
更新消息(“正在运行…”);
试一试{
DatagramSocket serverSocket=新的DatagramSocket(mPortNum);
//为接收到的数据报分配空间
字节[]字节=新字节[512];
//message.setByteBuffer(ByteBuffer.wrap(字节),0);
DatagramPacket数据包=新的DatagramPacket(字节,字节.长度);
而(!isCancelled()){
接收(数据包);
SystemStatusMessage=新的SystemStatusMessage();
message.setByteBuffer(ByteBuffer.wrap(字节),0);
}
}捕获(例外情况除外){
System.out.println(例如getMessage());
}
更新消息(“已取消”);
返回null;
} 
};
}
}
低层方法是使用
Platform.runLater(Runnable r)
来更新UI。这将在FX应用程序线程上执行
r
,相当于Swing的
SwingUtilities.invokeLater(…)
。因此,一种方法就是从
call()
方法内部调用
Platform.runLater(…)
,并更新UI。正如您所指出的,这本质上要求服务了解UI的细节,这是不可取的(尽管有一些模式可以解决这一问题)

Task
定义了一些属性,并具有相应的
updatexx
方法,例如在示例代码中调用的
updateMessage(…)
方法。从任何线程调用这些方法都是安全的,并且会导致在FX应用程序线程上执行相应属性的更新。(因此,在您的示例中,您可以安全地将标签文本绑定到服务的
messageProperty
)以及确保在正确的线程上执行更新,这些
updateXXX
方法也会限制更新,因此,您可以根据自己的喜好随时调用它们,而不会让FX应用程序线程中充斥太多要处理的事件:在UI的单个框架内发生的更新将合并,以便只有最后一次这样的更新(在给定的框架内)可见

如果适合您的用例,您可以利用它来更新任务/服务的
valueProperty
。因此,如果您有一些(最好是不可变的)类来表示解析数据包的结果(我们称之为
PacketData
;但它可能像
字符串那样简单),那么您可以

public class StatusListener implements Service<PacketData> {

   // ...

   @Override
   protected Task<PacketData> createTask() {
      return new Task<PacketData>() {
          // ...

          @Override
          public PacketData call() {
              // ...
              while (! isCancelled()) { 
                  // receive packet, parse data, and wrap results:
                  PacketData data = new PacketData(...);
                  updateValue(data);
              }
              return null ;
          }
      };
   }
}
请注意,在取消服务时,代码会将值更新为
null
,因此在我介绍的实现中,您需要确保
valueProperty()
上的侦听器处理这种情况

还请注意,如果对
updateValue()
的连续调用发生在同一帧渲染中,则这将合并这些调用。因此,如果您需要确保处理处理程序中的每个数据(尽管通常不需要在FX应用程序线程上执行此类功能),那么这不是一种合适的方法。如果您的UI只需要显示后台进程的“最新状态”,那么这是一种很好的方法

SSCCE展示了这种技术:

import java.util.Random;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class LongRunningTaskExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        CheckBox enabled = new CheckBox("Enabled");
        enabled.setDisable(true);
        CheckBox activated = new CheckBox("Activated");
        activated.setDisable(true);
        Label name = new Label();
        Label value = new Label();

        Label serviceStatus = new Label();

        StatusService service = new StatusService();
        serviceStatus.textProperty().bind(service.messageProperty());

        service.valueProperty().addListener((obs, oldValue, newValue) -> {
            if (newValue == null) {
                enabled.setSelected(false);
                activated.setSelected(false);
                name.setText("");
                value.setText("");
            } else {
                enabled.setSelected(newValue.isEnabled());
                activated.setSelected(newValue.isActivated());
                name.setText(newValue.getName());
                value.setText("Value: "+newValue.getValue());
            }
        });

        Button startStop = new Button();
        startStop.textProperty().bind(Bindings
                .when(service.runningProperty())
                .then("Stop")
                .otherwise("Start"));

        startStop.setOnAction(e -> {
            if (service.isRunning()) {
                service.cancel() ;
            } else {
                service.restart();
            }
        });

        VBox root = new VBox(5, serviceStatus, name, value, enabled, activated, startStop);
        root.setAlignment(Pos.CENTER);
        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private static class StatusService extends Service<Status> {
        @Override
        protected Task<Status> createTask() {
            return new Task<Status>() {
                @Override
                protected Status call() throws Exception {
                    Random rng = new Random();
                    updateMessage("Running");
                    while (! isCancelled()) {

                        // mimic sporadic data feed:
                        try {
                            Thread.sleep(rng.nextInt(2000));
                        } catch (InterruptedException exc) {
                            Thread.currentThread().interrupt();
                            if (isCancelled()) {
                                break ;
                            }
                        }

                        Status status = new Status("Status "+rng.nextInt(100), 
                                rng.nextInt(100), rng.nextBoolean(), rng.nextBoolean());
                        updateValue(status);
                    }
                    updateMessage("Cancelled");
                    return null ;
                }
            };
        }
    }

    private static class Status {
        private final boolean enabled ; 
        private final boolean activated ;
        private final String name ;
        private final int value ;

        public Status(String name, int value, boolean enabled, boolean activated) {
            this.name = name ;
            this.value = value ;
            this.enabled = enabled ;
            this.activated = activated ;
        }

        public boolean isEnabled() {
            return enabled;
        }

        public boolean isActivated() {
            return activated;
        }

        public String getName() {
            return name;
        }

        public int getValue() {
            return value;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
import java.util.Random;
导入javafx.application.application;
导入javafx.beans.binding.Bindings;
导入javafx.concurrent.Service;
导入javafx.concurrent.Task;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.CheckBox;
导入javafx.scene.control.Label;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
公共类LongRunningTaskExample扩展了应用程序{
@凌驾
公共无效开始(阶段primaryStage){
复选框启用=新复选框(“启用”);
enabled.setDisable(true);
复选框激活=新复选框(“激活”);
激活。设置禁用(真);
标签名称=新标签();
标签值=新标签();
标签服务状态=新标签();
StatusService=新的StatusService();
serviceStatus.textProperty().bind(service.messageProperty());
service.valueProperty().addListener((obs、oldValue、newValue)->{
if(newValue==null){
enabled.setSelected(false);
激活。选择设置(假);
name.setText(“”);
value.setText(“”);
}否则{
enabled.setSelected(
import java.util.Random;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class LongRunningTaskExample extends Application {

    @Override
    public void start(Stage primaryStage) {
        CheckBox enabled = new CheckBox("Enabled");
        enabled.setDisable(true);
        CheckBox activated = new CheckBox("Activated");
        activated.setDisable(true);
        Label name = new Label();
        Label value = new Label();

        Label serviceStatus = new Label();

        StatusService service = new StatusService();
        serviceStatus.textProperty().bind(service.messageProperty());

        service.valueProperty().addListener((obs, oldValue, newValue) -> {
            if (newValue == null) {
                enabled.setSelected(false);
                activated.setSelected(false);
                name.setText("");
                value.setText("");
            } else {
                enabled.setSelected(newValue.isEnabled());
                activated.setSelected(newValue.isActivated());
                name.setText(newValue.getName());
                value.setText("Value: "+newValue.getValue());
            }
        });

        Button startStop = new Button();
        startStop.textProperty().bind(Bindings
                .when(service.runningProperty())
                .then("Stop")
                .otherwise("Start"));

        startStop.setOnAction(e -> {
            if (service.isRunning()) {
                service.cancel() ;
            } else {
                service.restart();
            }
        });

        VBox root = new VBox(5, serviceStatus, name, value, enabled, activated, startStop);
        root.setAlignment(Pos.CENTER);
        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private static class StatusService extends Service<Status> {
        @Override
        protected Task<Status> createTask() {
            return new Task<Status>() {
                @Override
                protected Status call() throws Exception {
                    Random rng = new Random();
                    updateMessage("Running");
                    while (! isCancelled()) {

                        // mimic sporadic data feed:
                        try {
                            Thread.sleep(rng.nextInt(2000));
                        } catch (InterruptedException exc) {
                            Thread.currentThread().interrupt();
                            if (isCancelled()) {
                                break ;
                            }
                        }

                        Status status = new Status("Status "+rng.nextInt(100), 
                                rng.nextInt(100), rng.nextBoolean(), rng.nextBoolean());
                        updateValue(status);
                    }
                    updateMessage("Cancelled");
                    return null ;
                }
            };
        }
    }

    private static class Status {
        private final boolean enabled ; 
        private final boolean activated ;
        private final String name ;
        private final int value ;

        public Status(String name, int value, boolean enabled, boolean activated) {
            this.name = name ;
            this.value = value ;
            this.enabled = enabled ;
            this.activated = activated ;
        }

        public boolean isEnabled() {
            return enabled;
        }

        public boolean isActivated() {
            return activated;
        }

        public String getName() {
            return name;
        }

        public int getValue() {
            return value;
        }
    }

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