2016-10-22 1 views
0

JavaFX를 처음 사용하고 ControlsFX Notification을 사용할 때 사소한 문제로 끊었습니다. 예를 들어 파일을 다운로드하는 등 더 오래 실행되는 작업 중에 다운로드가 시작되면 알림을 표시하고 끝내면 다시 알림을 표시하고 싶습니다. 그러나이 작업을 시도하면 작업이 완료된 후에 만 ​​알림이 모두 표시됩니다.Javafx controlsfx show()가 호출 될 때 알림이 즉시 표시되지 않습니다.

여기 Thread.sleep를 어떤 코드를 실행하기위한 지연을 시뮬레이션과 샘플입니다 :

Notifications.create() .title("Title Text") .text("Hello World 1!") .darkStyle() .show(); 
Thread.sleep(500); 
Notifications.create() .title("Title Text") .text("Hello World 2!") .darkStyle() .show(); 
Thread.sleep(500); 
Notifications.create() .title("Title Text") .text("Hello World 3!") .darkStyle() .show(); 
Thread.sleep(500); 

이 실행 모든 알림을 한 번에 아닌 0.5 초 간격을 보여줍니다.

However, they fade away a half second apart..

Here's an image of what the notifications look like in the lower right corner

는 그래서 그들은 500 밀리 초 간격 만들어지고있어하지만 바로 표시되지 않습니다. 바로 그들을 어떻게 보이게 할 수 있습니까?

답변

1

코드에서 UI 다시 그리기를 담당하는 JavaFX 응용 프로그램 스레드를 차단합니다. 이 방법으로 GUI의 모든 변경 사항은 표시되지 않으며 이벤트는 처리되지 않습니다.

Task을 사용하고 메시지를 표시하기 위해 message 속성에 수신기를 추가 할 수 있습니다. 이 속성에 대한 업데이트는 응용 프로그램 스레드에서 실행되도록 보장됩니다. 유일한 단점은 속성에 대한 빠른 업데이트를 위해 일부 알림을 건너 뛸 수 있다는 것입니다. 당신이 표시되는 모든 메시지가 필요하면


Task<Void> task = new Task<Void>() { 

    @Override 
    protected Void call() throws Exception { 
     // update message property 
     updateMessage("Hello World 1!"); 

     Thread.sleep(500); 
     updateMessage("Hello World 2!"); 
     Thread.sleep(500); 
     updateMessage("Hello World 3!"); 
     Thread.sleep(500); 
     return null; 
    } 

}; 

// display message changes as notifications 
task.messageProperty().addListener((observable, oldMessage, newMessage) -> 
     Notifications.create().title("Title Text").text(newMessage).darkStyle().show()); 

// execute long running task on background thread 
new Thread(task).start(); 

, 당신은 알림을 트리거 Platform.runLater를 사용해야합니다.

Thread thread = new Thread(new Runnable() { 

    private void postMessage(final String message) { 
     Platform.runLater(() -> Notifications.create().title("Title Text").text(message).darkStyle().show()); 
    } 

    @Override 
    public void run() { 
     try { 
      postMessage("Hello World 1!"); 
      Thread.sleep(500); 
      postMessage("Hello World 2!"); 
      Thread.sleep(500); 
      postMessage("Hello World 3!"); 
      Thread.sleep(500); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(NotificationsTestMain.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 

}); 

thread.start(); 

Platform.runLater을 너무 자주 사용하지 않도록주의하십시오. 많은 업데이트가있는 경우, 때때로 그룹화하는 것이 가장 좋습니다. 그러나이 경우 알림을 사용하지 않으려는 경우가 많습니다. 알림을 모두 표시하기 만하면됩니다. 여기에 업데이트 그룹화를 보여주는 코드가 있습니다.

private final List<String> messageQueue = new ArrayList<>(); 
private boolean updating; 
private final Runnable updater =() -> { 
    synchronized (messageQueue) { 
     for (String message : messageQueue) { 
      Notifications.create().title("Title Text").text(message).darkStyle().show(); 
     } 
     messageQueue.clear(); 
     updating = false; 
    } 
}; 

private void postMessage(String message) { 
    synchronized (messageQueue) { 
     messageQueue.add(message); 
     if (!updating) { 
      updating = true; 
      Platform.runLater(updater); 
     } 
    } 
} 
+0

타임 라인 사용 platform.runLater와 동일한 문제가 발생합니다. 세 가지 모두는 응용 프로그램 스레드가 수행중인 모든 작업을 마치면 만들어지고 표시됩니다. 내 질문에 Thread.sleep 사용하지만 실제 응용 프로그램을 일부 파일을 다운로드하고 다른 파일 처리를 않습니다. "다운로드 시작 중"을 알리고 "다운로드 완료"등을 알리고 싶습니다.결국 사용자에게 모든 알림을 한 번에 보여주는 것은 분명히 유익하지 않습니다. 저는 타임 라인에 익숙하지 않아서 제가 원하는 방식으로 행동 할 수 있는지보기 위해 조금만 놀아 볼 것입니다. – docb45

+0

@ docb45'타임 라인 (Timeline) '은 나쁜 생각이었습니다 (저는 어떻게 든 "지연을 시뮬레이션하는 스레드. 슬립 (Sleep.Sleep) 지연"부분에주의를 기울이지 않았습니다). 대답을 수정했습니다 ... – fabian

+0

놀라운 작품! 나는 Task와 함께 연주했지만 알림을 표시하기 위해 리스너를 추가하는 것에 대한 부분을 놓치고있었습니다. 이것은 완벽하게 작동합니다. – docb45

0

아무런 내용도 표시하지 않지만 코드가 JavaFX GUI 스레드를 차단하고 있다고 말하고 싶습니다. 위의 코드를 별도의 스레드에서 실행하고 각 알림 작성을 Platform.runLater 호출로 래핑해야합니다. 또는 AnimationTimer 또는 Timeline을 사용할 수도 있습니다. 그런 다음 별도의 스레드가 필요없고 Thread.sleep도 필요하지 않습니다.

+0

아, 예, 그렇습니다. Platform.runLater에 대해 완전히 잊었습니다. 나는 그것을 시도했지만 응용 프로그램 스레드가 완료된 후에 모든 알림이 생성된다는 문제가 발생했습니다. 위와 함께 그들은 ** 개별적으로 만들어지고 ** 동시에 ** 모든 ** ** 마지막에 ** 표시됩니다. 따라서 첫 번째 호출 (3 초 동안 표시되어야 함)은 세 번의 호출을 기다린 후 1.5 초 동안 만 나타나야합니다. platform.runLater를 사용하면 3 초 모두 나타나고 3 초 동안 머무를 수 있지만 응용 프로그램 스레드가 완료된 후에 만 ​​동시에 만들어집니다. – docb45

관련 문제