From 7119d1175cb46e655d8e0d42ef714eacea6b2932 Mon Sep 17 00:00:00 2001 From: Timi Date: Tue, 13 Jan 2026 17:50:44 +0800 Subject: [PATCH] add FXTimiInject --- .gitignore | 4 + pom.xml | 10 ++- src/main/java/com/imyeyu/fx/TimiFX.java | 3 + .../java/com/imyeyu/fx/bean/Interpolates.java | 4 +- .../com/imyeyu/fx/config/BindingsConfig.java | 19 ++++- .../com/imyeyu/fx/inject/FXTimiInject.java | 74 +++++++++++++++++++ .../java/com/imyeyu/fx/task/RunAsync.java | 7 +- .../com/imyeyu/fx/task/RunAsyncScheduled.java | 1 + .../imyeyu/fx/utils/AnimationRenderer.java | 6 +- src/main/java/com/imyeyu/fx/utils/BgFill.java | 2 +- .../java/com/imyeyu/fx/utils/BgImage.java | 7 +- .../com/imyeyu/fx/utils/SmoothScroll.java | 6 ++ 12 files changed, 122 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/imyeyu/fx/inject/FXTimiInject.java diff --git a/.gitignore b/.gitignore index 5ff6309..0ec825b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +/.claude +/CLAUDE.md +/AGENTS.md + target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ diff --git a/pom.xml b/pom.xml index e0699d6..396ea57 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.imyeyu.fx timi-fx - 0.0.1 + 0.0.2 21.0.2 @@ -25,7 +25,13 @@ com.imyeyu.config timi-config - 0.0.1 + 0.0.2 + + + com.imyeyu.inject + timi-inject + 0.0.2 + true diff --git a/src/main/java/com/imyeyu/fx/TimiFX.java b/src/main/java/com/imyeyu/fx/TimiFX.java index 599c636..29db211 100644 --- a/src/main/java/com/imyeyu/fx/TimiFX.java +++ b/src/main/java/com/imyeyu/fx/TimiFX.java @@ -295,6 +295,9 @@ public final class TimiFX { if (flow == null) { throw new UnsupportedOperationException("unsupported this control"); } + if (flow.getCellCount() == 0 || flow.getCell(0) == null) { + return; + } int offset = Calc.floor(flow.getHeight() * .5 / flow.getCell(0).getHeight()); // 滚动 Method method = Ref.getMethod(control.getClass(), "scrollTo", int.class); diff --git a/src/main/java/com/imyeyu/fx/bean/Interpolates.java b/src/main/java/com/imyeyu/fx/bean/Interpolates.java index 18a805f..f8e3760 100644 --- a/src/main/java/com/imyeyu/fx/bean/Interpolates.java +++ b/src/main/java/com/imyeyu/fx/bean/Interpolates.java @@ -68,7 +68,7 @@ public enum Interpolates { */ public double[][] buildBezierPoint(double boost, double precision) { if (precision < 4) { - throw new IllegalArgumentException("precision can not lessthan 4: " + precision); + throw new IllegalArgumentException("precision can not less than 4: " + precision); } precision = 1D / precision; @@ -176,4 +176,4 @@ public enum Interpolates { public SplineInterpolator getValue() { return value; } -} \ No newline at end of file +} diff --git a/src/main/java/com/imyeyu/fx/config/BindingsConfig.java b/src/main/java/com/imyeyu/fx/config/BindingsConfig.java index 30569a8..c966db7 100644 --- a/src/main/java/com/imyeyu/fx/config/BindingsConfig.java +++ b/src/main/java/com/imyeyu/fx/config/BindingsConfig.java @@ -155,6 +155,9 @@ public final class BindingsConfig { @Override protected String serialize(Field field, ObjectProperty property) { + if (property.getValue() == null) { + return null; + } return TimiFX.toHexString(property.getValue()); } @@ -173,7 +176,14 @@ public final class BindingsConfig { @Override protected String serialize(Field field, ObjectProperty property) { - return TimiFX.toHexString(Color.valueOf(property.toString())); + Paint paint = property.getValue(); + if (paint == null) { + return null; + } + if (paint instanceof Color color) { + return TimiFX.toHexString(color); + } + return paint.toString(); } @Override @@ -191,6 +201,9 @@ public final class BindingsConfig { @Override protected String serialize(Field field, ObjectProperty property) { + if (property.getValue() == null || property.getValue().getFills().isEmpty()) { + return null; + } return TimiFX.toHexString(Color.valueOf(property.getValue().getFills().getFirst().getFill().toString())); } @@ -225,7 +238,7 @@ public final class BindingsConfig { throw new RuntimeException(e); } } - throw new RuntimeException("not found " + field.getType() + " property converter"); + throw new RuntimeException("未找到 " + field.getType() + " 属性转换器"); } @SuppressWarnings("unchecked") @@ -249,7 +262,7 @@ public final class BindingsConfig { throw new RuntimeException(e); } } - throw new RuntimeException("not found " + genericType + " property converter"); + throw new RuntimeException("未找到 " + genericType + " 属性转换器"); } }; diff --git a/src/main/java/com/imyeyu/fx/inject/FXTimiInject.java b/src/main/java/com/imyeyu/fx/inject/FXTimiInject.java new file mode 100644 index 0000000..54527a8 --- /dev/null +++ b/src/main/java/com/imyeyu/fx/inject/FXTimiInject.java @@ -0,0 +1,74 @@ +package com.imyeyu.fx.inject; + +import com.imyeyu.inject.TimiInject; +import javafx.application.Application; +import javafx.stage.Stage; + +/** + * JavaFX 与 TimiInject 集成支持 + *

+ * 提供 JavaFX Application 和 Stage 对象到依赖注入容器的集成。 + * 在 Application.start() 方法中调用 {@link #register} 方法即可完成注册和注入。 + *

+ * 使用示例: + *

+ * public class Main extends Application {
+ *     @Inject
+ *     private SomeService service;
+ *
+ *     @Override
+ *     public void start(Stage stage) {
+ *         TimiInject inject = FXTimiInject.run(Main.class, this, stage);
+ *         // 现在 service 已经被注入,可以使用了
+ *     }
+ * }
+ * 
+ * + * @author 夜雨 + */ +public final class FXTimiInject { + + private FXTimiInject() { + throw new UnsupportedOperationException("工具类不允许实例化"); + } + + /** + * 启动容器并在初始化前注册 Application 和 Stage + * + * @param applicationClass 启动类 + * @param app JavaFX Application 实例 + * @param stage JavaFX 主舞台(Primary Stage) + * @return TimiInject 容器实例 + */ + public static TimiInject run(Class applicationClass, Application app, Stage stage) { + TimiInject inject = TimiInject.run(applicationClass, injector -> registerBeans(injector, app, stage)); + inject.inject(app); + return inject; + } + + /** + * 将 JavaFX Application 和 Stage 注册到容器,并对 Application 执行字段注入 + *

+ * 此方法会: + *

    + *
  1. 将 Application 对象以 "application" 为名称注册到容器
  2. + *
  3. 将 Stage 对象以 "stage" 和 "primaryStage" 为名称注册到容器
  4. + *
  5. 对 Application 对象执行字段注入,使其 @Inject 字段生效
  6. + *
+ * + * @param inject TimiInject 容器实例 + * @param app JavaFX Application 实例 + * @param stage JavaFX 主舞台(Primary Stage) + */ + public static void register(TimiInject inject, Application app, Stage stage) { + registerBeans(inject, app, stage); + inject.inject(app); + } + + private static void registerBeans(TimiInject inject, Application app, Stage stage) { + // 注册 Application 和 Stage 到容器 + inject.registerBean("application", app); + inject.registerBean("stage", stage); + inject.registerBean("primaryStage", stage); + } +} diff --git a/src/main/java/com/imyeyu/fx/task/RunAsync.java b/src/main/java/com/imyeyu/fx/task/RunAsync.java index 0b153f1..f610a19 100644 --- a/src/main/java/com/imyeyu/fx/task/RunAsync.java +++ b/src/main/java/com/imyeyu/fx/task/RunAsync.java @@ -52,12 +52,8 @@ import com.imyeyu.java.bean.CallbackReturn; * * * @author 夜雨 - * @since - * + * @since 2021-02-13 12:56 * @param 数据处理返回类型 - * - * @author 夜雨 - * @version 2021-02-13 12:56 */ public abstract class RunAsync extends Service { @@ -192,6 +188,7 @@ public abstract class RunAsync extends Service { /** 中断任务 */ public void interrupt() { isInterrupted = true; + cancel(); } // ---------- 静态构造 ---------- diff --git a/src/main/java/com/imyeyu/fx/task/RunAsyncScheduled.java b/src/main/java/com/imyeyu/fx/task/RunAsyncScheduled.java index 593d901..c9208c1 100644 --- a/src/main/java/com/imyeyu/fx/task/RunAsyncScheduled.java +++ b/src/main/java/com/imyeyu/fx/task/RunAsyncScheduled.java @@ -219,6 +219,7 @@ public abstract class RunAsyncScheduled extends ScheduledService { /** 中断任务 */ public void interrupt() { isInterrupted = true; + cancel(); } // ---------- 静态构造 ---------- diff --git a/src/main/java/com/imyeyu/fx/utils/AnimationRenderer.java b/src/main/java/com/imyeyu/fx/utils/AnimationRenderer.java index b355d65..fee9e07 100644 --- a/src/main/java/com/imyeyu/fx/utils/AnimationRenderer.java +++ b/src/main/java/com/imyeyu/fx/utils/AnimationRenderer.java @@ -326,7 +326,7 @@ public class AnimationRenderer { * 一次性动画 * * @author 夜雨 - * @since 2023-05-16 16:02 + * @since 2023-05-16 16:02 */ public static class Animation { @@ -341,7 +341,7 @@ public class AnimationRenderer { * 一次性动画回调 * * @author 夜雨 - * @since 2023-05-14 10:10 + * @since 2023-05-14 10:10 */ public interface AnimationCallback { @@ -353,4 +353,4 @@ public class AnimationRenderer { */ void handler(double deltaSecond, double percent); } -} \ No newline at end of file +} diff --git a/src/main/java/com/imyeyu/fx/utils/BgFill.java b/src/main/java/com/imyeyu/fx/utils/BgFill.java index c582537..65212b1 100644 --- a/src/main/java/com/imyeyu/fx/utils/BgFill.java +++ b/src/main/java/com/imyeyu/fx/utils/BgFill.java @@ -195,4 +195,4 @@ public class BgFill { } return new BgFill(sb.toString()).build(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/imyeyu/fx/utils/BgImage.java b/src/main/java/com/imyeyu/fx/utils/BgImage.java index 6cb3ec7..fe7e2be 100644 --- a/src/main/java/com/imyeyu/fx/utils/BgImage.java +++ b/src/main/java/com/imyeyu/fx/utils/BgImage.java @@ -10,8 +10,6 @@ import javafx.scene.layout.BackgroundRepeat; import javafx.scene.layout.BackgroundSize; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; /** * 背景图片封装。{@link #build()} 作为导出作用,最后执行 @@ -49,10 +47,9 @@ public class BgImage { * 背景图构造器 * * @param file 图片文件(程序外资源) - * @throws FileNotFoundException 找不到文件 */ - public BgImage(File file) throws FileNotFoundException { - this(new Image(new FileInputStream(file))); + public BgImage(File file) { + this(new Image(file.toURI().toString())); } /** diff --git a/src/main/java/com/imyeyu/fx/utils/SmoothScroll.java b/src/main/java/com/imyeyu/fx/utils/SmoothScroll.java index 5eb899c..6ffbe2b 100644 --- a/src/main/java/com/imyeyu/fx/utils/SmoothScroll.java +++ b/src/main/java/com/imyeyu/fx/utils/SmoothScroll.java @@ -311,6 +311,9 @@ public class SmoothScroll { * @param sizeFunc 高度回调 */ public static void scrollPane(ScrollPane scrollPane, DoubleProperty scrollProperty, Function sizeFunc) { + if (scrollPane.getContent() == null) { + return; + } final double[] derivatives = new double[FRICTIONS.length]; Timeline timeline = new Timeline(); @@ -350,6 +353,9 @@ public class SmoothScroll { } double dy = derivatives[derivatives.length - 1]; double size = sizeFunc.apply(scrollPane.getContent().getLayoutBounds()); + if (size <= 0) { + return; + } scrollProperty.set(Math.min(Math.max(scrollProperty.get() + dy / size, 0), 1)); if (Math.abs(dy) < .001) { timeline.stop();