如何使用javafx中的进度指示器等待某些操作完成?
我有一个向服务器发送命令的代码如何使用javafx中的进度指示器等待某些操作完成?,java,sockets,javafx,Java,Sockets,Javafx,我有一个向服务器发送命令的代码 public static void createAndSendCommand(String action, byte[] data) { if (action.equals(OE_Constants.ACTION_UPDATE)) { File file = new File(OE_Constants.FILE_BACKUP_TOPOLOGY); Command command = ConnectionManager.po
public static void createAndSendCommand(String action, byte[] data) {
if (action.equals(OE_Constants.ACTION_UPDATE)) {
File file = new File(OE_Constants.FILE_BACKUP_TOPOLOGY);
Command command = ConnectionManager.populateData(file);
FrontEndClient.sendCommandToServer(command);
}
}
及
我收到的结果如下
public void receiveResultFromServer() {
try {
while(!clientSocket.isClosed()) {
CommandExecResult result;
try {
result = (CommandExecResult) inStream.readObject();
ConnectionManager.parseCommandExecutionResult(result);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
现在,我想等待命令在服务器上成功执行,直到客户端收到命令的结果。我想展示一些进度指示器类型的UI…如何做到这一点?
谢谢
对于长时间运行的服务器调用,请使用。
用于通知当前进度/完成的工作。
将正在运行的任务的绑定到或。
您指定了标记java和javafx。这是我的javafx解决方案。这是一个简单的对话框,可以通过绑定从“外部”进行更新 WorkingDialog.java:
package stackoverflow.progress;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
public final class WorkingDialog extends Stage implements Initializable {
private static final Logger LOG = Logger.getLogger(WorkingDialog.class.getName());
public SimpleDoubleProperty progress = new SimpleDoubleProperty(0);
public WorkingDialog(String title, Stage owner) {
super();
setTitle(title);
initStyle(StageStyle.UTILITY);
initModality(Modality.APPLICATION_MODAL);
initOwner(owner);
double w = 300;
double h = 200;
setWidth(w);
setHeight(h);
double dx = (owner.getWidth() - w) / 2;
double dy = (owner.getHeight() - h) / 2;
setX(owner.xProperty().get() + dx);
setY(owner.yProperty().get() + dy);
setResizable(false);
showDialog(progress);
}
public void hideDialog() {
Platform.runLater(() -> {
hide();
});
}
public void setTitleText(String title) {
Platform.runLater(() -> {
setTitle(title);
});
}
private void showDialog(SimpleDoubleProperty progress) {
//scene : gridPane : 0,0->progressbar,0,1->borderpane : center->button
GridPane gridPane = new GridPane();
gridPane.setGridLinesVisible(false);
gridPane.setPadding(new Insets(10));
gridPane.setHgap(5);
gridPane.setVgap(5);
setOnCloseRequest((WindowEvent e) -> {
e.consume();
});
ProgressBar pb = new ProgressBar(-1);
pb.setPrefWidth(300);
pb.progressProperty().bind(progress);
BorderPane borderPane = new BorderPane(pb);
gridPane.add(borderPane, 0, 0);
Scene scene = new Scene(gridPane);
setScene(scene);
sizeToScene();
show();
}
@Override
public void initialize(URL location, ResourceBundle resources) {
}
}
WorkingDialogTest.java的用法示例:
package stackoverflow.progress;
import java.util.logging.Logger;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class WorkingDialogTest extends Application {
private static final Logger LOG = Logger.getLogger(WorkingDialogTest.class.getName());
@Override
public void start(Stage primaryStage) {
Group group = new Group();
Scene scene = new Scene(group);
primaryStage.setTitle("Dialogs");
primaryStage.setWidth(600);
primaryStage.setHeight(400);
Button button = new Button("function");
button.setOnAction((ActionEvent e) -> {
WorkingDialog wd = new WorkingDialog("title", primaryStage);
new Thread(() -> {
int counter = 10;
for (int i = 0; i < counter; i++) {
try {
wd.progress.set(1.0 * i / (counter - 1));
Thread.sleep(1000); //<-------- do more useful stuff here
} catch (InterruptedException ex) {
}
}
wd.hideDialog();
}).start();
});
HBox hbox = new HBox(button);
group.getChildren().addAll(hbox);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
看起来是这样的:
这不是从后台线程而不是从FX应用程序线程更新进度条吗?我认为更新进度的“命令”是在创建新工作对话框后直接启动的新线程中给出的。这是保持ui活动所必需的。这应该不是问题-你为什么要问?如果包含进度条的ui是从FX应用程序线程外部更新的,它违反了JavaFX的线程规则,并且行为是不确定的。我明白了。。。这可能会导致问题,例如tableview.getColumns.add。。。。如果我做了这些事情,我会得到一个java.lang.IllegalStateException:不在FX应用程序线程上。。。这是通过使用Platform.runLater解决的吗。。。?我的意思是它可以工作,但我应该这样做吗?你应该使用Platform.runLater更新FX应用程序线程上进度条的进度属性。。。在某处由于您使WorkingDialog类中的所有其他内容都是线程安全的,所以更新其progress属性也应该是线程安全的,尽管这很棘手。为什么不使用@eckig建议的方法呢?这将为您处理所有线程安全问题,以及更多问题,例如,它限制了对updateProgress的太多调用,因此FX应用程序线程不会被淹没,而您的代码不会这样做。
package stackoverflow.progress;
import java.util.logging.Logger;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class WorkingDialogTest extends Application {
private static final Logger LOG = Logger.getLogger(WorkingDialogTest.class.getName());
@Override
public void start(Stage primaryStage) {
Group group = new Group();
Scene scene = new Scene(group);
primaryStage.setTitle("Dialogs");
primaryStage.setWidth(600);
primaryStage.setHeight(400);
Button button = new Button("function");
button.setOnAction((ActionEvent e) -> {
WorkingDialog wd = new WorkingDialog("title", primaryStage);
new Thread(() -> {
int counter = 10;
for (int i = 0; i < counter; i++) {
try {
wd.progress.set(1.0 * i / (counter - 1));
Thread.sleep(1000); //<-------- do more useful stuff here
} catch (InterruptedException ex) {
}
}
wd.hideDialog();
}).start();
});
HBox hbox = new HBox(button);
group.getChildren().addAll(hbox);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}