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 单实例应用程序 的相关文章

  • TreeMap 删除所有大于某个键的键

    在项目中 我需要删除键值大于某个键的所有对象 键类型为Date 如果重要的话 据我所知TreeMapJava中实现的是红黑树 它是一种二叉搜索树 所以我应该得到O n 删除子树时 但除了制作尾部视图并一一删除之外 我找不到任何方法可以做到这
  • 如何在java中将数组值排序为循环格式?

    我的数组值如下 String value 1 2 3 4 5 6 7 8 9 10 假设如果我将值 5 传递给 tat 数组 它应该按如下顺序排序 5 6 7 8 9 10 1 2 3 4 怎么办 有人帮忙吗 感谢你 你需要的就是所谓的轮换
  • Java 的支持向量机?

    我想用Java编写一个 智能监视器 它可以随时发出警报detects即将到来的性能问题 我的 Java 应用程序正在以结构化格式将数据写入日志文件
  • Thymeleaf 3 Spring 5 映射加载字符串而不是 HTML

    我正在尝试将 Spring 5 和 Thymeleaf 3 一起配置 我正在 Eclipse 上工作 我使用 全新安装 构建并使用 springboot run 运行应用程序 我已经设置了一个控制器和几个模板 但 Thymeleaf 似乎找
  • 什么是抽象类? [复制]

    这个问题在这里已经有答案了 当我了解抽象类时 我说 WT H 问题 创建一个无法实例化的类有什么意义呢 为什么有人想要这样的课程 什么情况下需要抽象类 如果你明白我的意思 最常见的是用作基类或接口 某些语言有单独的interface构建 有
  • 在 Java 中如何找出哪个对象打开了文件?

    我需要找出答案哪个对象在我的 Java 应用程序中打开了一个文件 这是为了调试 因此欢迎使用工具或实用程序 如果发现哪个对象太具体了 这class也会很有帮助 这可能很棘手 您可以从使用分析器开始 例如VisualVM http visua
  • Java 中如何将 char 转换为 int? [复制]

    这个问题在这里已经有答案了 我是Java编程新手 我有例如 char x 9 我需要得到撇号中的数字 即数字 9 本身 我尝试执行以下操作 char x 9 int y int x 但没有成功 那么我应该怎么做才能得到撇号中的数字呢 ASC
  • Sun 在 EDT 之外做 GUI 工作的演示?

    我正在看SplashDemo java http download oracle com javase tutorial uiswing examples misc SplashDemoProject src misc SplashDemo
  • 如何在字段值无效的情况下更改 Struts2 验证错误消息?

    我在 Web 表单上使用 Struts2 验证 如果字段假设为整数或日期 则
  • 如何仅从 Firestore 获取最新更新的数据?

    在 Firestore 上发现任何更改时始终获取整个文档 如何只获取最近更新的数据 这是我的数据 我需要在第一次加载时在聊天中按对象顺序 例如 2018 09 17 30 40 msg和sendby 并且如果数据更新则仅获取新的msg和se
  • Akka 与现有 java 项目集成的示例

    如果我已经有现有的javaWeb 应用程序使用spring and servlet容器 将 Akka 集成到其中的正确方法是什么 就像我将会有Actor1 and Actor2互相沟通的 开始使用这些演员的切入点是什么 例如 1 把它放在那
  • 如何使用 JMagick 转换色彩空间?

    如何使用 JMagick API 转换色彩空间 例如 CMYK gt RGB 和 RGB gt CMYK None
  • 如何在.NET中使用java.util.zip.Deflater解压缩放气流?

    之后我有一个转储java util zip Deflater 可以确认它是有效的 因为 Java 的Inflater打开它很好 并且需要在 NET中打开它 byte content ReadSample sampleName var inp
  • 提高 PostgreSQL 1 亿数据左连接查询性能

    我在用Postgresql 9 2 version Windows 7 64 bit RAM 6GB 这是一个Java企业项目 我必须在我的页面中显示订单相关信息 有三个表通过左连接连接在一起 Tables TV HD 389772 行 T
  • 为什么\0在java中不同系统中打印不同的输出

    下面的代码在不同的系统中打印不同的输出 String s hello vsrd replace 0 System out println s 当我在我的系统中尝试时 Linux Ubuntu Netbeans 7 1 它打印 When I
  • 使用 HtmlUnit 定位弹出窗口

    我正在构建一个登录网站并抓取一些数据的程序 登录表单是一个弹出窗口 所以我需要访问这个www betexplorer com网站 在页面的右上角有一个登录链接 写着 登录 我单击该链接 然后出现登录弹出表单 我能够找到顶部的登录链接 但找不
  • 手动设置Android Studio的JDK路径

    如何为 Android Studio 使用自定义 JDK 路径 我不想弄乱 PATH 因为我没有管理员权限 是否有某个配置设置文件允许我进行设置 如果您查看项目设置 您可以从那里访问 jdk 在标准 Windows 键盘映射上 您可以在项目
  • java XMLSerializer 避免复杂的空元素

    我有这个代码 DocumentBuilderFactory factory DocumentBuilderFactory newInstance DocumentBuilder builder factory newDocumentBuil
  • Android View Canvas onDraw 未执行

    我目前正在开发一个自定义视图 它在画布上绘制一些图块 这些图块是从多个文件加载的 并将在需要时加载 它们将由 AsyncTask 加载 如果它们已经加载 它们只会被绘制在画布上 这工作正常 如果加载了这些图片 AsyncTask 就会触发v
  • Spring RESTful控制器方法改进建议

    我是 Spring REST 和 Hibernate 的新手 也就是说 我尝试组合一个企业级控制器方法 我计划将其用作未来开发的模式 您认为可以通过哪些方法来改进 我确信有很多 RequestMapping value user metho

随机推荐

  • 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