よく考えたら新規作成にもいろんなパターンがありますね。
①新しいウィンドウが開く
②新しいタブが作成される
③作業中のファイルを閉じてからそのまま開く
個人的には①が好きなので、この方法で実装します。

新しいウィンドウが開く処理はダイアログの表示でも使えるはずなので、どちらにしても作れるようになっておきたい部分です。
結論から言うと、JavaFXで新しくウィンドウを作るのはかなり大変な作業でした。
これはStageクラスの使い方がある程度理解が必要なことと、[閉じる]ボタンを押したときに全ウィンドウ閉じられたり、別のウィンドウが閉じられたりするなど、色々予定外のバグがでました。主にスレッド関係が原因のようでした。
また、ネットの情報は断片的でテキストエディタを作るとなると自分で考えないと無理でした。
と言うことで、ここから先については僕のオリジナルな部分が多いので、設計の良し悪しは不明です。動作確認では一応、違和感なく動作しました。
【ProcessManagerクラス】このクラスのmainメソッドが初めに実行されます。残念なことにApplicationクラスのサブクラスである必要がありました。
public class ProcessManager extends Application {
@Override
public void start(Stage stage) throws Exception {
createTextEditer();
}
public static void main(String[] args) {
launch(args);
}
/**
* 新しいテキストエディタを作成します。
*/
public void createTextEditer() {
try {
new TextEditer01().start(new Stage());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 引数で指定されたウィンドウを非表示にします。
* @param scene 終了対象の画面
*/
public void terminateTextEditer(Scene scene) {
try {
scene.getWindow().hide();
} catch (Exception e) {
e.printStackTrace();
}
}
}
【TextEditer01クラス】ProcessManagerクラスから呼ばれます。普通はこのクラスのプロパティにSceneがありますが、イベントからSceneをうまく取得できなかったので、代替案としてSceneをFXMLDocumentControllerクラスに持っていき、FXMLに紐づいているコントローラの情報を保持しておきます。
public class TextEditer01 extends Application {
private FXMLDocumentController controller;
private ProcessManager pm = new ProcessManager();
@Override
public void start(Stage stage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
Parent root = fxmlLoader.load();
controller = (FXMLDocumentController) fxmlLoader.getController();
controller.setScene(new Scene(root));
stage.setScene(controller.getScene());
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
@Override
public void handle(WindowEvent event) {
event.consume();
try {
pm.terminateTextEditer(controller.getScene());
} catch (Exception e) {
e.printStackTrace();
}
}
});
stage.show();
}
}
【FXMLDocumentControllerクラス】Sceneをプロパティにするとイベントとうまく紐付けできました。
public class FXMLDocumentController implements Initializable {
private ProcessManager pm;
private Scene scene;
/**
* 新しいウィンドウを表示します。
* @param event
*/
@FXML
private void newAction(ActionEvent event) {
pm.createTextEditer();
}
/**
* MenuItem[閉じる] イベントが発生したウィンドウを非表示にします。
* @param event
*/
@FXML
void closeAction(ActionEvent event) {
pm.terminateTextEditer(getScene());
}
@Override
public void initialize(URL url, ResourceBundle rb) {
pm = new ProcessManager();
}
public Scene getScene() {
return scene;
}
public void setScene(Scene scene) {
this.scene = scene;
}
こんな感じで「新規作成」と「閉じる」が実装できました。
次は「開く」を追加します。