拆分模块
This commit is contained in:
322
client/src/main/java/com/ecep/contract/util/UITools.java
Normal file
322
client/src/main/java/com/ecep/contract/util/UITools.java
Normal file
@@ -0,0 +1,322 @@
|
||||
package com.ecep.contract.util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.controlsfx.control.textfield.AutoCompletionBinding;
|
||||
import org.controlsfx.control.textfield.TextFields;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.ecep.contract.Desktop;
|
||||
import com.ecep.contract.Message;
|
||||
import com.ecep.contract.converter.EntityStringConverter;
|
||||
import com.ecep.contract.task.Tasker;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Rectangle2D;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Dialog;
|
||||
import javafx.scene.control.DialogPane;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Screen;
|
||||
import javafx.util.StringConverter;
|
||||
|
||||
public class UITools {
|
||||
private static final Logger logger = LoggerFactory.getLogger(UITools.class);
|
||||
|
||||
public static void showExceptionAndWait(String title, Throwable e) {
|
||||
String stackTrace = printStackTrace(e);
|
||||
Label label = new Label("异常堆栈信息如下:");
|
||||
TextArea textArea = new TextArea(stackTrace);
|
||||
textArea.setEditable(false);
|
||||
textArea.setWrapText(true);
|
||||
|
||||
GridPane.setVgrow(textArea, Priority.ALWAYS);
|
||||
GridPane.setHgrow(textArea, Priority.ALWAYS);
|
||||
|
||||
GridPane expContent = new GridPane();
|
||||
expContent.setMaxWidth(Double.MAX_VALUE);
|
||||
expContent.add(label, 0, 0);
|
||||
expContent.add(textArea, 0, 1);
|
||||
|
||||
String message = null;
|
||||
if (e instanceof org.springframework.orm.ObjectOptimisticLockingFailureException) {
|
||||
message = "锁冲突, 数据可能已经被修改, 请重新加载, 再次重试.";
|
||||
} else {
|
||||
message = e.getMessage();
|
||||
}
|
||||
|
||||
showAndWait(Alert.AlertType.ERROR, "程序异常", title, message, expContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示 Alert 窗口
|
||||
*
|
||||
* @param alertType alert 类型
|
||||
* @param title 标题
|
||||
* @param header 头
|
||||
* @param message 消息内容
|
||||
* @param content 扩张节点
|
||||
*/
|
||||
public static CompletableFuture<ButtonType> showAndWait(Alert.AlertType alertType, String title, String header,
|
||||
String message, Node content) {
|
||||
CompletableFuture<ButtonType> future = new CompletableFuture<>();
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new Alert(alertType);
|
||||
if (content != null) {
|
||||
alert.getDialogPane().setExpandableContent(content);
|
||||
alert.getDialogPane().setExpanded(true);
|
||||
}
|
||||
alert.setTitle(title);
|
||||
if (header != null)
|
||||
alert.setHeaderText(header);
|
||||
if (message != null)
|
||||
alert.setContentText(message);
|
||||
|
||||
Rectangle2D visualBounds = Screen.getPrimary().getVisualBounds();
|
||||
alert.getDialogPane().setMaxWidth(visualBounds.getWidth() * 0.9);
|
||||
alert.showAndWait();
|
||||
future.complete(alert.getResult());
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
public static CompletableFuture<ButtonType> showConfirmation(String title, String message) {
|
||||
return showAndWait(Alert.AlertType.CONFIRMATION, "请选择", title, message, null);
|
||||
}
|
||||
|
||||
public static <T> Dialog<T> createDialog() {
|
||||
Dialog<T> dialog = new Dialog<>();
|
||||
VBox box = new VBox();
|
||||
Label headerLabel = new Label();
|
||||
headerLabel.setId("header");
|
||||
|
||||
VBox.setMargin(headerLabel, new Insets(5, 0, 8, 0));
|
||||
|
||||
ListView<T> listView = new ListView<>();
|
||||
listView.setMinHeight(50);
|
||||
listView.setId("list-view");
|
||||
ObservableList<T> listViewDataSet = FXCollections.observableArrayList();
|
||||
listView.setItems(listViewDataSet);
|
||||
VBox.setVgrow(listView, Priority.ALWAYS);
|
||||
|
||||
box.getChildren().setAll(headerLabel, listView);
|
||||
|
||||
dialog.getDialogPane().setContent(box);
|
||||
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
|
||||
dialog.setResizable(true);
|
||||
dialog.setWidth(600);
|
||||
dialog.setHeight(500);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示一个对话框, 并等待用户关闭对话框
|
||||
* <p>
|
||||
* 对话框内嵌一个 ListView,可在 consumer 中向 ListView 添加内容
|
||||
*
|
||||
* @param title 对话框标题
|
||||
* @param header 对话框头
|
||||
* @param consumer 对话框内容生成器
|
||||
*/
|
||||
public static void showDialogAndWait(String title, String header, Consumer<ObservableList<String>> consumer) {
|
||||
Dialog<String> dialog = createDialog();
|
||||
dialog.setTitle(title);
|
||||
|
||||
DialogPane dialogPane = dialog.getDialogPane();
|
||||
Node content = dialogPane.getContent();
|
||||
|
||||
Label headerLabel = (Label) content.lookup("#header");
|
||||
ListView<String> listView = (ListView<String>) content.lookup("#list-view");
|
||||
headerLabel.setText(header);
|
||||
CompletableFuture.runAsync(() -> {
|
||||
consumer.accept(listView.getItems());
|
||||
}).exceptionally(e -> {
|
||||
Platform.runLater(() -> {
|
||||
listView.getItems().add(e.getMessage());
|
||||
});
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
dialog.showAndWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示一个对话框, 并等待用户关闭对话框
|
||||
*
|
||||
* @param title 对话框标题
|
||||
* @param task 任务
|
||||
* @param init 初始化
|
||||
*/
|
||||
public static void showTaskDialogAndWait(String title, javafx.concurrent.Task<?> task,
|
||||
Consumer<Consumer<Message>> init) {
|
||||
Dialog<Message> dialog = createDialog();
|
||||
dialog.getDialogPane().getScene().getStylesheets().add("/ui/dialog.css");
|
||||
dialog.setTitle(title);
|
||||
|
||||
DialogPane dialogPane = dialog.getDialogPane();
|
||||
VBox box = (VBox) dialogPane.getContent();
|
||||
Label headerLabel = (Label) box.lookup("#header");
|
||||
ListView<Message> listView = (ListView<Message>) box.lookup("#list-view");
|
||||
listView.setCellFactory(param -> new Tasker.MessageListCell());
|
||||
|
||||
headerLabel.textProperty().bind(task.titleProperty());
|
||||
|
||||
java.util.function.Predicate<Message> consumer = message -> {
|
||||
if (Platform.isFxApplicationThread()) {
|
||||
listView.getItems().add(message);
|
||||
} else {
|
||||
Platform.runLater(() -> listView.getItems().add(message));
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (task instanceof Tasker<?> tasker) {
|
||||
tasker.setMessageHandler(consumer);
|
||||
} else {
|
||||
task.messageProperty().addListener((observable, oldValue, newValue) -> {
|
||||
consumer.test(Message.info(newValue));
|
||||
});
|
||||
}
|
||||
|
||||
// 加一个进度条
|
||||
ProgressBar progressBar = new ProgressBar(0);
|
||||
progressBar.setPrefHeight(12);
|
||||
progressBar.setPrefWidth(200);
|
||||
progressBar.prefWidthProperty().bind(box.widthProperty().subtract(10));
|
||||
progressBar.setMinHeight(12);
|
||||
progressBar.setVisible(true);
|
||||
VBox.setMargin(progressBar, new Insets(6, 0, 6, 0));
|
||||
|
||||
Platform.runLater(() -> {
|
||||
box.getChildren().add(progressBar);
|
||||
});
|
||||
|
||||
// progressBar.disabledProperty().bind(task.runningProperty());
|
||||
progressBar.visibleProperty().bind(task.runningProperty());
|
||||
progressBar.progressProperty().bind(task.progressProperty());
|
||||
|
||||
if (task instanceof Tasker<?> tasker) {
|
||||
// 提交任务
|
||||
Desktop.instance.getExecutorService().submit(tasker);
|
||||
}
|
||||
if (init != null) {
|
||||
init.accept(msg -> consumer.test(msg));
|
||||
}
|
||||
dialog.showAndWait();
|
||||
if (task.isRunning()) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private static String printStackTrace(Throwable e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public static void showAlertAndWait(String message) {
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
||||
alert.setContentText(message);
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
public static <T> AutoCompletionBinding<T> autoCompletion(
|
||||
TextField textField,
|
||||
SimpleObjectProperty<T> property,
|
||||
EntityStringConverter<T> converter) {
|
||||
return autoCompletion(textField, property, converter::suggest, converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 TextField 增加一个 自动补全功能
|
||||
*
|
||||
* @param textField 要补全的文本框
|
||||
* @param property 绑定的属性
|
||||
* @param func 获取补全数据的方法
|
||||
* @param converter 对象转换器
|
||||
* @param <T> 对象类型
|
||||
* @return AutoCompletionBinding
|
||||
*/
|
||||
public static <T> AutoCompletionBinding<T> autoCompletion(
|
||||
TextField textField,
|
||||
SimpleObjectProperty<T> property,
|
||||
Function<AutoCompletionBinding.ISuggestionRequest, List<T>> func,
|
||||
StringConverter<T> converter) {
|
||||
// 先赋值
|
||||
textField.textProperty().set(converter.toString(property.get()));
|
||||
// 监听 property 变化
|
||||
property.addListener((observable, oldValue, newValue) -> {
|
||||
textField.textProperty().set(converter.toString(newValue));
|
||||
});
|
||||
|
||||
// 关联一个 自动完成
|
||||
AutoCompletionBinding<T> completionBinding = TextFields.bindAutoCompletion(textField, p -> {
|
||||
if (p.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return func.apply(p);
|
||||
} catch (Exception e) {
|
||||
textField.setText(e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}, converter);
|
||||
|
||||
// 设置自动补全选中值到 property
|
||||
completionBinding.setOnAutoCompleted(event -> {
|
||||
property.set(event.getCompletion());
|
||||
});
|
||||
|
||||
// fixed 当输入框丢失焦点时,输入框内容为空时,设置property 为null
|
||||
textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
if (!StringUtils.hasText(textField.getText())) {
|
||||
property.set(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return completionBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认对话框
|
||||
*
|
||||
* @param title
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
public static boolean showConfirmDialog(String title, String text) {
|
||||
// TODO
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setTitle(title);
|
||||
alert.setHeaderText(text);
|
||||
if (alert.showAndWait().get() == ButtonType.OK) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user