2016-12-09 7 views
3

사용자가 모든 종료 버튼을 클릭하여 프로그램을 "닫아"더 이상 트레이 아이콘이 없도록 만들려고합니다.JavaFX 단일 인스턴스 응용 프로그램

나는 Platform.setImplicitExit (false)를 호출했습니다. 그래서 프로그램은 여전히 ​​backround에서 실행됩니다.

사용자가 jar을 실행하는 .exe 파일을 다시 클릭 할 때 새 프로그램을 실행하는 대신 백그라운드에서 실행중인 .exe 파일을 다시 표시하는 방법을 배우려고합니다.

Platform.setImplicitExit(false); 
+0

jsmooth를 사용하여 .exe를 만들었습니다. –

답변

5

블로그 게시물의 해결책 : Java Single Instance Application을 기반으로합니다.

이 솔루션은 "소켓 기술"을 사용 : 우리의 응용 프로그램의 첫 번째 인스턴스가 다른 소켓에 자신을 결합 후, 그래서 우리가 포트에서 수신 대기 시작이 기술을

을 하나의 프로세스 만 소켓에들을 수 있습니다 인스턴스가 BindException을 얻습니다. 이는 우리가 이미 실행 중임을 의미합니다.

이 접근 방식의 단점은 응용 프로그램이 소켓에서 청취하기 시작할 때 경고 메시지를 표시하는 것입니다. 이는 사용자 기반에 따라 잘못 해석 될 수 있습니다. 일반적으로 많이 사용되지 않는 포트 번호를 선택하거나 응용 프로그램의 단일 인스턴스를 실행하지 않아도됩니다.

샘플에서는 응용 프로그램 인스턴스에 대한 고유 한 인스턴스 ID를 작성하고 몇 가지 옵션을 기록했습니다.

  • unique

    창을 최소화 할 수
    최소화 할 수 있습니다.
  • 숨기기은 앱을 숨 깁니다 (최소화 된 상태로 표시되지 않지만 앱은 계속 실행 됨).
  • 출구은 신청 프로세스를 종료합니다.

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; 

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