javaFx 系统最小化托盘(及其避坑)、开机自启动

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);
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值