JavaFX 单实例应用程序

2024-02-03

尝试做到这一点,当用户“关闭”程序时单击所有退出按钮,这样就不再有托盘图标。

我调用 Platform.setImplicitExit(false);所以程序仍然在后台运行。

我正在尝试学习如何做到这一点,以便当用户重新单击运行 jar 的 .exe 文件时,它不会运行新程序,而是重新显示在后台运行的程序。

 Platform.setImplicitExit(false);

这是基于博客文章中的解决方案:Java单实例应用程序 https://nakkaya.com/2009/04/12/java-single-instance-application/.

该解决方案使用“套接字技术”:

通过这种技术,我们开始侦听端口,只有一个进程可以侦听套接字,因此在应用程序的第一个实例将自身绑定到套接字后,其他实例将得到 BindException,这意味着我们已经在运行。

这种方法的缺点是,当应用程序开始侦听套接字时,某些病毒扫描程序会发出警告,这可能会被错误地解释,具体取决于您的用户群。您应该选择一个不常用且较高的端口号,否则您甚至无法运行应用程序的单个实例。

在示例中,我们为应用程序实例创建了一个唯一的实例 ID 并记录了一些选项。

  • Minimize将最小化窗口。
  • Hide将隐藏它(因此它不会显示为最小化,但应用程序仍保持运行)。
  • Exit将结束申请流程。

窗口上的操作系统关闭按钮将关闭应用程序窗口,但应用程序进程将继续在后台运行(因此其作用与“隐藏”按钮相同)。

当您启动应用程序实例时,它将打开一个套接字并侦听它。

当您尝试启动另一个应用程序实例时,它将尝试绑定到侦听套接字。如果它无法绑定,那么它就知道该套接字上已经有一个应用程序实例正在运行。如果检测到另一个实例,则会通过套接字向现有实例发送一条消息,导致现有实例取消隐藏或取消最小化自身,并尝试将其阶段置于前面。

请不要滥用这个,有很多我不喜欢的程序隐藏在后台。

import javafx.application.*;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;

public class SingleInstanceApp extends Application {

    private static final int SINGLE_INSTANCE_LISTENER_PORT = 9999;
    private static final String SINGLE_INSTANCE_FOCUS_MESSAGE = "focus";

    private static final String instanceId = UUID.randomUUID().toString();

    // We define a pause before focusing on an existing instance
    // because sometimes the command line or window launching the instance
    // might take focus back after the second instance execution complete
    // so we introduce a slight delay before focusing on the original window
    // so that the original window can retain focus.
    private static final int FOCUS_REQUEST_PAUSE_MILLIS = 500;

    private Stage stage;

    public void init() {
        CountDownLatch instanceCheckLatch = new CountDownLatch(1);

        Thread instanceListener = new Thread(() -> {
            try (ServerSocket serverSocket = new ServerSocket(SINGLE_INSTANCE_LISTENER_PORT, 10)) {
                instanceCheckLatch.countDown();

                while (true) {
                    try (
                            Socket clientSocket = serverSocket.accept();
                            BufferedReader in = new BufferedReader(
                                    new InputStreamReader(clientSocket.getInputStream()))
                    ) {
                        String input = in.readLine();
                        System.out.println("Received single instance listener message: " + input);
                        if (input.startsWith(SINGLE_INSTANCE_FOCUS_MESSAGE) && stage != null) {
                            Thread.sleep(FOCUS_REQUEST_PAUSE_MILLIS);
                            Platform.runLater(() -> {
                                System.out.println("To front " + instanceId);
                                stage.setIconified(false);
                                stage.show();
                                stage.toFront();
                            });
                        }
                    } catch (IOException e) {
                        System.out.println("Single instance listener unable to process focus message from client");
                        e.printStackTrace();
                    }
                }
            } catch(java.net.BindException b) {
                System.out.println("SingleInstanceApp already running");

                try (
                        Socket clientSocket = new Socket(InetAddress.getLocalHost(), SINGLE_INSTANCE_LISTENER_PORT);
                        PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()))
                ) {
                    System.out.println("Requesting existing app to focus");
                    out.println(SINGLE_INSTANCE_FOCUS_MESSAGE + " requested by " + instanceId);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                System.out.println("Aborting execution for instance " + instanceId);
                Platform.exit();
            } catch(Exception e) {
                System.out.println(e.toString());
            } finally {
                instanceCheckLatch.countDown();
            }
        }, "instance-listener");
        instanceListener.setDaemon(true);
        instanceListener.start();

        try {
            instanceCheckLatch.await();
        } catch (InterruptedException e) {
            Thread.interrupted();
        }
    }

    public void stop() {
        System.out.println("Exiting instance " + instanceId);
    }

    @Override
    public void start(Stage stage) throws Exception{
        this.stage = stage;

        System.out.println("Starting instance " + instanceId);

        Platform.setImplicitExit(false);

        Button minimize = new Button("Minimize");
        minimize.setOnAction(event -> stage.setIconified(true));

        Button hide = new Button("Hide");
        hide.setOnAction(event -> stage.hide());

        Button exit = new Button("Exit");
        exit.setOnAction(event -> Platform.exit());

        Label instance = new Label(instanceId);

        Pane layout = new VBox(10, instance, new HBox(10, minimize, hide, exit));
        layout.setPadding(new Insets(10));

        Scene scene = new Scene(layout);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

相关问题

包含进一步的讨论,如果此答案中提供的解决方案的变体以及可能的替代方法:

  • 处理多个应用程序实例 https://stackoverflow.com/questions/71429246/dealing-with-multiple-application-instances/71431379#71431379
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaFX 单实例应用程序 的相关文章

  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • Java Swing:从 JOptionPane 获取文本值

    我想创建一个用于 POS 系统的新窗口 用户输入的是客户拥有的金额 并且窗口必须显示兑换金额 我是新来的JOptionPane功能 我一直在使用JAVAFX并且它是不同的 这是我的代码 public static void main Str
  • Play框架运行应用程序问题

    每当我尝试运行使用以下命令创建的新 Web 应用程序时 我都会收到以下错误Play http www playframework org Error occurred during initialization of VM Could no
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • JAXb、Hibernate 和 beans

    目前我正在开发一个使用 Spring Web 服务 hibernate 和 JAXb 的项目 1 我已经使用IDE hibernate代码生成 生成了hibernate bean 2 另外 我已经使用maven编译器生成了jaxb bean
  • 列出jshell中所有活动的方法

    是否有任何命令可以打印当前 jshell 会话中所有新创建的方法 类似的东西 list但仅适用于方法 您正在寻找命令 methods all 它会打印所有方法 包括启动 JShell 时添加的方法 以及失败 被覆盖或删除的方法 对于您声明的
  • 反射找不到对象子类型

    我试图通过使用反射来获取包中的所有类 当我使用具体类的代码 本例中为 A 时 它可以工作并打印子类信息 B 扩展 A 因此它打印 B 信息 但是当我将它与对象类一起使用时 它不起作用 我该如何修复它 这段代码的工作原理 Reflection
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • 斯坦福 NLP - 处理文件列表时 OpenIE 内存不足

    我正在尝试使用斯坦福 CoreNLP 中的 OpenIE 工具从多个文件中提取信息 当多个文件 而不是一个 传递到输入时 它会给出内存不足错误 All files have been queued awaiting termination
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • Java按日期升序对列表对象进行排序[重复]

    这个问题在这里已经有答案了 我想按一个参数对对象列表进行排序 其日期格式为 YYYY MM DD HH mm 按升序排列 我找不到正确的解决方案 在 python 中使用 lambda 很容易对其进行排序 但在 Java 中我遇到了问题 f
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 如何在桌面浏览器上使用 webdriver 移动网络

    我正在使用 selenium webdriver 进行 AUT 被测应用程序 的功能测试自动化 AUT 是响应式网络 我几乎完成了桌面浏览器的不同测试用例 现在 相同的测试用例也适用于移动浏览器 因为可以从移动浏览器访问 AUT 由于它是响
  • 在 Maven 依赖项中指定 jar 和 test-jar 类型

    我有一个名为 commons 的项目 其中包含运行时和测试的常见内容 在主项目中 我添加了公共资源的依赖项
  • JGit 检查分支是否已签出

    我正在使用 JGit 开发一个项目 我设法删除了一个分支 但我还想检查该分支是否已签出 我发现了一个变量CheckoutCommand但它是私有的 private boolean isCheckoutIndex return startCo
  • Spring Boot @ConfigurationProperties 不从环境中检索属性

    我正在使用 Spring Boot 1 2 1 并尝试创建一个 ConfigurationProperties带有验证的bean 如下所示 package com sampleapp import java net URL import j
  • 使用 xpath 和 vtd-xml 以字符串形式获取元素的子节点和文本

    这是我的 XML 的一部分

随机推荐

  • Windows 上的 Mongodb 性能

    我最近一直在研究可用于 NET 的 nosql 选项 并且 MongoDB 在可用性和支持方面明显成为赢家 所以今晚我决定尝试一下 我从 mongodb 站点下载了版本 1 2 4 Windows x64 二进制 并使用以下选项运行它 C
  • 将对象序列化为 JSON、XML、YAML?

    我之前问过有关序列化和验证的问题 有人提到使用 JSON gem 它允许我告诉我的对象如何使用to json方法 然而 Ruby 似乎很容易做很多复杂的事情 但另一方面 一些非常简单的事情似乎相当复杂 序列化就是其中之一 我想知道是否有办法
  • Java 1.3.1,编译器错误

    我正在使用一台新的工作计算机 上面有一个旧的 sdk Java 1 3 1 并且想看看我是否可以在它上做一些课堂作业 我从我们的教授那里得到了这个文件 它可以在课堂上的他的机器上运行 当我运行它时 我收到编译器错误 我在线检查了 Java
  • Pandas:当DataFrame描述返回的计数是浮点数时有哪些情况

    在描述我的 Pandas 数据框时 我得到以下结果 Mains 1 Power Mains 2 Power count 17 000000 17 000000 mean 57 063528 200 428607 std 67 605151
  • 错误:DateTime 类的对象无法转换为字符串

    我在显示值时遇到错误 thedate row2 date echo thedate 在 php 中 数据库 thedate 中的值是 2015 05 05 21 52 31 000 如何格式化它以便能够将其作为字符串显示在 php 页面上
  • ORA-00910: 指定的长度对于其数据类型来说太长

    我在Oracle中有一个列来存储评论Nvarchar2 2000 当用户尝试输入超过 2000 个字符时 我收到以下错误 ORA 00910 specified length too long for its datatype The NL
  • FileSystemWatcher 不适用于从 Windows 服务创建的文件

    我正在从本地系统帐户下运行的 Windows 服务创建文件 我有一个 Windows 应用程序 用于监视创建文件的指定文件夹 我正在使用 FileSystemWatcher 但它不会触发 Windows 资源管理器中的文件图标是一个挂锁图标
  • 尝试将多个外键添加到单个表时出错

    我正在尝试创建一个子表来约束来自父级的 3 个外键 但收到错误1215 无法添加外键约束 父表 CREATE TABLE Availability time of day varchar 20 NOT NULL day of week va
  • 如何在 Swift 中从 CGWindowID 获取窗口引用(CGWindow、NSWindow 或 WindowRef)?

    如何在 XCode 7 3 Mac Playground 上的 Swift 中从 CGWindowID 获取窗口引用 CGWindow NSWindow 或 WindowRef 我引用了Apple的文档 窗口管理器参考 http n eth
  • 提取信息。从 XML 到 Cocoa

    我正在尝试解析 XML 以提取某些变量的值 这是一个例子
  • 如果更新值为空,则不更新列

    我有一个这样的查询 在函数中 UPDATE some table SET column 1 param 1 column 2 param 2 column 3 param 3 column 4 param 4 column 5 param
  • 如何在 Ruby 中限制 Markdown 语法?

    我希望使用 Ruby 库在 Rails CMS 评论系统中实现 Markdown 例如Maraku http maruku rubyforge org or Kramdown http kramdown rubyforge org 我需要限
  • 多种 OpenSSL RSA 签名方法会产生不同的结果

    尝试着全神贯注于签名并使用 测试各种选项 我可以使用以下命令进行签名 openssl dgst sha256 sign private key pem binary out sig file data file 但文档好像说我也可以使用这个
  • 如何在wxpython中的StaticBitmap上创建悬停效果?

    我想在 StaticBitmap 上创建悬停效果 如果鼠标光标位于位图上 则显示一张图像 如果没有 则显示第二张图像 这是一个简单的程序 与按钮完美配合 但是 StaticBitmap 不会发出 EVT WINDOW ENTER EVT W
  • 在 HTML 5 视频之上叠加 DIV

    我需要在包含 HTML 5 视频的 div 顶部覆盖一个 div 在下面的示例中 覆盖 div 的 id 是 video overlays 请参阅下面的示例 div div div div div div
  • 哪个更好 - 使用 String 或 File 作为采用文件名的方法的参数类型[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 执行多个请求 Axios (Vue.js)

    我正在尝试执行两个非并发请求 但想在执行第二个请求之前使用第一个请求中的数据 如何实现从第一个请求获取数据 然后将该数据用于第二个请求 axios get user 12345 then response gt this arrayOne
  • 比较日期?

    我正在尝试比较 Android 中的两个日期 但我得到了这个 当我写这个的时候 SimpleDateFormat sdf new SimpleDateFormat ddMMyyyy String valid until 26052018 f
  • 我在这个 ASPxPageControl 中做错了什么? (开发快报)

    这是我所拥有的 我正在尝试使用 Developer Express ASPxPageControl 我只想在加载页面时加载第一个 TabPage 及其包含的 WebUserControl 然后当我单击后续选项卡时加载这些 WebUserCo
  • JavaFX 单实例应用程序

    尝试做到这一点 当用户 关闭 程序时单击所有退出按钮 这样就不再有托盘图标 我调用 Platform setImplicitExit false 所以程序仍然在后台运行 我正在尝试学习如何做到这一点 以便当用户重新单击运行 jar 的 ex