diff --git a/.editorconfig b/.editorconfig
index af32f6166f35dbd20f67251378e3b9cd2e383b1a..ba60bec869a65c74991807aa96d724ec3aafdf45 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,9 +1,30 @@
-[*]
+root = true
+
+[*.{txt, java, xml, md, properties}]
charset = utf-8
-end_of_line = lf
-insert_final_newline = false
indent_style = space
+end_of_line = lf
+
+[*.{txt, java, xml}]
indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false
+
+[*.java]
+ij_java_blank_lines_around_field = 1
+ij_java_blank_lines_after_class_header = 1
+ij_java_doc_add_blank_line_after_return = true
+ij_java_doc_add_blank_line_after_param_comments = true
+ij_java_doc_add_blank_line_after_description = true
+ij_java_doc_keep_empty_parameter_tag = false
+ij_java_doc_keep_empty_return_tag = false
+ij_java_doc_keep_empty_throws_tag = false
+
+[*.properties]
+ij_properties_keep_blank_lines = true
+ij_properties_spaces_around_key_value_delimiter = true
-[*.{html, xml, yaml}]
-indent_size = 2
diff --git a/.gitignore b/.gitignore
index 29ed5a82c2fba4c716ea5d61a9ff05fbaa6bc9ae..46fd667c245a3eebfd44d031b0b7ee78b1bc4df4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,10 @@
# Default ignored files
#/.gitignore
-/xcore.iml
-/data
-/log/
-/target/
-/.idea
\ No newline at end of file
+data
+log/
+target/
+.idea/
+.mvnd/
+*.iml
+
+C:
\ No newline at end of file
diff --git a/README.md b/README.md
index 620c533bb4beb9906f055932b4df02a6c1530b07..be324376089795b6943bb5e7005c98a0377cc36c 100644
--- a/README.md
+++ b/README.md
@@ -15,16 +15,16 @@
```
- xwintop-maven
- https://xwintop.gitee.io/maven/repository
+ jitpack.io
+ https://jitpack.io
- com.xwintop
+ com.gitee.xwintop
xcore
- 0.0.3-SNAPSHOT
+ 0.0.7
provided
@@ -43,4 +43,10 @@ git 托管 maven可参考教程(若无法下载请拉取项目自行编译)。[
- 0.0.4-SNAPSHOT 2020-03-16
1. 优化界面布局
- 0.0.5 2020-03-16
- 1. 添加进度条对话框
\ No newline at end of file
+ 1. 添加进度条对话框
+- 0.0.6 2020-07-04
+ 1. 添加历史输入框功能封装
+ 2. 优化部分功能代码
+- 0.0.7 2022-03-29
+ 1. 升级jdk版本为17
+ 2. 优化部分功能代码
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 5ebf01104d390705136982396ba9e3df89c225b8..a739f158c7580cf1e60aa784c743d76f0fa88558 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,205 +1,243 @@
- 4.0.0
-
- com.xwintop
- xcore
- 0.0.6
- jar
-
- xcore
- xcore核心jar包
- https://gitee.com/xwintop/xcore
-
-
- 1.8
- 1.8
- UTF-8
-
-
-
-
- aliyunmaven
- http://maven.aliyun.com/nexus/content/groups/public/
-
-
- spring-snapshots
- http://repo.spring.io/snapshot
-
- true
-
-
-
- spring-milestones
- http://repo.spring.io/milestone
-
-
- apache.snapshots
- Apache Development Snapshot Repository
- https://repository.apache.org/content/repositories/snapshots/
-
- false
-
-
- true
-
-
-
-
-
-
- junit
- junit
- 4.12
- test
-
-
-
- ch.qos.logback
- logback-classic
- 1.2.3
-
-
-
-
- org.dom4j
- dom4j
- 2.1.1
-
-
- jaxen
- jaxen
- 1.2.0
-
-
-
-
- org.quartz-scheduler
- quartz
- 2.3.1
-
-
-
-
- org.controlsfx
- controlsfx
- 8.40.16
-
-
-
- com.jfoenix
- jfoenix
- 8.0.9
-
-
-
-
- commons-codec
- commons-codec
- 1.12
-
-
- commons-configuration
- commons-configuration
- 1.10
-
-
- commons-io
- commons-io
- 2.6
-
-
- org.apache.commons
- commons-lang3
- 3.9
-
-
- org.apache.commons
- commons-collections4
- 4.4
-
-
- org.apache.commons
- commons-text
- 1.8
-
-
- commons-beanutils
- commons-beanutils
- 1.9.3
-
-
- org.apache.commons
- commons-imaging
- 1.0-alpha1
-
-
-
-
- com.squareup.okhttp3
- okhttp
- 4.5.0
-
-
-
-
- org.projectlombok
- lombok
- 1.18.6
- provided
-
-
-
-
- cn.hutool
- hutool-all
- 5.3.1
-
-
-
-
- com.alibaba
- fastjson
- 1.2.68
-
-
-
-
- org.yaml
- snakeyaml
- 1.26
-
-
-
-
-
-
- xwintop-maven
- file:C:/gitFiles/maven/repository/
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-resources-plugin
- 3.0.2
-
- UTF-8
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 2.20
-
- true
- once
- -Dfile.encoding=UTF-8
-
-
-
-
+ 4.0.0
+
+ com.gitee.xwintop
+ xcore
+ 0.0.7
+ jar
+
+ xcore
+ xcore核心jar包
+ https://gitee.com/xwintop/xcore
+
+
+ 17
+ 17
+ UTF-8
+ true
+ 17.0.2
+
+
+
+
+ aliyunmaven
+ https://maven.aliyun.com/repository/public
+
+
+
+
+
+
+
+
+
+ org.openjfx
+ javafx-controls
+ ${javafx.version}
+
+
+ org.openjfx
+ javafx-base
+ ${javafx.version}
+
+
+ org.openjfx
+ javafx-graphics
+ ${javafx.version}
+
+
+ org.openjfx
+ javafx-fxml
+ ${javafx.version}
+
+
+ org.openjfx
+ javafx-swing
+ ${javafx.version}
+
+
+ org.openjfx
+ javafx-media
+ ${javafx.version}
+
+
+ org.openjfx
+ javafx-web
+ ${javafx.version}
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.11
+
+
+
+
+ org.dom4j
+ dom4j
+ 2.1.3
+
+
+ jaxen
+ jaxen
+ 1.2.0
+
+
+
+
+ org.quartz-scheduler
+ quartz
+ 2.3.2
+
+
+
+
+ org.controlsfx
+ controlsfx
+ 11.1.1
+
+
+
+ com.jfoenix
+ jfoenix
+ 9.0.10
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ commons-codec
+ commons-codec
+ 1.15
+
+
+ commons-configuration
+ commons-configuration
+ 1.10
+
+
+ commons-io
+ commons-io
+ 2.11.0
+
+
+ org.apache.commons
+ commons-lang3
+ 3.12.0
+
+
+ org.apache.commons
+ commons-collections4
+ 4.4
+
+
+ org.apache.commons
+ commons-text
+ 1.9
+
+
+ commons-beanutils
+ commons-beanutils
+ 1.9.4
+
+
+ org.apache.commons
+ commons-imaging
+ 1.0-alpha2
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.9.3
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.22
+ provided
+
+
+
+
+ cn.hutool
+ hutool-all
+ 5.7.22
+
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.80
+
+
+
+
+ org.yaml
+ snakeyaml
+ 1.30
+
+
+
+
+
+
+ xwintop-maven
+ file:C:/gitFiles/maven/repository/
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.2.0
+
+ UTF-8
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.2
+
+ true
+ once
+ -Dfile.encoding=UTF-8
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.10.0
+
+
+
diff --git a/src/main/java/com/xwintop/xcore/info/package-info.java b/src/main/java/com/xwintop/xcore/info/package-info.java
deleted file mode 100644
index b501c9b37dc97a1f207435b86a2a6a702022c4bc..0000000000000000000000000000000000000000
--- a/src/main/java/com/xwintop/xcore/info/package-info.java
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- *
- */
-/**
- * @author Administrator
- *
- */
-package com.xwintop.xcore.info;
\ No newline at end of file
diff --git a/src/main/java/com/xwintop/xcore/javafx/cells/ListCellFactory.java b/src/main/java/com/xwintop/xcore/javafx/cells/ListCellFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7cc5ec944659f7afedfd7ce9fb1254d8ca59a44
--- /dev/null
+++ b/src/main/java/com/xwintop/xcore/javafx/cells/ListCellFactory.java
@@ -0,0 +1,135 @@
+package com.xwintop.xcore.javafx.cells;
+
+import javafx.beans.value.ObservableValue;
+import javafx.scene.Node;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.util.Callback;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * 封装对列表节点的配置
+ *
+ * @author yiding.he
+ */
+public class ListCellFactory implements Callback, ListCell> {
+
+ private Function textFunction;
+
+ private Function> textProperty;
+
+ private Function graphicFunction;
+
+ private Function> graphicProperty;
+
+ private Consumer> cellInitializer;
+
+ /**
+ * 对 ListCell 的额外配置
+ */
+ public ListCellFactory setCellInitializer(Consumer> cellInitializer) {
+ this.cellInitializer = cellInitializer;
+ return this;
+ }
+
+ /**
+ * 设置列表项文本
+ */
+ public ListCellFactory withTextFunction(Function toStringFunction) {
+ if (this.textProperty != null) {
+ throw new IllegalStateException("You have already assigned textProperty.");
+ }
+ this.textFunction = toStringFunction;
+ return this;
+ }
+
+ /**
+ * 绑定列表项文本为一个自动更新的属性
+ */
+ public ListCellFactory withTextProperty(Function> toStringProperty) {
+ if (this.textFunction != null) {
+ throw new IllegalStateException("You have already assigned textFunction.");
+ }
+ this.textProperty = toStringProperty;
+ return this;
+ }
+
+ /**
+ * 设置列表项图标
+ */
+ public ListCellFactory withGraphicFunction(Function graphicFunction) {
+ if (this.graphicProperty != null) {
+ throw new IllegalStateException("You have already assigned graphicProperty.");
+ }
+ this.graphicFunction = graphicFunction;
+ return this;
+ }
+
+ /**
+ * 绑定列表项图标为一个自动更新的属性
+ */
+ public ListCellFactory withGraphicProperty(Function> graphicProperty) {
+ if (this.graphicFunction != null) {
+ throw new IllegalStateException("You have already assigned graphicFunction.");
+ }
+ this.graphicProperty = graphicProperty;
+ return this;
+ }
+
+ @Override
+ public ListCell call(ListView param) {
+
+ ListCell listCell = new ListCell() {
+ @Override
+ protected void updateItem(T item, boolean empty) {
+ super.updateItem(item, empty);
+
+ if (textProperty().isBound()) {
+ textProperty().unbind();
+ }
+ if (graphicProperty().isBound()) {
+ graphicProperty().unbind();
+ }
+
+ if (empty) {
+ setText(null);
+ setGraphic(null);
+ } else {
+ setCellText(this, item);
+ setCellGraphic(this, item);
+ }
+ }
+ };
+
+ if (cellInitializer != null) {
+ cellInitializer.accept(listCell);
+ }
+
+ return listCell;
+ }
+
+ private void setCellGraphic(ListCell cell, T item) {
+ if (graphicFunction != null) {
+ cell.setGraphic(graphicFunction.apply(item));
+ }
+ if (graphicProperty != null) {
+ cell.graphicProperty().unbind();
+ cell.graphicProperty().bind(graphicProperty.apply(item));
+ }
+ }
+
+ private void setCellText(ListCell cell, T item) {
+ if (textFunction != null) {
+ cell.setText(textFunction.apply(item));
+ }
+ if (textProperty != null) {
+ cell.textProperty().unbind();
+ cell.textProperty().bind(textProperty.apply(item));
+ }
+ if (textFunction == null && textProperty == null) {
+ cell.setText(String.valueOf(item));
+ }
+ }
+}
diff --git a/src/main/java/com/xwintop/xcore/javafx/cells/TreeCellFactory.java b/src/main/java/com/xwintop/xcore/javafx/cells/TreeCellFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..875527291393a215e015dc96cc2e9bc7c711e1f4
--- /dev/null
+++ b/src/main/java/com/xwintop/xcore/javafx/cells/TreeCellFactory.java
@@ -0,0 +1,91 @@
+package com.xwintop.xcore.javafx.cells;
+
+import javafx.scene.control.TreeCell;
+import javafx.scene.control.TreeItem;
+import javafx.scene.control.TreeView;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.util.Callback;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * 封装对 TreeView 的配置过程
+ *
+ * @author yiding.he
+ */
+public class TreeCellFactory implements Callback, TreeCell> {
+
+ private Consumer onDoubleClick;
+
+ private Function toString;
+
+ private Function, Image> iconSupplier;
+
+ /**
+ * 设置当双击树节点时要做的事
+ */
+ public TreeCellFactory setOnDoubleClick(Consumer onDoubleClick) {
+ this.onDoubleClick = onDoubleClick;
+ return this;
+ }
+
+ /**
+ * 设置树节点文本
+ */
+ public TreeCellFactory setToString(Function toString) {
+ this.toString = toString;
+ return this;
+ }
+
+ /**
+ * 设置树节点图标
+ */
+ public TreeCellFactory setIconSupplier(Function, Image> iconSupplier) {
+ this.iconSupplier = iconSupplier;
+ return this;
+ }
+
+ @Override
+ public TreeCell call(TreeView param) {
+ TreeCell treeCell = new TreeCell() {
+ @Override
+ protected void updateItem(T item, boolean empty) {
+ super.updateItem(item, empty);
+
+ if (empty) {
+ setText(null);
+ setGraphic(null);
+ } else {
+ setCellText(item);
+ setCellIcon(this.getTreeItem());
+ }
+ }
+
+ private void setCellIcon(TreeItem treeItem) {
+ if (iconSupplier != null) {
+ Image image = iconSupplier.apply(treeItem);
+ ImageView imageView = new ImageView(image);
+ imageView.setFitWidth(16);
+ imageView.setFitHeight(16);
+ setGraphic(imageView);
+ }
+ }
+
+ private void setCellText(T item) {
+ setText(toString != null ? toString.apply(item) : String.valueOf(item));
+ }
+ };
+
+ if (onDoubleClick != null) {
+ treeCell.setOnMouseClicked(event -> {
+ if (!treeCell.isEmpty() && event.getClickCount() == 2) {
+ onDoubleClick.accept(treeCell.getItem());
+ }
+ });
+ }
+
+ return treeCell;
+ }
+}
diff --git a/src/main/java/com/xwintop/xcore/javafx/decorator/ComboBoxDecorator.java b/src/main/java/com/xwintop/xcore/javafx/decorator/ComboBoxDecorator.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9d72a2cb2e55c8b3cde3df52b54f520e8a90303
--- /dev/null
+++ b/src/main/java/com/xwintop/xcore/javafx/decorator/ComboBoxDecorator.java
@@ -0,0 +1,103 @@
+package com.xwintop.xcore.javafx.decorator;
+
+import com.xwintop.xcore.javafx.cells.ListCellFactory;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.control.cell.ComboBoxListCell;
+import javafx.util.Callback;
+import javafx.util.StringConverter;
+
+import java.util.Collection;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * 封装对 ComboBox 的配置
+ */
+@SuppressWarnings("unchecked")
+public class ComboBoxDecorator {
+
+ public static ComboBoxDecorator of(ComboBox comboBox) {
+ return new ComboBoxDecorator<>(comboBox);
+ }
+
+ private ComboBox comboBox;
+
+ private ComboBoxDecorator(ComboBox comboBox) {
+ this.comboBox = comboBox;
+ }
+
+ /**
+ * 设置下拉选项和当前选项的文本
+ */
+ public ComboBoxDecorator setToStringFunction(Function toString) {
+ setCellFactory(new ListCellFactory().withTextFunction(toString));
+ return this;
+ }
+
+ /**
+ * 设置下拉选项的 CellFactory
+ */
+ public ComboBoxDecorator setCellFactory(Callback, ListCell> cellFactory) {
+ this.comboBox.setCellFactory(cellFactory);
+ this.comboBox.setButtonCell(cellFactory.call(null));
+ return this;
+ }
+
+ /**
+ * 设置当前选项的文本
+ */
+ public ComboBoxDecorator setButtonCellToStringFunction(Function toStringFunction) {
+ this.comboBox.setButtonCell(new ComboBoxListCell<>(new StringConverter() {
+ @Override
+ public String toString(T object) {
+ return toStringFunction.apply(object);
+ }
+
+ @Override
+ public T fromString(String string) {
+ return null;
+ }
+ }));
+ return this;
+ }
+
+ /**
+ * 设置选项列表
+ */
+ public ComboBoxDecorator setItems(Collection tCollection) {
+ this.comboBox.getItems().setAll(tCollection);
+ return this;
+ }
+
+ /**
+ * 设置选项列表
+ */
+ @SafeVarargs
+ public final ComboBoxDecorator setItems(T... tCollection) {
+ this.comboBox.getItems().setAll(tCollection);
+ return this;
+ }
+
+ /**
+ * 根据指定规则设置当前选项
+ */
+ public ComboBoxDecorator setInitialValue(Predicate valueMatcher) {
+ this.comboBox.getSelectionModel().select(
+ this.comboBox.getItems().stream().filter(valueMatcher).findFirst().orElse(null)
+ );
+ return this;
+ }
+
+ /**
+ * 设置当选项变化时的处理
+ */
+ public ComboBoxDecorator setOnChange(Consumer newValueConsumer) {
+ this.comboBox.getSelectionModel().selectedItemProperty().addListener(
+ (_ob, _old, _new) -> newValueConsumer.accept(_new)
+ );
+ return this;
+ }
+}
diff --git a/src/main/java/com/xwintop/xcore/javafx/dialog/FxAlerts.java b/src/main/java/com/xwintop/xcore/javafx/dialog/FxAlerts.java
index 96ce31ae345b67904acce5c2f88e4deefb18f893..c8eb69f5d90434a3ecb827d2eeabb271a659db13 100644
--- a/src/main/java/com/xwintop/xcore/javafx/dialog/FxAlerts.java
+++ b/src/main/java/com/xwintop/xcore/javafx/dialog/FxAlerts.java
@@ -1,21 +1,31 @@
package com.xwintop.xcore.javafx.dialog;
import com.xwintop.xcore.javafx.FxApp;
-import java.util.Optional;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
+import javafx.stage.Window;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
+import java.util.Optional;
+
/**
* 系统对话框封装
*/
public class FxAlerts {
+ public static void info(String title, String message) {
+ alert(Alert.AlertType.INFORMATION, title, message);
+ }
+
+ public static void warn(String title, String message) {
+ alert(Alert.AlertType.WARNING, title, message);
+ }
+
public static void error(String message) {
alert(Alert.AlertType.ERROR, "错误", message);
}
@@ -24,21 +34,27 @@ public class FxAlerts {
alert(Alert.AlertType.ERROR, title, message);
}
+ public static void error(Window owner, String title, String message) {
+ alert(owner, Alert.AlertType.ERROR, title, message);
+ }
+
public static void error(String title, Throwable throwable) {
boolean noMessage = StringUtils.isBlank(throwable.getMessage());
String message = noMessage ? throwable.toString() : throwable.getMessage();
error(title, message, ExceptionUtils.getStackTrace(throwable));
}
- public static void info(String title, String message) {
- alert(Alert.AlertType.INFORMATION, title, message);
+ public static void error(Window owner, String title, Throwable throwable) {
+ boolean noMessage = StringUtils.isBlank(throwable.getMessage());
+ String message = noMessage ? throwable.toString() : throwable.getMessage();
+ error(owner, title, message, ExceptionUtils.getStackTrace(throwable));
}
- public static void warn(String title, String message) {
- alert(Alert.AlertType.WARNING, title, message);
+ public static void alert(Alert.AlertType alertType, String title, String message) {
+ alert(null, alertType, title, message);
}
- public static void alert(Alert.AlertType alertType, String title, String message) {
+ public static void alert(Window owner, Alert.AlertType alertType, String title, String message) {
FxApp.runLater(() -> {
try {
Alert alert = new Alert(alertType, message, ButtonType.OK);
@@ -47,7 +63,12 @@ public class FxAlerts {
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
FxApp.setupIcon(stage);
- FxApp.setupModality(alert);
+
+ if (owner != null) {
+ stage.initOwner(owner);
+ } else {
+ FxApp.setupModality(alert);
+ }
alert.showAndWait();
} catch (Exception e) {
@@ -58,10 +79,15 @@ public class FxAlerts {
// 打开一个展示了详细错误信息的错误对话框
public static void error(String title, String message, String details) {
- FxApp.runLater(() -> error0(title, message, details));
+ FxApp.runLater(() -> error0(null, title, message, details));
+ }
+
+ // 打开一个展示了详细错误信息的错误对话框
+ public static void error(Window owner, String title, String message, String details) {
+ FxApp.runLater(() -> error0(owner, title, message, details));
}
- private static void error0(String title, String message, String details) {
+ private static void error0(Window owner, String title, String message, String details) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle(title);
alert.setHeaderText(null);
@@ -84,7 +110,12 @@ public class FxAlerts {
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
FxApp.setupIcon(stage);
- FxApp.setupModality(alert);
+
+ if (owner != null) {
+ stage.initOwner(owner);
+ } else {
+ FxApp.setupModality(alert);
+ }
alert.showAndWait();
}
diff --git a/src/main/java/com/xwintop/xcore/javafx/dialog/FxDialog.java b/src/main/java/com/xwintop/xcore/javafx/dialog/FxDialog.java
index f0e2e1544e94bd727ff8933ab5e7cb731b7539e1..b6882189565ccaf5849dd3b6b9783356923dcd96 100644
--- a/src/main/java/com/xwintop/xcore/javafx/dialog/FxDialog.java
+++ b/src/main/java/com/xwintop/xcore/javafx/dialog/FxDialog.java
@@ -3,13 +3,6 @@ package com.xwintop.xcore.javafx.dialog;
import com.xwintop.xcore.XCoreException;
import com.xwintop.xcore.javafx.FxApp;
import com.xwintop.xcore.util.javafx.FxmlUtil;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ResourceBundle;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXMLLoader;
@@ -29,6 +22,14 @@ import javafx.stage.Window;
import javafx.stage.WindowEvent;
import org.apache.commons.lang3.ArrayUtils;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
/**
* 自定义对话框
*
@@ -48,6 +49,8 @@ public class FxDialog {
private Window owner;
+ private ClassLoader bodyFxmlClassLoader;
+
private String bodyFxmlPath;
private Parent body;
@@ -62,11 +65,22 @@ public class FxDialog {
private ResourceBundle resourceBundle;
+ public FxDialog setBodyFxmlClassLoader(ClassLoader bodyFxmlClassLoader) {
+ this.bodyFxmlClassLoader = bodyFxmlClassLoader;
+ return this;
+ }
+
public FxDialog setResizable(boolean resizable) {
this.resizable = resizable;
return this;
}
+ public FxDialog setPrefSize(double prefWidth, double prefHeight) {
+ this.prefWidth = prefWidth;
+ this.prefHeight = prefHeight;
+ return this;
+ }
+
public FxDialog setPrefHeight(double prefHeight) {
this.prefHeight = prefHeight;
return this;
@@ -92,6 +106,15 @@ public class FxDialog {
return this;
}
+ public FxDialog setBodyFxml(ClassLoader classLoader, String bodyFxmlPath) {
+ this.bodyFxmlClassLoader = classLoader;
+ this.bodyFxmlPath = bodyFxmlPath;
+ return this;
+ }
+
+ /**
+ * @deprecated Use {@link #setBodyFxml(ClassLoader, String)} )} instead
+ */
public FxDialog setBodyFxml(String bodyFxmlPath) {
this.bodyFxmlPath = bodyFxmlPath;
return this;
@@ -130,9 +153,12 @@ public class FxDialog {
public T show() {
if (this.bodyFxmlPath != null) {
+ ClassLoader classLoader =
+ this.bodyFxmlClassLoader == null ? FxDialog.class.getClassLoader() : this.bodyFxmlClassLoader;
+
FXMLLoader fxmlLoader = resourceBundle == null?
- FxmlUtil.loadFxmlFromResource(this.bodyFxmlPath):
- FxmlUtil.loadFxmlFromResource(this.bodyFxmlPath, resourceBundle);
+ FxmlUtil.loadFxmlFromResource(classLoader, this.bodyFxmlPath):
+ FxmlUtil.loadFxmlFromResource(classLoader, this.bodyFxmlPath, resourceBundle);
Stage stage = createStage(fxmlLoader.getRoot());
stage.show();
@@ -151,9 +177,12 @@ public class FxDialog {
public T showAndWait() {
if (this.bodyFxmlPath != null) {
+ ClassLoader classLoader =
+ this.bodyFxmlClassLoader == null ? FxDialog.class.getClassLoader() : this.bodyFxmlClassLoader;
+
FXMLLoader fxmlLoader = resourceBundle == null?
- FxmlUtil.loadFxmlFromResource(this.bodyFxmlPath):
- FxmlUtil.loadFxmlFromResource(this.bodyFxmlPath, resourceBundle);
+ FxmlUtil.loadFxmlFromResource(classLoader, this.bodyFxmlPath):
+ FxmlUtil.loadFxmlFromResource(classLoader, this.bodyFxmlPath, resourceBundle);
Stage stage = createStage(fxmlLoader.getRoot());
stage.showAndWait();
diff --git a/src/main/java/com/xwintop/xcore/log/package-info.java b/src/main/java/com/xwintop/xcore/log/package-info.java
deleted file mode 100644
index 47acf58ff850127a5813bd49d72061cb5fa8d168..0000000000000000000000000000000000000000
--- a/src/main/java/com/xwintop/xcore/log/package-info.java
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- *
- */
-/**
- * @author Administrator
- *
- */
-package com.xwintop.xcore.log;
\ No newline at end of file
diff --git a/src/main/java/com/xwintop/xcore/plugin/PluginEvent.java b/src/main/java/com/xwintop/xcore/plugin/PluginEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..80e9463125a7f675f8d47d05c6df43ae762f7984
--- /dev/null
+++ b/src/main/java/com/xwintop/xcore/plugin/PluginEvent.java
@@ -0,0 +1,29 @@
+package com.xwintop.xcore.plugin;
+
+import javafx.event.Event;
+import javafx.event.EventTarget;
+import javafx.event.EventType;
+
+/**
+ * 插件生命周期相关事件,可在插件 root 节点中接收事件
+ */
+public class PluginEvent extends Event {
+
+ /**
+ * 插件在框架中完成初始化,即完成 FXMLLoader.load()
+ */
+ public static final EventType PLUGIN_INITIALIZED = new EventType<>(Event.ANY, "PLUGIN_INITIALIZED");
+
+ /**
+ * 插件即将被卸载
+ */
+ public static final EventType PLUGIN_UNLOADING = new EventType<>(Event.ANY, "PLUGIN_UNLOADING");
+
+ public PluginEvent(Object source, EventTarget target, EventType extends Event> eventType) {
+ super(source, target, eventType);
+ }
+
+ public PluginEvent(Object source, EventType extends Event> eventType) {
+ super(source, null, eventType);
+ }
+}
diff --git a/src/main/java/com/xwintop/xcore/util/KeyValue.java b/src/main/java/com/xwintop/xcore/util/KeyValue.java
index 562c0b4b3b2df15a46ef734d6443c4e2229d2aae..2215d2af32ccf073ce8a66dd6a2caf1d01ae53b9 100644
--- a/src/main/java/com/xwintop/xcore/util/KeyValue.java
+++ b/src/main/java/com/xwintop/xcore/util/KeyValue.java
@@ -2,6 +2,9 @@ package com.xwintop.xcore.util;
import java.util.Objects;
+/**
+ * 键值对,默认是可修改的,可以通过 {@link #unmodifiable()} 方法获取不可修改的键值对。
+ */
public class KeyValue {
private K key;
@@ -28,6 +31,31 @@ public class KeyValue {
return value;
}
+ public void setKey(K key) {
+ this.key = key;
+ }
+
+ public void setValue(V value) {
+ this.value = value;
+ }
+
+ /**
+ * 创建一个只读实例
+ */
+ public KeyValue unmodifiable() {
+ return new KeyValue<>(this) {
+ @Override
+ public void setKey(K key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setValue(V value) {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
@Override
public String toString() {
return String.valueOf(key);
diff --git a/src/main/java/com/xwintop/xcore/util/SystemInfoUtil.java b/src/main/java/com/xwintop/xcore/util/SystemInfoUtil.java
index c51d6d3218a1e4634f597147cc5951ff55ae2c03..67278fd375cbe9a5616ef4cd026a866ceffd0a66 100644
--- a/src/main/java/com/xwintop/xcore/util/SystemInfoUtil.java
+++ b/src/main/java/com/xwintop/xcore/util/SystemInfoUtil.java
@@ -22,7 +22,7 @@ public class SystemInfoUtil {
} else {
fileName = "C://WINDOWS//system32//drivers//etc//hosts";
}
- log.info("获取hosts文件路径:"+fileName);
+// log.info("获取hosts文件路径:"+fileName);
return fileName;
}
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/ActionJob.java b/src/main/java/com/xwintop/xcore/util/javafx/ActionJob.java
new file mode 100644
index 0000000000000000000000000000000000000000..8206892688fefb1a3565dc4104109b3f4d281de4
--- /dev/null
+++ b/src/main/java/com/xwintop/xcore/util/javafx/ActionJob.java
@@ -0,0 +1,13 @@
+package com.xwintop.xcore.util.javafx;
+
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+public class ActionJob implements Job {
+ @Override
+ public void execute(JobExecutionContext context) throws JobExecutionException {
+ Runnable runnable = (Runnable) context.getMergedJobDataMap().get("runnable");
+ runnable.run();
+ }
+}
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/ActionScheduleUtil.java b/src/main/java/com/xwintop/xcore/util/javafx/ActionScheduleUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7d25e1f3ba148a9cb9eed7cb99d777ec47bc4df
--- /dev/null
+++ b/src/main/java/com/xwintop/xcore/util/javafx/ActionScheduleUtil.java
@@ -0,0 +1,147 @@
+package com.xwintop.xcore.util.javafx;
+
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.geometry.Pos;
+import javafx.scene.control.*;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.StackPane;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.quartz.*;
+import org.quartz.impl.StdSchedulerFactory;
+import org.slf4j.Logger;
+
+/**
+ * @ClassName: ScheduleManager
+ * @Description: 自动任务管理类
+ * @author: xufeng
+ * @date: 2018/1/25 16:35
+ */
+
+@Getter
+@Setter
+//@Slf4j
+public class ActionScheduleUtil {
+ private static Logger log = org.slf4j.LoggerFactory.getLogger(ActionScheduleUtil.class);
+ private static final String[] quartzChoiceBoxStrings = new String[]{"简单表达式", "Cron表达式"};
+ private SchedulerFactory sf = new StdSchedulerFactory();
+ private String schedulerKeyGroup = "x";
+ private String schedulerKeyName = "x";
+
+ private TextField cronTextField;
+ private ChoiceBox quartzChoiceBox;
+ private Spinner intervalSpinner;
+ private Spinner repeatCountSpinner;
+
+ private Runnable runnable;
+
+ //添加调度控件
+ public void setScheduleNode(Pane pane) {
+ quartzChoiceBox = new ChoiceBox();
+ quartzChoiceBox.setPrefWidth(100);
+ quartzChoiceBox.getItems().addAll(quartzChoiceBoxStrings);
+ quartzChoiceBox.getSelectionModel().select(0);
+ StackPane stackPane = new StackPane();
+ cronTextField = new TextField("* * * * * ?");
+ cronTextField.setVisible(false);
+ stackPane.getChildren().add(cronTextField);
+ HBox simpleScheduleAnchorPane = new HBox();
+ simpleScheduleAnchorPane.setAlignment(Pos.CENTER_LEFT);
+ simpleScheduleAnchorPane.setSpacing(5);
+ stackPane.getChildren().add(simpleScheduleAnchorPane);
+ intervalSpinner = new Spinner<>();
+ intervalSpinner.setEditable(true);
+ intervalSpinner.setPrefWidth(66);
+ intervalSpinner.setTooltip(new Tooltip("单位为秒"));
+ repeatCountSpinner = new Spinner<>();
+ repeatCountSpinner.setEditable(true);
+ repeatCountSpinner.setPrefWidth(66);
+ repeatCountSpinner.setTooltip(new Tooltip("-1为永久任务"));
+ simpleScheduleAnchorPane.getChildren().add(new Label("间隔"));
+ simpleScheduleAnchorPane.getChildren().add(intervalSpinner);
+ simpleScheduleAnchorPane.getChildren().add(new Label("次数"));
+ simpleScheduleAnchorPane.getChildren().add(repeatCountSpinner);
+ JavaFxViewUtil.setSpinnerValueFactory(intervalSpinner, 1, Integer.MAX_VALUE);
+ JavaFxViewUtil.setSpinnerValueFactory(repeatCountSpinner, -1, Integer.MAX_VALUE);
+ quartzChoiceBox.valueProperty().addListener(new ChangeListener() {
+ @Override
+ public void changed(ObservableValue extends String> observable, String oldValue, String newValue) {
+ if (quartzChoiceBoxStrings[0].equals(newValue)) {
+ cronTextField.setVisible(false);
+ simpleScheduleAnchorPane.setVisible(true);
+ } else if (quartzChoiceBoxStrings[1].equals(newValue)) {
+ cronTextField.setVisible(true);
+ simpleScheduleAnchorPane.setVisible(false);
+ }
+ }
+ });
+ Button runQuartzButton = new Button("定时运行");
+ runQuartzButton.setOnAction(event -> {
+ if ("定时运行".equals(runQuartzButton.getText())) {
+ try {
+ ActionScheduleUtil.this.runQuartzAction();
+ runQuartzButton.setText("停止运行");
+ } catch (Exception e) {
+ log.error("运行错误!", e);
+ TooltipUtil.showToast("运行错误:" + e.getMessage());
+ }
+ } else {
+ try {
+ ActionScheduleUtil.this.stopQuartzAction();
+ runQuartzButton.setText("定时运行");
+ } catch (Exception e) {
+ log.error("停止错误!", e);
+ TooltipUtil.showToast("停止错误:" + e.getMessage());
+ }
+ }
+ });
+ pane.getChildren().add(quartzChoiceBox);
+ pane.getChildren().add(stackPane);
+ pane.getChildren().add(runQuartzButton);
+ }
+
+ //设置调度执行事件
+ public void setJobAction(Runnable runnable) {
+ this.runnable = runnable;
+ }
+
+ public void runQuartzAction() throws Exception {
+// schedulerKeyGroup = jobClass.toString();
+ schedulerKeyName = schedulerKeyGroup + System.currentTimeMillis();
+ JobDetail jobDetail = JobBuilder.newJob(ActionJob.class).withIdentity(schedulerKeyName, schedulerKeyGroup).build();
+ jobDetail.getJobDataMap().put("runnable", runnable);
+ ScheduleBuilder scheduleBuilder = null;
+ if (quartzChoiceBoxStrings[0].equals(quartzChoiceBox.getValue())) {
+ scheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(intervalSpinner.getValue())// 时间间隔
+ .withRepeatCount(repeatCountSpinner.getValue());// 重复次数
+ } else if (quartzChoiceBoxStrings[1].equals(quartzChoiceBox.getValue())) {
+ if (StringUtils.isEmpty(cronTextField.getText())) {
+ throw new Exception("cron表达式不能为空。");
+ }
+ scheduleBuilder = CronScheduleBuilder.cronSchedule(cronTextField.getText());
+ }
+ // 描叙触发Job执行的时间触发规则,Trigger实例化一个触发器
+ Trigger trigger = TriggerBuilder.newTrigger()// 创建一个新的TriggerBuilder来规范一个触发器
+ .withIdentity(schedulerKeyName, schedulerKeyGroup)// 给触发器一个名字和组名
+ .startNow()// 立即执行
+ .withSchedule(scheduleBuilder).build();// 产生触发器
+
+ // 运行容器,使用SchedulerFactory创建Scheduler实例
+ Scheduler scheduler = sf.getScheduler();
+ // 向Scheduler添加一个job和trigger
+ scheduler.scheduleJob(jobDetail, trigger);
+ if (!scheduler.isStarted()) {
+ scheduler.start();
+ }
+ }
+
+ public void stopQuartzAction() throws Exception {
+ Scheduler sched = sf.getScheduler();
+ sched.unscheduleJob(new TriggerKey(schedulerKeyName, schedulerKeyGroup));
+ sched.deleteJob(new JobKey(schedulerKeyName, schedulerKeyGroup));
+ }
+}
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/AlertUtil.java b/src/main/java/com/xwintop/xcore/util/javafx/AlertUtil.java
index 59168335df8518dcf362ead31d7cc6faf451e0be..ab33c40c75633e0687f7215fede341c24b2ecb0d 100644
--- a/src/main/java/com/xwintop/xcore/util/javafx/AlertUtil.java
+++ b/src/main/java/com/xwintop/xcore/util/javafx/AlertUtil.java
@@ -6,13 +6,14 @@ import static com.xwintop.xcore.javafx.helper.LayoutHelper.vbox;
import com.xwintop.xcore.javafx.FxApp;
import com.xwintop.xcore.javafx.dialog.FxDialog;
import com.xwintop.xcore.javafx.helper.LayoutHelper;
+
+import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
-import javafx.scene.control.Button;
-import javafx.scene.control.ButtonType;
-import javafx.scene.control.Label;
-import javafx.scene.control.TextField;
+import javafx.scene.control.*;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Modality;
@@ -164,4 +165,51 @@ public class AlertUtil {
newStage.showAndWait();
return isOk.get();
}
+
+ @Deprecated
+ public static String showInputAlert(String message) {
+ return showInputAlertDefaultValue(message, null);
+ }
+
+ public static String[] showInputAlert(String message, String... names) {
+ return showInputAlertMore(message, names);
+ }
+
+ public static String[] showInputAlertMore(String message, String... names) {
+ return showInputAlertMore(message, names, new String[names.length]);
+ }
+
+ public static String[] showInputAlertMore(String message, String[] names, String[] defaultValue) {
+ GridPane page1Grid = new GridPane();
+ page1Grid.setVgap(10);
+ page1Grid.setHgap(10);
+
+ TextField[] textFields = new TextField[names.length];
+ for (int i = 0; i < names.length; i++) {
+ TextField textField = new TextField();
+ textField.setText(defaultValue[i]);
+ textField.setMinWidth(100);
+ textField.prefColumnCountProperty().bind(textField.textProperty().length());
+ GridPane.setHgrow(textField, Priority.ALWAYS);
+ page1Grid.add(new Label(names[i]), 0, i);
+ page1Grid.add(textField, 1, i);
+ textFields[i] = textField;
+ }
+
+ Alert alert = new Alert(Alert.AlertType.NONE, null, new ButtonType("取消", ButtonBar.ButtonData.NO),
+ new ButtonType("确定", ButtonBar.ButtonData.YES));
+ alert.setTitle(message);
+ alert.setGraphic(page1Grid);
+ alert.setWidth(200);
+ Optional _buttonType = alert.showAndWait();
+ // 根据点击结果返回
+ if (_buttonType.get().getButtonData().equals(ButtonBar.ButtonData.YES)) {
+ String[] stringS = new String[names.length];
+ for (int i = 0; i < textFields.length; i++) {
+ stringS[i] = textFields[i].getText();
+ }
+ return stringS;
+ }
+ return null;
+ }
}
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/FileChooserUtil.java b/src/main/java/com/xwintop/xcore/util/javafx/FileChooserUtil.java
index 8794db991794be5c19e9aff3788a7ac514d9f5c6..c6c36cac9a741ec75bb25b954362baed230c9ea2 100644
--- a/src/main/java/com/xwintop/xcore/util/javafx/FileChooserUtil.java
+++ b/src/main/java/com/xwintop/xcore/util/javafx/FileChooserUtil.java
@@ -10,6 +10,7 @@ import javafx.stage.FileChooser.ExtensionFilter;
import javax.swing.filechooser.FileSystemView;
import java.io.File;
+import java.util.List;
/**
* 文件选择工具
@@ -20,6 +21,22 @@ public class FileChooserUtil {
public static final File HOME_DIRECTORY = FileSystemView.getFileSystemView().getHomeDirectory();
+ //选择多个文件
+ public static List chooseFiles() {
+ return chooseFiles(null);
+ }
+
+ public static List chooseFiles(ExtensionFilter... extensionFilter) {
+ FileChooser fileChooser = new FileChooser();
+ fileChooser.setTitle("请选择文件");
+ fileChooser.setInitialDirectory(HOME_DIRECTORY);
+
+ if (extensionFilter != null) {
+ fileChooser.getExtensionFilters().addAll(extensionFilter);
+ }
+ return fileChooser.showOpenMultipleDialog(null);
+ }
+
public static File chooseFile() {
return chooseFile(null);
}
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/FxmlUtil.java b/src/main/java/com/xwintop/xcore/util/javafx/FxmlUtil.java
index b3d77cd79467c3e0fc01a8f4fe06c98ac4e8b2ee..c04aaeccce4cbf36639e5a8fdc0b770eefa05c14 100644
--- a/src/main/java/com/xwintop/xcore/util/javafx/FxmlUtil.java
+++ b/src/main/java/com/xwintop/xcore/util/javafx/FxmlUtil.java
@@ -1,20 +1,41 @@
package com.xwintop.xcore.util.javafx;
import com.xwintop.xcore.XCoreException;
+import javafx.fxml.FXMLLoader;
+import org.apache.commons.lang3.StringUtils;
+
import java.io.IOException;
import java.util.ResourceBundle;
-import javafx.fxml.FXMLLoader;
+/**
+ * 调用者最好自己提供 ClassLoader 用于加载自身的资源文件,
+ * 否则使用 xcore 的 ClassLoader 加载可能会由于安全原因而失败
+ */
public class FxmlUtil {
+ /**
+ * @deprecated Use {@link #loadFxmlFromResource(ClassLoader, String)} )} instead.
+ */
public static FXMLLoader loadFxmlFromResource(String resourcePath) {
- return loadFxmlFromResource(resourcePath, null);
+ return loadFxmlFromResource(FxmlUtil.class.getClassLoader(), resourcePath, null);
}
+ /**
+ * @deprecated Use {@link #loadFxmlFromResource(ClassLoader, String, ResourceBundle)} instead.
+ */
public static FXMLLoader loadFxmlFromResource(String resourcePath, ResourceBundle resourceBundle) {
+ return loadFxmlFromResource(FxmlUtil.class.getClassLoader(), resourcePath, resourceBundle);
+ }
+
+ public static FXMLLoader loadFxmlFromResource(ClassLoader classLoader, String resourcePath) {
+ return loadFxmlFromResource(classLoader, resourcePath, null);
+ }
+
+ public static FXMLLoader loadFxmlFromResource(
+ ClassLoader classLoader, String resourcePath, ResourceBundle resourceBundle) {
try {
FXMLLoader fxmlLoader = new FXMLLoader();
- fxmlLoader.setLocation(FxmlUtil.class.getResource(resourcePath));
+ fxmlLoader.setLocation(classLoader.getResource(StringUtils.removeStart(resourcePath, "/")));
fxmlLoader.setResources(resourceBundle);
fxmlLoader.load();
return fxmlLoader;
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/ImageUtil.java b/src/main/java/com/xwintop/xcore/util/javafx/ImageUtil.java
index 1a46f9290b237ca4eff801ac9819e877e8609ecd..44340b4caa1e3c926f259ed72389997d3c0a4ce2 100644
--- a/src/main/java/com/xwintop/xcore/util/javafx/ImageUtil.java
+++ b/src/main/java/com/xwintop/xcore/util/javafx/ImageUtil.java
@@ -2,6 +2,7 @@ package com.xwintop.xcore.util.javafx;
import com.xwintop.xcore.util.FileUtil;
import javafx.embed.swing.SwingFXUtils;
+import javafx.scene.image.*;
import javafx.scene.image.Image;
import lombok.Getter;
import lombok.Setter;
@@ -9,6 +10,9 @@ import org.apache.commons.imaging.ImageFormats;
import org.apache.commons.imaging.Imaging;
import javax.imageio.ImageIO;
+import javax.swing.*;
+import javax.swing.filechooser.FileSystemView;
+import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
@@ -26,6 +30,7 @@ public class ImageUtil {
/**
* 获取图片BufferedImage
+ *
* @param path 图片路径
*/
public static BufferedImage getBufferedImage(String path) {
@@ -48,6 +53,7 @@ public class ImageUtil {
/**
* 获取javafx图片
+ *
* @param path 图片路径
*/
public static Image getFXImage(String path) {
@@ -77,19 +83,107 @@ public class ImageUtil {
/**
* 保存图片
+ *
* @param image
* @param file
*/
- public static void writeImage(Image image, File file) throws Exception{
- writeImage(SwingFXUtils.fromFXImage(image, null),file);
+ public static void writeImage(Image image, File file) throws Exception {
+ writeImage(SwingFXUtils.fromFXImage(image, null), file);
}
- public static void writeImage(BufferedImage bufferedImage, File file) throws Exception{
+ public static void writeImage(BufferedImage bufferedImage, File file) throws Exception {
try {
- Imaging.writeImage(bufferedImage,file, ImageFormats.valueOf(FileUtil.getFileSuffixName(file).toUpperCase()),null);
+ Imaging.writeImage(bufferedImage, file, ImageFormats.valueOf(FileUtil.getFileSuffixName(file).toUpperCase()), null);
} catch (Exception e) {
e.printStackTrace();
- ImageIO.write(bufferedImage, FileUtil.getFileSuffixName(file),file);
+ ImageIO.write(bufferedImage, FileUtil.getFileSuffixName(file), file);
}
}
+
+ //获取文件夹图标
+ public static ImageView getDirectoryIconImage() {
+ return getFileIconImage(FileSystemView.getFileSystemView().getHomeDirectory());
+ }
+
+ //获取文件图标
+ public static ImageView getFileIconImage(File file) {
+ Icon icon = FileSystemView.getFileSystemView().getSystemIcon(file);
+ BufferedImage bufferedImage = new BufferedImage(
+ icon.getIconWidth(),
+ icon.getIconHeight(),
+ BufferedImage.TYPE_INT_ARGB
+ );
+ icon.paintIcon(null, bufferedImage.getGraphics(), 0, 0);
+ Image fxImage = SwingFXUtils.toFXImage(bufferedImage, null);
+ return new ImageView(fxImage);
+ }
+
+ /**
+ * 根据传入类型变化图片像素
+ */
+ public static javafx.scene.image.Image pixWithImage(int type, javafx.scene.image.Image image) {
+ PixelReader pixelReader = image.getPixelReader();
+ if (image.getWidth() > 0 && image.getHeight() > 0) {
+ WritableImage wImage;
+ wImage = new WritableImage((int) image.getWidth(), (int) image.getHeight());
+ PixelWriter pixelWriter = wImage.getPixelWriter();
+
+ for (int y = 0; y < image.getHeight(); y++) {
+ for (int x = 0; x < image.getWidth(); x++) {
+ javafx.scene.paint.Color color = pixelReader.getColor(x, y);
+ switch (type) {
+ case 1:
+ // 颜色变轻
+ color = color.brighter();
+ break;
+ case 2:
+ // 颜色变深
+ color = color.darker();
+ break;
+ case 3:
+ // 灰度化
+ color = color.grayscale();
+ break;
+ case 4:
+ // 颜色反转
+ color = color.invert();
+ break;
+ case 5:
+ // 颜色饱和
+ color = color.saturate();
+ break;
+ case 6:
+ // 颜色不饱和
+ color = color.desaturate();
+ break;
+ case 7:
+ // 颜色灰度化后反转(字黑体,背景鲜亮,可用于强字弱景)
+ color = color.grayscale();
+ color = color.invert();
+ break;
+ case 8:
+ // 颜色透明
+ if (color.getOpacity() == 0) {
+ color = new javafx.scene.paint.Color(color.getRed(), color.getGreen(), color.getBlue(), 0);
+ } else {
+ color = new javafx.scene.paint.Color(color.getRed(), color.getGreen(), color.getBlue(), 0.5);
+ }
+ break;
+ default:
+ break;
+ }
+
+ pixelWriter.setColor(x, y, color);
+ }
+ }
+ return wImage;
+ }
+ return null;
+ }
+
+ //将javafx中Color转换为awt中Color
+ public static java.awt.Color getAwtColor(javafx.scene.paint.Color color) {
+ java.awt.Color colorw = new Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
+ return colorw;
+ }
}
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/JavaFxDragResizer.java b/src/main/java/com/xwintop/xcore/util/javafx/JavaFxDragResizer.java
new file mode 100644
index 0000000000000000000000000000000000000000..c742ac8260be4ca9eec7a736c6b60f0669cc2a13
--- /dev/null
+++ b/src/main/java/com/xwintop/xcore/util/javafx/JavaFxDragResizer.java
@@ -0,0 +1,127 @@
+package com.xwintop.xcore.util.javafx;
+
+import javafx.scene.Cursor;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Region;
+
+/**
+ * @ClassName: JavaFxDragResizer
+ * @Description: 设置控件自定义大小
+ * @author: xufeng
+ * @date: 2021/12/25 14:40
+ */
+
+public class JavaFxDragResizer {
+
+ /**
+ * The margin around the control that a user can click in to start resizing
+ * the region.
+ */
+ private static final int RESIZE_MARGIN = 10;
+ private final Region region;
+ private double y;
+ private double x;
+ private boolean initMinHeight;
+ private boolean initMinWidth;
+ private boolean draggableZoneX, draggableZoneY;
+ private boolean dragging;
+ private boolean draggableX = true;
+ private boolean draggableY = true;
+
+ private JavaFxDragResizer(Region aRegion) {
+ region = aRegion;
+ this.setOnMouse();
+ }
+
+ private JavaFxDragResizer(Region aRegion, boolean draggableX, boolean draggableY) {
+ region = aRegion;
+ this.draggableX = draggableX;
+ this.draggableY = draggableY;
+ this.setOnMouse();
+ }
+
+ public static void makeResizableX(Region region) {
+ new JavaFxDragResizer(region, true, false);
+ }
+
+ public static void makeResizableY(Region region) {
+ new JavaFxDragResizer(region, false, true);
+ }
+
+ public static void makeResizable(Region region) {
+ new JavaFxDragResizer(region);
+ }
+
+ protected void setOnMouse() {
+ region.setOnMousePressed(event -> this.mousePressed(event));
+ region.setOnMouseDragged(event -> this.mouseDragged(event));
+ region.setOnMouseMoved(event -> this.mouseOver(event));
+ region.setOnMouseReleased(event -> this.mouseReleased(event));
+ }
+
+ protected void mouseReleased(MouseEvent event) {
+ dragging = false;
+ region.setCursor(Cursor.DEFAULT);
+ }
+
+ protected void mouseOver(MouseEvent event) {
+ if (isInDraggableZone(event) || dragging) {
+ if (draggableZoneY && draggableZoneX) {
+ region.setCursor(Cursor.SE_RESIZE);
+ } else if (draggableZoneY) {
+ region.setCursor(Cursor.S_RESIZE);
+ } else if (draggableZoneX) {
+ region.setCursor(Cursor.E_RESIZE);
+ }
+ } else {
+ region.setCursor(Cursor.DEFAULT);
+ }
+ }
+
+
+ //had to use 2 variables for the controll, tried without, had unexpected behaviour (going big was ok, going small nope.)
+ protected boolean isInDraggableZone(MouseEvent event) {
+ draggableZoneY = draggableY && (boolean) (event.getY() > (region.getHeight() - RESIZE_MARGIN));
+ draggableZoneX = draggableX && (boolean) (event.getX() > (region.getWidth() - RESIZE_MARGIN));
+ return (draggableZoneY || draggableZoneX);
+ }
+
+ protected void mouseDragged(MouseEvent event) {
+ if (!dragging) {
+ return;
+ }
+ if (draggableY && draggableZoneY) {
+ double mousey = event.getY();
+ double newHeight = region.getMinHeight() + (mousey - y);
+ region.setMinHeight(newHeight);
+ y = mousey;
+ }
+ if (draggableX && draggableZoneX) {
+ double mousex = event.getX();
+ double newWidth = region.getMinWidth() + (mousex - x);
+ region.setMinWidth(newWidth);
+ x = mousex;
+ }
+ }
+
+ protected void mousePressed(MouseEvent event) {
+ // ignore clicks outside of the draggable margin
+ if (!isInDraggableZone(event)) {
+ return;
+ }
+ dragging = true;
+ // make sure that the minimum height is set to the current height once,
+ // setting a min height that is smaller than the current height will
+ // have no effect
+ if (!initMinHeight) {
+ region.setMinHeight(region.getHeight());
+ initMinHeight = true;
+ }
+ y = event.getY();
+ if (!initMinWidth) {
+ region.setMinWidth(region.getWidth());
+ initMinWidth = true;
+ }
+ x = event.getX();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/JavaFxSystemUtil.java b/src/main/java/com/xwintop/xcore/util/javafx/JavaFxSystemUtil.java
index c7d9cc6dd5872f421b1a02c35d76027fc91c46fc..5248d84c6ddbefb85720b88f7eb49616b55e1ccd 100644
--- a/src/main/java/com/xwintop/xcore/util/javafx/JavaFxSystemUtil.java
+++ b/src/main/java/com/xwintop/xcore/util/javafx/JavaFxSystemUtil.java
@@ -5,14 +5,16 @@ import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.File;
import java.io.IOException;
+
import javafx.geometry.Rectangle2D;
import javafx.stage.Screen;
import javafx.stage.Stage;
import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
-@Slf4j
+//@Slf4j
public class JavaFxSystemUtil {
-
+ private static Logger log = org.slf4j.LoggerFactory.getLogger(JavaFxSystemUtil.class);
/**
* @deprecated 使用 {@link com.xwintop.xcore.javafx.FxApp#primaryStage}
*/
@@ -21,6 +23,7 @@ public class JavaFxSystemUtil {
/**
* 打开目录
+ *
* @param directoryPath 目录路径
*/
public static void openDirectory(String directoryPath) {
@@ -31,14 +34,17 @@ public class JavaFxSystemUtil {
}
}
-
/**
* 获取屏幕尺寸
+ *
* @param width 宽度比
* @param height 高度比
* @return 屏幕尺寸
*/
public static double[] getScreenSizeByScale(double width, double height) {
+// if (WebAPI.isBrowser()) {
+// return new double[]{1280, 900};
+// }
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double screenWidth = screenSize.width * width;
double screenHeight = screenSize.height * height;
diff --git a/src/main/java/com/xwintop/xcore/util/javafx/JavaFxViewUtil.java b/src/main/java/com/xwintop/xcore/util/javafx/JavaFxViewUtil.java
index a535731809630d35b2aa71237fa05ca5128c1af5..e8eb294c56fddb89473779a16a811ae42188c233 100644
--- a/src/main/java/com/xwintop/xcore/util/javafx/JavaFxViewUtil.java
+++ b/src/main/java/com/xwintop/xcore/util/javafx/JavaFxViewUtil.java
@@ -4,6 +4,8 @@ import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.lang.Singleton;
import com.jfoenix.controls.JFXDecorator;
import com.xwintop.xcore.javafx.FxApp;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.Event;
@@ -21,7 +23,6 @@ import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
-import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
@@ -35,6 +36,7 @@ import javafx.util.StringConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
+import org.slf4j.Logger;
import java.lang.reflect.Method;
import java.net.URL;
@@ -45,9 +47,9 @@ import java.util.function.Consumer;
import static com.xwintop.xcore.javafx.helper.LayoutHelper.iconView;
-@Slf4j
+//@Slf4j
public class JavaFxViewUtil {
-
+ private static Logger log = org.slf4j.LoggerFactory.getLogger(JavaFxViewUtil.class);
/**
* 创建对话框窗体
*
@@ -58,6 +60,7 @@ public class JavaFxViewUtil {
* @param fullScreenButton 是否显示全屏按钮
* @param maximizeButton 是否显示最大化按钮
* @param minimizeButton 是否显示最小化按钮
+ *
* @return 新建的窗体对象
*/
public static Stage jfxStage(
@@ -210,8 +213,13 @@ public class JavaFxViewUtil {
public static void openNewWindow(String title, String iconUrl, Parent root, double width, double height,
boolean fullScreen, boolean max, boolean min) {
Stage newStage = getNewStageNull(title, iconUrl, root, width, height, fullScreen, max, min);
- newStage.initModality(Modality.APPLICATION_MODAL);
- newStage.show();
+// if (WebAPI.isBrowser()) {
+// WebAPI webAPI = WebAPI.getWebAPI(JavaFxSystemUtil.mainStage);
+// webAPI.openStageAsTab(newStage);
+// } else {
+ newStage.initModality(Modality.APPLICATION_MODAL);
+ newStage.show();
+// }
}
//获取一个新窗口
@@ -327,29 +335,25 @@ public class JavaFxViewUtil {
*/
public static void addTableViewOnMouseRightClickMenu(TableView