所以我试图从Swing迁移到JavaFX,我只是在不知道它们是如何工作的情况下声明start()
和launch()
方法。但是下面的代码会向控制台输出false和false。但是,当我单击使用Scene Builder
构建的GUI中的按钮执行myMethod()
时,这次打印为true。为什么说primaryStage
没有实例化?
添加信息:
我也把这个类作为我的控制器,出于同样的原因 - 它需要访问舞台参考。如果重要的话,Main的完整版本(我没有发布)会实现Initializable
。
作为奖励问题我想知道我是否需要primaryStage
的字段来引用应用程序阶段,其中只有一个?,在myMethod()
中。
public class Main extends Application {
private Stage primaryStage;
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
try {
Scene scene = new Scene(FXMLLoader.load(getClass().getResource("Sample.fxml")),600,400);
primaryStage.setScene(scene);
} catch(Exception e) {
e.printStackTrace();
}
primaryStage.show();
//both lines below print false; As they should.
System.out.println(this.primaryStage == null);
myMethod();
}
public static void main(String[] args) {
launch(args);
}
public void myMethod() {
System.out.println(primaryStage == null);
}
}
修改
将此FXML文档放在与上一个类相同的文件夹中将允许您运行Main以查看该按钮确实打印为true。
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Main">
<children>
<Button mnemonicParsing="false" onAction="#myMethod" text="Button" />
</children>
</HBox>
答案 0 :(得分:1)
这是因为FXMLLoader
将创建application.Main
类的新实例,其中start()
方法未被调用,因此private Stage primaryStage
为空。
最好将FXML的主类和控制器分开,如果有必要,稍后通过初级阶段:
...
try
{
FXMLLoader loader = new FXMLLoader( getClass().getResource( "Sample.fxml" ) );
Scene scene = new Scene( loader.load(), 600, 400 );
( (MyController) loader.getController() ).setPrimaryStage(primaryStage);
primaryStage.setScene( scene );
}
catch ( Exception e )
{
e.printStackTrace();
}
...
MyController
类可以如下所示:
public class MyController {
private Stage primaryStage;
public void setPrimaryStage(Stage primaryStage) {
this.primaryStage = primaryStage;
}
}
但也可以实现Initializable接口。请参阅Introduction to FXML :: Controllers。
另请注意,您可以通过以下任意节点获取场景及其舞台,该节点是构建的场景图(即显示的舞台)的一部分:
Scene scene = anynode.getScene();
Stage primaryStage = (Stage) anynode.getScene().getWindow();
当然,对于您创建的第二阶段,getWindow()将返回该阶段而不是主阶段。
答案 1 :(得分:1)
根本不需要跳过任何这些箍来访问窗口。您可以在任何节点上调用getScene().getWindow()
以获取显示它的窗口(当然,您可以按照常规方式将任何节点注入控制器)。
不要使用Application
子类作为控制器类:您将拥有(至少)两个不同的实例(一个由launch()
方法创建,因为它是Application
子类,以及FXMLLoader
创建的一个,因为它是控制器类)。将在不同的实例中初始化不同的字段。
创建一个控制器类,并向其中注入至少一个节点:
public class Controller {
@FXML
private Parent root ;
@FXML
private void myMethod() {
Window window = root.getScene().getStage();
// assuming you are running as a standalone application, the window
// will actually be a Stage instance.
window.hide(); // for example...
}
}
将此作为您的控制器类并将节点注入其中:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Controller" fx:id="root">
<children>
<Button mnemonicParsing="false" onAction="#myMethod" text="Button" />
</children>
</HBox>