非Application类JavaFX绘图库开发及FatJar打包问题求助
问题:开发非Application类的JavaFX绘图弹窗库及FatJar打包问题
问题简述
如何开发可创建JavaFX弹窗、具备绘图能力的Java库(无需继承JavaFX的Application类),以及如何将使用该库的应用打包为FatJar?
详细描述
我正在开发一个支持序列化的DataFrame库(Java生态中未找到同类支持序列化的库),核心逻辑已完成。通过chart-fx库实现了表格数据绘图功能,用带静态main的测试类在IntelliJ中运行正常,但Maven打包成FatJar后运行报错:
java.lang.UnsupportedOperationException: Cannot resolve 'fa-arrows-alt'
因为是开发库而非应用,我没有遵循JavaFX标准的继承Application类的方式,而是使用Platform.startup(/* 包含JavaFX代码的Lambda函数 */)方法。添加-Dprism.verbose=true参数运行FatJar的控制台日志如下:
jan. 25, 2024 3:55:38 PM com.sun.javafx.application.PlatformImpl startup WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @3b192d32' Prism pipeline init order: d3d sw Using Double Precision Marlin Rasterizer Using dirty region optimizations Not using texture mask for primitives Not forcing power of 2 sizes for textures Using hardware CLAMP_TO_ZERO mode Opting in for HiDPI pixel scaling Prism pipeline name = com.sun.prism.d3d.D3DPipeline Loading D3D native library ... succeeded. D3DPipelineManager: Created D3D9Ex device Direct3D initialization succeeded (X) Got class = class com.sun.prism.d3d.D3DPipeline Initialized prism pipeline: com.sun.prism.d3d.D3DPipeline Maximum supported texture size: 16384 Maximum texture size clamped to 4096 OS Information: Windows version 10.0 build 19042 D3D Driver Information: NVIDIA GeForce GT 710 \\.\DISPLAY1 Driver nvldumdx.dll, version 27.21.14.5671 Pixel Shader version 3.0 Device : ven_10DE, dev_128B, subsys_118B10DE Max Multisamples supported: 4 SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. java.lang.UnsupportedOperationException: Cannot resolve 'fa-arrows-alt' at org.kordamp.ikonli.AbstractIkonResolver.resolve(AbstractIkonResolver.java:61) at org.kordamp.ikonli.javafx.IkonResolver.resolve(IkonResolver.java:73) at org.kordamp.ikonli.javafx.FontIcon.setIconLiteral(FontIcon.java:251) at org.kordamp.ikonli.javafx.FontIcon.<init>(FontIcon.java:92) at io.fair_acc.chartfx.plugins.Zoomer.getZoomInteractorBar(Zoomer.java:421) at io.fair_acc.chartfx.plugins.Zoomer.<init>(Zoomer.java:148) at io.fair_acc.chartfx.plugins.Zoomer.<init>(Zoomer.java:252) at io.fair_acc.chartfx.plugins.Zoomer.<init>(Zoomer.java:243) at sst.visualization.chartFxBased.LineChart.lambda$plot$1(LineChart.java:85) at com.sun.javafx.application.PlatformImpl.lambda$startup$5(PlatformImpl.java:294) at com.sun.glass.ui.Application.invokeAndWait(Application.java:470) at com.sun.javafx.tk.quantum.QuantumToolkit.runToolkit(QuantumToolkit.java:377) at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$startup$10(QuantumToolkit.java:290) at com.sun.glass.ui.Application.lambda$run$1(Application.java:155) at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:185) at java.base/java.lang.Thread.run(Thread.java:1583) vsync: true vpipe: true
已尝试方案
- 使用
--module-path和--add-modules参数运行,命令为java --module-path C:/javafx-jmods --add-modules javafx.base -jar sst-0.0.1.0-withDependencies.jar,但出现Module javafx.base not found错误,更换其他模块名也无效。 - 在pom.xml中添加
javafx-maven-plugin,但无效果。
个人想法
之前开发过继承Application类的JavaFX应用,可正常运行。
补充问题
不确定Platform.startup是否是开发非应用类JavaFX绘图弹窗的正确方式,不想花太多时间系统学习JavaFX。
解决方案
1. 关于Platform.startup的正确性
Platform.startup()是开发非Application类的JavaFX库的正确方式,它可以在非JavaFX应用的上下文初始化JavaFX运行时,适合库的场景。但要注意:
- 必须确保
Platform.startup()只被调用一次,多次调用会抛出异常 - 所有JavaFX UI操作必须在JavaFX应用线程执行,后续更新UI可以用
Platform.runLater()
2. 解决FatJar打包后的图标解析错误
报错Cannot resolve 'fa-arrows-alt'是因为chart-fx依赖的ikonli字体图标在FatJar打包时没有被正确包含,或者资源路径被破坏。解决步骤:
- 确保依赖完整:在pom.xml中显式添加ikonli的Font Awesome依赖,因为chart-fx可能是间接依赖,打包时可能遗漏:
<dependency> <groupId>org.kordamp.ikonli</groupId> <artifactId>ikonli-fontawesome-pack</artifactId> <version>12.3.1</version> <!-- 使用与chart-fx兼容的版本 --> </dependency> - 修正Maven打包配置:使用
maven-shade-plugin打包时,需要配置资源转换器,处理ikonli的字体资源:<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <!-- 处理ikonli的字体资源 --> <transformer implementation="org.apache.maven.plugins.shade.resource.ResourceBundleAppendingTransformer"> <resource>META-INF/org/kordamp/ikonli/ikonli.properties</resource> </transformer> <!-- 设置主类(如果是测试用的FatJar) --> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>your.test.MainClass</mainClass> </transformer> </transformers> <filters> <!-- 排除重复的签名文件,避免打包错误 --> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> - 避免模块路径冲突:因为你是用非模块化方式打包(unnamed module),不要用
--module-path参数运行FatJar,直接用java -jar your-fatjar.jar即可,之前的Module javafx.base not found是因为你的FatJar已经包含了JavaFX类,不需要额外指定模块路径。
3. 额外注意事项
- 如果你的库需要被其他应用依赖,建议将JavaFX依赖设置为
provided,让使用方自行管理JavaFX依赖,避免冲突:<dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>21.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-fxml</artifactId> <version>21.0.1</version> <scope>provided</scope> </dependency> - 测试时,确保IntelliJ的运行配置中没有添加额外的模块路径参数,避免和打包后的运行方式不一致。
内容的提问来源于stack exchange,提问作者Lucas Monteiro
相关产品推荐
相关产品推荐

