코드가 Application
에 대한 API 설명서에 완전히 설명되어있는 JavaFX 응용 프로그램 수명주기에 맞지 않기 때문에 코드가 제대로 작동하지 않습니다. 간단히 말해서 Application
클래스는 전체 응용 프로그램 (또는 응용 프로그램의 수명주기)을 나타냅니다.
JavaFX에서 창을 표시하려면 FX 응용 프로그램 스레드에서 수행해야하며 FX 도구 키트를 시작해야이 스레드를 시작할 수 있습니다. Application.launch()
메서드는 FX 도구 키트를 시작하고 FX 응용 프로그램 스레드를 시작하고 응용 프로그램 클래스의 인스턴스를 만들고 해당 인스턴스에서 init()
을 호출 한 다음 해당 인스턴스에서 start()
을 호출합니다 (start()
에 대한 호출은 FX 응용 프로그램 스레드에서 발생 함).
documented으로, Application.launch()
은 FX 툴킷이 종료 될 때까지 (즉, 응용 프로그램이 종료 될 때까지) 차단 (반환되지 않음)하므로 한 번만 호출해야합니다. (전체 응용 프로그램을 나타내므로 의미가 있으며 두 번 호출하는 방법을 사용할 수 없습니다.)
응용 프로그램 구조가 실제로 사용자 관점에서도 이해가되지 않습니다. GUI 기반 응용 프로그램에 옵션을 표시하기 위해 사용자에게 명령 행을 사용하도록 요청하는 이유는 무엇입니까? 이러한 옵션을 GUI에 표시해야합니다. 시작할 때 옵션이있는 창을 표시 한 다음 선택한 옵션에 해당하는 창을 표시하십시오. 선택한 옵션이 완료되기 전에 사용자가 원래 창으로 돌아갈 수 없도록하려면 새 창을 모달로 만드십시오. 예를 들어
, 당신은 (이 응용 프로그램의 출발점이되지 않기 때문에 당신이해야) 그래서이 Application
서브 클래스가 아닌 MyJavaFXProgram
를 리팩토링하는 경우 :
다음
import javafx.scene.Parent;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
public class MyJavaFXProgram {
private StackPane view ;
public MyJavaFXProgram() {
Text oText = new Text("My JavaFXProgram");
view = new StackPane();
view.getChildren().add(oText);
}
public Parent getView() {
return view ;
}
}
당신이 할 수있는
import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MyJavaProgram extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
Button showMeSomethingButton = new Button("Show me something");
showMeSomethingButton.setOnAction(e -> {
MyJavaFXProgram myProgram = new MyJavaFXProgram();
showInModalWindow(myProgram.getView());
});
Button exitButton = new Button("Exit");
exitButton.setOnAction(e -> Platform.exit());
VBox root = new VBox(10, exitButton, showMeSomethingButton);
root.setPadding(new Insets(20));
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
private void showInModalWindow(Parent view) {
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setScene(new Scene(view));
stage.show();
}
}
명령 줄에서이 모든 것을 운전하고 싶다면 (솔직히 정당한 이유가 있음을 알 수 없다면) 까다로워지고 스레드 간 상호 작용을 관리해야 할 필요가 있습니다 어떤 시점에서.아마도 가장 간단한 접근법은 응용 프로그램이 시작될 때 FX 도구 키트가 시작되었는지 확인한 다음 코드에서와 같이 더 많이 또는 덜 진행하지만 MyJavaFXProgram
이 다시 리팩터링되어 Application
의 하위 클래스가 아니어야합니다. JFXPanel
을 생성하여 FX 툴킷을 시작하기위한 해킹이 있습니다. 그러나 실제로는 해킹이 약간 있습니다. Application
클래스를 사용하여 실제로 수행하지 않는 클래스 인 launch()
을 기다리고 기다리고 있습니다. 초기화가 완료되었습니다. this question에 대한 답변에서이 작업을 수행하는 방법을 보여 주었으므로 여기에서 해당 솔루션을 빌려 올 것입니다. 여기에 FX 툴킷을 시작하는 데 사용되는 Application
클래스 (그러나 당신이 실행 메인 클래스가되지 않음)입니다 :
import java.util.concurrent.CountDownLatch;
import javafx.application.Application;
import javafx.stage.Stage;
public class FXStarter extends Application {
private static final CountDownLatch latch = new CountDownLatch(1);
public static void awaitFXToolkit() throws InterruptedException {
latch.await();
}
@Override
public void init() {
latch.countDown();
}
@Override
public void start(Stage primaryStage) {
// no-op
}
}
아이디어는 Application.launch(FXStarter.class)
를 호출하는 것입니다,하지만 launch()
차단하기 때문에, 당신이에해야 배경 스레드. 즉, launch()
이 실제로 작업을 완료하기 전에 계속되는 코드가 실행될 수 있음을 의미하므로 작업이 완료 될 때까지 기다려야합니다.이 작업은 FXStarter.awaitFXToolkit()
과 함께 할 수 있습니다. 그런 다음 루프를 실행할 수 있습니다. 걱정할 가장 중요한 점은 FX 응용 프로그램 스레드에 새 창을 만들고 표시하는지 확인하는 것입니다.
이
import java.util.Scanner;
import java.util.concurrent.FutureTask;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MyJavaProgram {
public static void main(String[] args) throws Exception {
// start FX toolkit on background thread:
new Thread(() -> Application.launch(FXStarter.class)).start();
// wait for toolkit to start:
FXStarter.awaitFXToolkit();
// make sure closing first window does not exit FX toolkit:
Platform.setImplicitExit(false);
int input;
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("0 - exit");
System.out.println("1 - display something to me");
input = scanner.nextInt();
switch (input) {
case 0:
break;
case 1:
// task to show UI:
FutureTask<Void> showProgramTask = new FutureTask<>(() -> {
MyJavaFXProgram program = new MyJavaFXProgram();
Stage stage = new Stage();
stage.setScene(new Scene(program.getView(), 400, 400));
stage.setOnShown(e -> {
stage.toFront();
stage.requestFocus();
});
// showAndWait will block execution until window is hidden:
stage.showAndWait();
return null ;
});
// show UI on FX Application Thread:
Platform.runLater(showProgramTask);
// block until task completes (i.e. window is hidden):
showProgramTask.get() ;
break;
}
if (input == 0) break;
}
// all done, exit FX toolkit:
Platform.exit();
scanner.close();
}
}
(이것은 위의 MyJavaFXProgram
의 동일한 버전을 사용합니다.)
당신이'showAndWait()'을 찾고있는이 방법이 아닙니다 : 같은 당신의
MyJavaProgram
지금 보이는? –아직 처리하지 않았습니까? ['Application.launch()'] (http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#launch-java.lang.Class-java.lang.String. ..-)는 JavaFX 응용 프로그램이 종료 될 때까지 반환되지 않습니다. 또한 일반적으로이 방법은'launch() '를 두 번 이상 호출 할 수 없으므로 작동하지 않습니다. –
어쨌든 GUI 응용 프로그램을 명령 줄에서 구동하려는 이유는 무엇입니까? 이 작업을 수행하는 것은 매우 까다로운 작업입니다. 스레딩 등으로 손을 더러워해야합니다. 간단한 창에서 "나에게 뭔가를 보여줄 수있는"옵션을 표시하지 않는 것이 어떻습니까? –