拆分模块

This commit is contained in:
2025-09-03 20:56:44 +08:00
parent 08cc2c29a5
commit a2f5e4864b
939 changed files with 14227 additions and 9607 deletions

View 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;
}
}