这是我的自定义对话框中的一个小示例,用于显示正在运行的javafx.concurrent.Task
的进度。
DialogPane pane = this.getDialogPane()
pane.getButtonTypes().addAll(ButtonType.CANCEL);
pane.headerTextProperty().bind(task.titleProperty());
pane.contentTextProperty().bind(task.messageProperty());
由于某种原因,按钮栏中的按钮消失了,但只是在更新了一些文本之后。经过进一步的调查,我发现绑定对话框的标题文本似乎可以删除按钮栏中的所有按钮。为什么会发生这种情况,我该怎么做才能阻止按钮被隐藏?
编辑:这是一个演示问题的MCVE。
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MCVE extends Application {
public static class CustomDialog extends Dialog<ButtonType> {
public CustomDialog(Task<?> task) {
this.initModality(Modality.APPLICATION_MODAL);
DialogPane pane = this.getDialogPane();
{
pane.getButtonTypes().addAll(ButtonType.CANCEL);
pane.headerTextProperty().bind(task.titleProperty());
}
setOnCloseRequest(event -> {
if (task.isRunning()) event.consume();
});
}
}
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
StackPane root = new StackPane();
Button starter = new Button("Showcase");
starter.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
root.getChildren().add(starter);
Scene scene = new Scene(root, 500, 500);
stage.setScene(scene);
stage.show();
starter.setOnAction(event -> {
Task<Void> task = new Task<>() {
@Override
protected Void call() throws Exception {
updateTitle("Before loop");
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
if (isCancelled()) return null;
}
for (int i = 1; i <= 20; i++) {
updateTitle("loop " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) {
if (isCancelled()) return null;
}
}
return null;
}
};
Thread worker = new Thread(task);
worker.start();
new CustomDialog(task).showAndWait();
});
}
}
这个问题似乎需要在JavaFX端进行修复。事实上,按钮栏只是被推到视图之外。不过,有一个相对不错的解决方法。Dialog
在内部使用样式化的GridPane
来显示标题文本和图形,所以我只是使用外部GridPane
复制它,并绑定到Label
的textProperty()
。
public static class CustomDialog extends Dialog<ButtonType> {
public CustomDialog(Task<?> task) {
DialogPane pane = this.getDialogPane(); {
pane.getButtonTypes().addAll(ButtonType.CANCEL);
//construct custom header
GridPane headerRoot = new GridPane(); {
Label headerText = new Label();
//headerText is the label containing the header text
headerText.textProperty().bind(task.titleProperty());
headerRoot.add(headerText, 0, 0);
}
headerRoot.getStyleClass().addAll("header-panel");
pane.setHeader(headerRoot);
pane.setContentText("Placeholder content");
pane.getScene().getWindow().setOnCloseRequest(event -> {
if (!task.isDone()) {
event.consume();
}
});
}
}
它看起来与默认对话框完全相同,没有上面问题中提到的问题。