1、系统最小化托盘
参考资料:
https://blog.51cto.com/u_14191/6310480
javafx 设置最小窗口大小 - Java (1) - 芒果文档
注意事项
1.直接使用第一个参考资料中的MinWindow类即可。
#最小化托盘 -- 一般放置在 start(Stage stage)处
MinWindow.getInstance().listen(stage);
#隐藏最小化托盘 -- 一般放置在关闭窗口按钮的controller方法处
MinWindow.getInstance().hide(stage);
2.图片链接,我的放在了这个路径下
/img/icon.png
3. 配置pom文件
<!--系统最小托盘参数,此参数必须, 空格及后面的-xmx是设置内存大小的,可以不用-->
<vmArgs>-Djava.awt.headless=false -Xmx1024m</vmArgs>
<!--可直接使用, 这个是为了让系统支持系统托盘,因为默认是true-->
<vmArgs>-Djava.awt.headless=false</vmArgs>
<build>
<plugins>
<plugin>
....
</plugin>
<plugin>
<groupId>io.github.fvarrui</groupId>
<artifactId>javapackager</artifactId>
<version>1.7.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>package</goal>
</goals>
<configuration>
<!-- 程序入口 -->
<mainClass>cn.xxx.xxxApplication</mainClass>
<!-- 打包Jre -->
<bundleJre>true</bundleJre>
<!--系统最小托盘参数,此参数必须-->
<vmArgs>-Djava.awt.headless=false -Xmx1024m</vmArgs>
<!-- admin 权限检查-->
<administratorRequired>true</administratorRequired>
<platform>windows</platform>
<!-- 设置Jre路径 -->
<jrePath>C:\Program Files (x86)\Java\jre\jre</jrePath>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
4、系统最小化托盘后,创建桌面快捷方式后,点击快捷方式或.exe,发现会重复打开多个窗口。
解决方法:
private Stage primaryStage;
// 通信用
private static ServerSocket socket;
private static final int PORT = 9999;
private static final String REGISTRY_KEY = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
private static final String APP_NAME = "xxx程序";
/**
* 加载页面
*
* @param stage 页面根对象
* @throws IOException 加载异常
*/
@Override
public void start(Stage stage) throws IOException {
// 尝试绑定端口
if (!lockInstance()) {
// 使用socket发送信号显示窗口
sendShowWindowSignal();
// 阻止当前程序开启
System.exit(0);
}
primaryStage = stage;
try {
MinWindow.getInstance().listen(stage);
}catch (Exception e){
e.printStackTrace();
}
// 展示文件选择页面
fileSelectPageShow(stage);
// 启动一个线程进行监听
new Thread(this::startServer).start();
}
// 尝试绑定端口
private static boolean lockInstance() {
try {
socket = new ServerSocket(PORT); // 替换为你选择的端口
return true;
} catch (IOException e) {
return false;
}
}
// 使用socket发送信号显示窗口
private static void sendShowWindowSignal(){
try (Socket clientSocket = new Socket("localhost", PORT);
DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream()))
{
out.writeUTF("SHOW_WINDOW");
} catch (IOException e) {
e.printStackTrace();
}
}
// 启动监听程序
private void startServer() {
try {
while (true) {
try (Socket clientSocket = socket.accept();
DataInputStream in = new DataInputStream(clientSocket.getInputStream())) {
String command = in.readUTF();
if ("SHOW_WINDOW".equals(command)) {
Platform.runLater(this::showAndFocusStage);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 显示窗口并置顶程序
private void showAndFocusStage() {
if (primaryStage.isIconified()) {
primaryStage.setIconified(false);
}
if (!primaryStage.isShowing()) {
primaryStage.show();
}
primaryStage.toFront();
primaryStage.setAlwaysOnTop(true); // 临时置顶以确保窗口显示在前面
primaryStage.setAlwaysOnTop(false); // 取消置顶
}
// 当窗口真正退出关闭时,将socket关闭
private static void unlockInstance() {
try {
if (socket != null && !socket.isClosed()) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 启动窗口程序
private void fileSelectPageShow(Stage stage) throws IOException {
// 这个是窗口页面
FXMLLoader loa = new FXMLLoader(Objects.requireNonNull(getClass().getClassLoader().getResource("fxml/xxxxx.fxml")));
Parent root = loa.load();
// 给Controller赋值根节点
ConventionalMeteorologySettingController npc = loa.getController();
npc.setStage(stage);
stage.setTitle("xxx程序");
// 窗口关闭监听
stage.setOnCloseRequest(event -> unlockInstance());
stage.setScene(new Scene(root, 800.0, 600));
// 设置窗口样式,去掉最小化、最大化、关闭按钮
stage.initStyle(StageStyle.UNDECORATED);
// 添加拖动事件监听器
root.setOnMousePressed(event -> {
xOffset = event.getSceneX();
yOffset = event.getSceneY();
});
root.setOnMouseDragged(event -> {
stage.setX(event.getScreenX() - xOffset);
stage.setY(event.getScreenY() - yOffset);
});
stage.show();
// 这个是controller中的一个方法(当程序启动时去执行)
npc.initFilePath();
}
2、开机自启动
// 开机自启程序 -- 其实就是利用程序向注册表中注册,电脑开机后会检查注册表的
public static void setStartup(boolean enable) {
String exePath = new File(PathUtils.getExecutablePath(), "xxx程序.exe").getAbsolutePath();
String command = "\"" + exePath + "\"";
if (enable) {
Advapi32Util.registrySetStringValue(WinReg.HKEY_CURRENT_USER, REGISTRY_KEY, APP_NAME, command);
} else {
Advapi32Util.registryDeleteValue(WinReg.HKEY_CURRENT_USER, REGISTRY_KEY, APP_NAME);
}
}