JavaFX单实例应用程序 [英] JavaFX Single Instance Application

查看:182
本文介绍了JavaFX单实例应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当用户关闭程序时单击所有退出按钮,以便不再有托盘图标时,尝试这样做。



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



我正在尝试学习如何在用户重新点击运行jar的.exe文件时,而不是运行一个新的程序,它重新显示那个在后台运行的人。

  Platform.setImplicitExit(false); 


解决方案

这是基于博客文章中的解决方案:




  • 最小化将最小化窗口。

  • 隐藏将隐藏它(因此它不显示为最小化,但应用程序仍在运行)。

  • 退出将结束申请流程。



窗口上的OS关闭按钮将关闭应用程序窗口,但应用程序进程将继续在后台运行(因此它会起作用)与隐藏按钮相同。



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



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



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

  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;

公共类SingleInstanceApp扩展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();

//我们在关注现有实例
//之前定义一个暂停因为有时启动实例
//的命令行或窗口可能会在第二个实例之后重新关注执行完成
//所以我们在关注原始窗口
//之前引入一点延迟,以便原始窗口可以保持焦点。
private static final int FOCUS_REQUEST_PAUSE_MILLIS = 500;

私人舞台舞台;

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

线程instanceListener = new线程(() - > {
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(单实例监听器无法处理来自客户端的焦点消息);
e.printStackTrace();
}
}
} catch(java.net.BindException b){
System.out.println(SingleInstanceApp已经运行);

try(
Socket clientSocket = new Socket(InetAddress.getLocalHost(),SINGLE_INSTANCE_LISTENER_PORT);
PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()))
){
System.out.println(请求现有应用程序关注);
out.println(SINGLE_INSTANCE_FOCUS_MESSAGE +由+ instanceId请求);
} catch(IOException e){
e.printStackTrace();
}

System.out.println(例如中止执行+ instanceId);
Platform.exit();
} catch(例外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(退出实例+ instanceId);
}

@Override
public void start(阶段阶段)抛出异常{
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());

按钮退出=新按钮(退出);
exit.setOnAction(event - > Platform.exit());

Label instance = new Label(instanceId);

窗格布局=新VBox(10,实例,新HBox(10,最小化,隐藏,退出));
layout.setPadding(new Insets(10));

场景场景=新场景(布局);
stage.setScene(场景);
stage.show();
}

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


Trying to make it so when the user "closes" the program clicking all the exit buttons so there is no more tray icon.

I called Platform.setImplicitExit(false); so the program still runs in backround.

I am trying to learn how to make it so when the user re-clicks the .exe files which runs the jar,instead of running a new program it re-shows that one that is running in background.

 Platform.setImplicitExit(false);

解决方案

This is based upon the solution in the blog post: Java Single Instance Application.

The solution uses the "Socket Technique":

With this technique we start listening on a port, only one process can listen on a socket so after first instance of our application binds itself to the socket other instances will get BindException, which means we are already running.

Cons of this approach is that some virus scanners will give a warning when an application starts listening on a socket, depending on your user base this could be interpreted badly. You should pick a port number thats not commonly used and high or you won't even get a single instance of your application running.

In the sample, we have created a unique instance id for the application instance and recorded some options.

  • Minimize will minimize the window.
  • Hide will hide it (so it doesn't show as minimized, but the app remains running).
  • Exit will end the application process.

The OS close button on the window will close the application window, but the application process will continue running in the background (so it acts the same as the "Hide" button).

When you start an application instance, it will open a socket and listen on it.

When you try to start another application instance it will try to bind to the listening socket. If it cannot bind, then it knows there is already an application instance running on that socket. If another instance is detected, a message is sent across the socket to the existing instance causing the existing instance to unhide or un-minimize itself and try to bring its stage to the front.

Please don't abuse this, there are many programs that hide in the background that I don't like.

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

这篇关于JavaFX单实例应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆