2017-11-10 7 views
0

클라이언트 응용 프로그램에 gui를 추가했습니다 ( ). 소켓 메시지를 전달하려고합니다. 지금까지 클라이언트를 싱글 톤으로 조롱 했으므로 Application 스레드 에서 액세스 할 수 있었지만 지금은 여러 클라이언트가 GUI에 액세스하려고합니다. fxml은 속성 리스너를 바인딩하지만 은 가능한 한 간단하게 원합니다. 스레드 자체에서 직접 작업하십시오. Application.launch()이 자체적으로 생성하는 경우 Platform.runLater()은 장면 인스턴스를 참조 할 수 있습니까? 저는 꽤 광범위하게 읽었지만 솔루션은 어디서나 fxml 인터페이스를 활용하여 내가 좋아하지 않을 작업을 건너 뛰었습니다. Control 클래스 (간체, 9 호선에 문제) :다른 스레드에서 JavaFX 응용 프로그램 장면을 수정 하시겠습니까?

public class Client { 
    private Socket socket = new Socket("127.0.0.1",4444); 
    private BufferedReader incoming = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
    private Browser browser = new Browser(); 
    public static void main(String[] arguments) throws IOException { 
     Application.launch(browser.class); 
     while(socket.isConnected()) { 
      Platform.runLater(new Runnable(){ 
       @Override public void run(){ 
        try{browser.bubble(incoming.readLine());} 
        catch(IOException fail){fail.printStackTrace();} 
       } 
      }); 
     } 
    } 
} 

사용자 인터페이스 (간체) : 당신은 오직 생성 된 인스턴스가 당신의 Application 서브 클래스의 인스턴스가 있어야

public class Browser extends Application { 
    private Stage stage; 
    private Scene scene; 
    private BorderPane layout = new BorderPane(); 
    private VBox history = new VBox(); 
    @Override public void start(Stage stage) throws Exception { 
     layout.setCenter(history); 
     scene = new Scene(layout); 
     stage = stage; 
     stage.setScene(scene); 
     stage.show(); 
    } 
    public void bubble(String message){ 
     VBox record = new VBox(); 
     Label label = new Label(message); 
     record.getChildren().add(label); 
     history.getChildren().add(record); 
    } 
} 
+1

대다수의 경우 main 메소드를 제외한 다른 곳에서'Application.launch()'를 호출하면 안되며 main 메소드에서 다른 것을하지 말아야한다. 다른 방법으로이 작업을 수행하십시오. 나는. 'start()'메소드에서'Client' 인스턴스를 생성하고 거기에서 게시 한 코드가 들어있는 메소드를 백그라운드 스레드에서 호출하십시오. 당신은 여전히 ​​스레딩 문제가 있습니다 - 당신은'readLine()'호출로 fx 응용 프로그램 스레드를 차단하고 있습니다. –

+0

죄송합니다. psvm 메서드가 포함되지 않았습니다. 수정되었습니다. 나는 당신이 그린 원리, 메인 메소드에서 다른 것을 응용 프로그램에서 인스턴스화하는 것을 좋아한다. 그 인스턴스를 세 번째 쓰레드로 파견하는 것은 블로킹 문제를 해결할 수있을뿐만 아니라 그것을 막을 수있다. 나는 아마도 이렇게 할 것이다. – bpstrngr

답변

2

응용 프로그램은 Application.launch()을 통해 시작됩니다. JavaFX 응용 프로그램의 main() 메서드는 실제로 Application.launch()을 호출하고 다른 작업은 수행하지 않아야합니다. 실행 프로세스의 일부로 호출되는 start() (또는 init()) 메소드를 응용 프로그램의 진입 점으로 간주해야합니다.

따라서 start() 메서드에서 Client 인스턴스를 만들고이를 백그라운드 스레드에서 수행하는 작업을 수행하도록 설정해야합니다.

다음과 같이 코드를 리팩토링으로이 모든 것을 달성 할 수

:

public class Browser extends Application { 
    private Stage stage; 
    private Scene scene; 
    private BorderPane layout = new BorderPane(); 
    private VBox history = new VBox(); 
    @Override public void start(Stage stage) throws Exception { 
     layout.setCenter(history); 
     scene = new Scene(layout); 
     stage = stage; 
     stage.setScene(scene); 
     stage.show(); 

     Client client = new Client(this); 
     Thread thread = new Thread(client::processIncomingData); 
     thread.setDaemon(true); 
     thread.start(); 
    } 
    public void bubble(String message){ 
     VBox record = new VBox(); 
     Label label = new Label(message); 
     record.getChildren().add(label); 
     history.getChildren().add(record); 
    } 
    public static void main(String[] args) { 
     Application.launch(args); 
    } 
} 

public class Client { 
    private Socket socket = new Socket("127.0.0.1",4444); 
    private BufferedReader incoming = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
    private Browser browser ; 

    public Client(Browser browser) { 
     this.browser = browser ; 
    } 

    public void processIncomingData() { 
     while(socket.isConnected()) { 
      try { 
       String data = incoming.readLine(); 
       Platform.runLater(() -> browser.bubble(data)); 
      } catch (IOException exc) { 
       // TODO: handle properly 
       exc.printStackTrace(); 
      } 
     } 
    } 
} 

다른 몇 가지주의 할 : 응용 프로그램이 종료 될 때까지 Application.launch() 블록; 그래서 원래의 코드에서 응용 프로그램이 종료 될 때까지 while 루프가 시작되지 않습니다. 또한 readLine() 메서드는 차단되므로 FX 응용 프로그램 스레드에서이 작업을 수행하지 않으려합니다 (UI가 선을 읽을 때까지 어떤 식 으로든 응답하지 않게됩니다). 후자 문제는 Platform.runLater() 블록에서 readLine()을 이동하여 해결됩니다.

+0

좋아, 그래서 논리를 반전하고 응용 프로그램 스레드에서 인스턴스. 충분 해. 루프 이전에'Application.launch()'를 삽입하는 것은 나의 단축에서 실수 였지만 언급 할 만하다. 고마워, 제임스. – bpstrngr