概述
文章目录
- 准备工作
- 使用命令行简单编译
- 使用 gradle 编译
- module build.gradle
- project build.gradle
- 非模块化编译
- jpacakge
- 优化
- 瘦身
- 通过 Inno Setup 自定义安装包
- 根据需要,修改脚本代码:
- 运行时问题
- 1. JNI 的动态库路径配置
这个小项目弄完了,把之前记录都整理编辑了一下,后续完善的话再追加。
准备工作
javafx 在 java11 以后被单独分开了,在这里下载 SDK,教程在这里
使用命令行简单编译
idea 能直接生成 JAVAFX 项目,根据教程在项目属性里添加好 lib 依赖,代码就不报错了,但是需要添加 vm option 的参数才可以编译运行。
好的,坑来了,当你根据教程配置好 PATH_TO_FX 的环境变量,并且在命令行 echo 通过了没有问题,配置进 vm option 的时候,会告诉你 FindException: Module javafx.base not found
。一般也不会用在项目中用到命令行编译,不方便。懒得试就直接跳到 gradle 编译的部分吧。
D:develop_envjdk11binjava.exe --module-path %PATH_TO_FX% --add-modules javafx.controls,javafx.fxml --add-modules javafx.base,javafx.graphics --add-reads javafx.base=ALL-UNNAMED --add-reads javafx.graphics=ALL-UNNAMED "-javaagent:C:Program FilesJetBrainsIntelliJ IDEA 2020.2libidea_rt.jar=62234:C:Program FilesJetBrainsIntelliJ IDEA 2020.2bin" -Dfile.encoding=UTF-8 -classpath D:demosaaaoutproductionaaa;D:develop_envjavafx-11.0.2libsrc.zip;D:develop_envjavafx-11.0.2libjavafx-swt.jar;D:develop_envjavafx-11.0.2libjavafx.web.jar;D:develop_envjavafx-11.0.2libjavafx.base.jar;D:develop_envjavafx-11.0.2libjavafx.fxml.jar;D:develop_envjavafx-11.0.2libjavafx.media.jar;D:develop_envjavafx-11.0.2libjavafx.swing.jar;D:develop_envjavafx-11.0.2libjavafx.controls.jar;D:develop_envjavafx-11.0.2libjavafx.graphics.jar sample.Main
Error occurred during initialization of boot layer
java.lang.module.FindException: Module javafx.base not found
Process finished with exit code 1
但是,当你用命令行测试的时候,没问题的啊,这就很蛋疼了,我以为是后面加的参数配错了,原来是 IDEA 里不支持这么调用环境变量。需要把路径直接写入 vm option 才可以,不能用变量,就算在 IntelliJ->File->Settings->Appearance & Behavior->Path Variables
中配一遍也不行。来 骗!来 偷袭!我们刚上手写JAVAFX的新同志,这好吗?这不好。希望官方教程耗子尾汁,好好反思。
使用 gradle 编译
好的,跨过第一个坑,接下来用 gradle 或者 maven 工具进行编译打包,我选了 gradle,maven 太丑。
根据教程,建立一个 gradle + java
项目,添加一个 module-info.java
文件,注意需要加在 src/java
的下面,和代码包根目录平级,这里仔细点没什么问题,贴一下, module 的 name 可以自定义。
module javafx {
requires javafx.controls;
requires javafx.fxml;
opens tech.sunyx.sample to javafx.fxml;
exports tech.sunyx.sample;
}
module build.gradle
plugins {
id 'application'
id 'java'
id 'org.openjfx.javafxplugin' version '0.0.8'
id 'org.beryx.jlink' version '2.12.0'
}
version '1.0.0'
javafx {
version = "11.0.2"
modules = [ 'javafx.controls','javafx.fxml' ]
mainClassName = "tech.sunyx.sample.Main"
}
// gradle 6.3+ 用这个形式写,6.3 直接写在 mainClassName
run {
main = "$moduleName/tech.sunyx.sample.Main"
}
jlink {
launcher {
name = 'test.exe'
}
}
dependencies {
implementation 'com.dlsc.formsfx:formsfx-core:11.4.1'
}
project build.gradle
buildscript {
repositories {
jcenter()
}
}
subprojects {
apply plugin: 'java'
sourceCompatibility = 11
group 'sunyx.tech'
repositories {
jcenter()
mavenCentral()
flatDir { dirs 'libs' }
}
dependencies {
testImplementation 'junit:junit:4.12'
}
}
并添加 build.gradle
配置好 gradle 插件。然后建立比较正式的项目结构,把刚刚那个项目的 3 个文件拿过来放在对应目录,如图。
看似没有问题,run 一下又报错了。告诉我 13 行 Location is required.
。其实 fxml 文件放到 Resource 文件夹之后,虽然在根目录,但是需要加个 /
,很容易忽略的问题。我的做法是 resource 文件夹下按照 android 的目录格式建立了一个 layout
文件夹,然后把界面文件放这里面,这样子一目了然,下次也不会忘了根目录要加 /
又出问题了
非模块化编译
真正的项目采用了 java9 的模块化写法之后(包含 module-info.java
文件),在依赖非模块化的 jar 包时可能出现多模块重复引用同一个包的问题,具体问题参考 java 模块化说明,而且此问题没有好方法解决。参考 javafx 非模块化打包应用,改用非模块化打包。
plugins {
id 'application'
id 'java'
id 'org.openjfx.javafxplugin' version '0.0.9'
//id 'org.beryx.jlink' version '2.12.0'
id 'org.beryx.runtime' version '1.11.4'
id "com.github.johnrengelman.shadow" version "6.1.0"
}
version '1.0.0'
javafx {
version = "11.0.2"
modules = [ 'javafx.controls','javafx.fxml' ]
}
application {
mainClassName = 'com.juno.converter.Launcher'
applicationName = project.name
}
runtime {
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
// 不显示黑框
noConsole = true
}
jpackage {
if (org.gradle.internal.os.OperatingSystem.current ().windows) {
jpackageHome = "D:\develop_env\jdk-16"
imageOptions = ['--icon', 'src/main/resources/icon/hellofx.ico']
imageOptions += ['--vendor', 'juno']
installerName = project.name + '_win_x64'
//installerOptions += ['--temp',"${buildDir}/tempDir"]
installerOptions += ['--install-dir','DtsTools/data2excel']
// 配合 resource 文件夹中的 wxl 文件,指定安装包语言参数,--temp 选项不能打开
installerOptions += ['--resource-dir', "src/main/resources"]
installerOptions += ['--win-per-user-install', '--win-dir-chooser', '--win-menu', '--win-shortcut']
//installerOptions += ['--verbose']
}
}
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.12'
annotationProcessor 'org.projectlombok:lombok:1.18.12'
implementation ('com.alibaba:easyexcel:2.2.6') {
exclude group: 'org.apache.poi', module: 'poi'
exclude group: 'org.apache.poi', module: 'poi-ooxml'
}
implementation 'org.apache.poi:poi:4.1.2'
implementation 'org.apache.poi:poi-ooxml:4.1.2'
implementation 'org.slf4j:slf4j-simple:1.7.26'
implementation project (':pojo')
implementation project (':core')
implementation project (':utils')
}
这个方法的好处在于用户不需要安装 jre 环境就可以解压即用,配合 jpackage 工具(java14 中发布但有 bug,用 OPENJDK16),可以做成安装包的方式符合用户习惯。
有一个坑点在于,runtime 这个插件需要一个 Launcher
类做程序入口,类名一定要叫这个,用别的类名会发现 JAVAFX 的依赖包找不到,无法启动程序。而且 官方教程 里也没说清楚,很奇怪的设计。
shadow 这个插件之前我在 打包带源码的 fatjar 到 maven 仓库 这篇文章中也有介绍,很强大的插件,这边用来打 jar 包并生成 jre 环境和启动脚本。
jpacakge
生成可执行的 exe 只需要执行 jpackageImage
这个 task,然后在 build/jpackage
文件夹下找到即可。而 jpackage
指令生成的是把可执行文件做成安装包。
jpackage 工具使用了 wix 这个 exe 生成工具,目前 jdk14 版本的 jpackage 在非英语环境 wix 打包会报错,在 JDK16 版本会修复,所以目前编译我用的 JDK11 LTS,但是打包用了 JDK16。解决方案查看 issue,需要在 src/main/resources
资源文件夹下增加一个 zh_cn.wxl
。配合 gradle 中的调用,把 Culture
和 Codepage
定义内容传给打包工具,文件内容如下
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="zh-CN" xmlns="http://schemas.microsoft.com/wix/2006/localization" Codepage="936"/>
优化
瘦身
参考这篇文章,后续还有给 jre 瘦身的余地,目前打出的安装包 57M。
通过 Inno Setup 自定义安装包
打安装包需要更多自定义内容,推荐 Inno Setup
这个项目,可以编写脚本自定义各种东西。
教程 https://www.cnblogs.com/benpaodejiandan/p/7081011.html
官网下载 https://jrsoftware.org/isdl.php
中文语言包下载 https://jrsoftware.org/files/istrans/
根据需要,修改脚本代码:
-
修改安装包左侧位图,其大小一般为 164x314px,在 INNO 脚本的 [Setup] 段添加如下代码:
WizardImageFile=ResWizardImage.bmp
注:红色的标记为位图路径,可以用相对路径或绝对路径 -
修改安装包右上角位图,其大小一般为 55x55px,在 INNO 脚本的 [Setup] 段添加如下代码:
WizardSmallImageFile=ResWizardSmallImage.bmp
-
修改安装包左下角的 BeveledLabel 内容,常见有两种方式:
- 临时性修改 在 INNO 脚本的 [Messages] 段添加如下代码:BeveledLabel = 软件汉化:XXX
- 永久性修改 用记事本打开 INNO 目录中的 “Default.isl” 修改 “BeveledLabel = ” 后的内容:软件汉化:XXX
-
修改安装包欢迎标签内容,即 WelcomeLabel2。
用记事本打开 INNO 目录中的 “Default.isl” 修改 “WelcomeLabel2 = ” 后的内容:
WelcomeLabel2 = 正在准备安装 [name/ver]…%n%n 推荐您在继续安装前关闭所有其它应用程序。%n%n 软件汉化:XXX%n%n 电子邮件:xxx%n%n
注:%n 在 INNO 脚本中为换行符 -
安装结束后动行主程序或打开文件等,只需在 INNO 脚本的 [Run] 段修改代码:
Filename: {app}PDFUnlocker.exe; Description: 启动 PDF Unlocker; Flags: nowait postinstall shellexec;
Filename: {app}汉化说明.txt; Description: 查看说明; Flags: nowait postinstall shellexec
运行时问题
1. JNI 的动态库路径配置
System.loadLibrary
通过jvm参数中的java.library.path
配置查询路径,会加载其中的so或者dll,但发现2个问题:
- gradle 启动Java程序。VM option 中配置
-Djava.library.path=D:/workspace/semi-secs/gem/src/main/jinLibs
无效 - 打包的exe发给客户如何配置
java.library.path
都是通过build.gradle文件中配置做解决
- gradle的run命令需要通过对应的block添加属性
run { systemProperty "java.library.path", 'D:/workspace/semi-secs/gem/src/main/jinLibs' }
- org.beryx.runtime 插件可以,launcher中增加一条配置,{{BIN_DIR}}代表app文件夹外层,和exe文件位置相同
launcher { //不显示黑框 noConsole = true jvmArgs = ['-Djava.library.path={{BIN_DIR}}'] }
最后
以上就是伶俐万宝路为你收集整理的在IntelliJ IDEA中使用 JAVAFX 过程记录的全部内容,希望文章能够帮你解决在IntelliJ IDEA中使用 JAVAFX 过程记录所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复