我最近已经深入研究了JavaFX作为C#开发人员。我在Java中注意到的一件事是,你不是像Visual Studio /微软用勺子喂我们那样用勺子喂食的。
因此。当我在JavaFX上使用IntelliJ Idea的场景构建器创建表单时。我为我的控制器类继承了“Stage”并创建了一个名为load的void,它将从FXML文件加载场景实例。因此,当我从Main入口点或任何地方调用load()时,它将加载fxml文件并显示。
LoginController frmLogin = new LoginController();
frmLogin.load();
问题是它有效并且不起作用。
这是我的代码。
Main.Java
public class Main extends Application
{
@Override
public void start(Stage primaryStage) throws Exception
{
LoginController frmLogin = new LoginController();
frmLogin.load();
}
public static void main(String[] args)
{
Application.launch(args);
}
}
LoginController.Java
public class LoginController extends Stage
{
@FXML
private TextField txtUsername;
@FXML
private TextField txtPassword;
@FXML
private void btnLogin_Clicked(ActionEvent e) throws Exception
{
if (txtUsername.getText().equals("admin") && txtPassword.getText().equals("pass"))
{
Messagebox.Show("Correct Login!");
this.show(); //The problem occurs here!
}
else
{
Messagebox.Show("Incorrect Login");
}
}
public void load() throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("frmLogin.fxml"));
this.setScene(new Scene(root));
this.setTitle("JavaFX GUI");
this.setResizable(false);
this.initModality(Modality.APPLICATION_MODAL);
this.show();
}
}
这是问题的GIF。 http://i.imgur.com/0hOG76M.gif
我想知道为什么当我调用.show()时显示空白? 任何帮助都会被贬低。
答案 0 :(得分:0)
看起来你混淆了构成应用程序的不同部分。
FXML通常代表"视图&#34 ;;即UI可见的部分。它定义了显示哪些控件以及它们的布局方式。
控制器实现连接到(控制)视图的逻辑。因此,它通常以各种方式处理用户输入并更新视图。
Stage
是一个窗口。
所以,我不认为你的控制器是Stage
是真的有意义。在某些情况下,您可以将控制器作为UI元素的子类,但这些是JavaFX的一些高级用法,即使这样,您通常也会子类化布局窗格,而不是Stage
。
以下是您在load
上致电FXMLLoader
时发生的情况:
FXMLLoader
创建与FXML文件中定义的元素对应的Node
s(UI元素)层次结构fx:controller
属性,则FXMLLoader
构造该类的新实例。然后,它将具有fx:id
属性的任何元素注入该控制器实例中的字段,其名称与fx:id
值匹配。它还注册映射到控制器实例中的方法的任何事件处理程序。FXMLLoader
' load()
方法返回与FXML文件的根元素对应的对象。因此,在您的代码中,您最终会得到两个LoginController
个实例。您可以在start()
方法中自己创建一个。然后,您在该实例上调用load()
。该方法在load(...)
上调用FXMLLoader
(通过非常丑陋的静态加载方法)。然后调用FXMLLoader.load(...)
会导致FXMLLoader
创建在fx:controller
中声明的类的实例。我猜测(你没有显示FXML代码)该类也是LoginController
。这是第二个例子。
现在发生了什么,是您从FXMLLoader.load()
获得对UI元素的引用。您将其放在Scene
中,并在Scene
中设置LoginController
,其中 - {异常 - - 是Stage
。然后,您使用Stage
在屏幕上显示show()
。请注意,这发生在您在start
方法中创建的实例中。
当用户按下已注册为btnLogin_Clicked
处理程序的按钮时,将在控制器实例上调用处理程序方法:由FXMLLoader
创建的方法。该实例从未设置过Scene
,因此当您再调用this.show()
时,它会显示LoginController
的实例(同样是Stage
)。由于它从未设置过场景,因此您会看到一个空白窗口。
我真的不清楚你打算在this.show()
中对btnLogin_Clicked
的调用是什么意思。假设您认为这与您使用Stage
方法创建的start(...)
相同,则Stage
已经显示。
典型的模式是您使用传递给primaryStage
方法的start(...)
,并在其中设置场景并显示它。所以你要做的事情是:
public class Main extends Application
{
@Override
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("frmLogin.fxml"));
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("JavaFX GUI");
primaryStage.setResizable(false);
primaryStage.initModality(Modality.APPLICATION_MODAL);
primaryStage.show();
}
public static void main(String[] args)
{
Application.launch(args);
}
}
然后控制器只是一个控制器:它只处理逻辑:
public class LoginController
{
@FXML
private TextField txtUsername;
@FXML
private TextField txtPassword;
@FXML
private void btnLogin_Clicked(ActionEvent e) throws Exception
{
if (txtUsername.getText().equals("admin") && txtPassword.getText().equals("pass"))
{
Messagebox.Show("Correct Login!");
// I don't really know what you were trying to do here
// but if you need a reference to the window containing the
// associated fxml elements, you can get it from one of those
// elements:
Stage stage = (Stage) txtUsername.getScene().getWindow();
//this.show(); //The problem occurs here!
}
else
{
Messagebox.Show("Incorrect Login");
}
}
}
通常,当用户成功登录时,您要执行的操作是在当前窗口中显示新内容。最简单的方法是将当前场景的根目录设置为不同FXML文件的内容。例如:
public class LoginController
{
@FXML
private TextField txtUsername;
@FXML
private TextField txtPassword;
@FXML
private void btnLogin_Clicked(ActionEvent e) throws Exception
{
if (txtUsername.getText().equals("admin") && txtPassword.getText().equals("pass"))
{
Messagebox.Show("Correct Login!");
Scene currentScene = txtUsername.getScene();
Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));
currentScene.setRoot(root);
// resize window:
currentScene.getWindow().sizeToScene();
}
else
{
Messagebox.Show("Incorrect Login");
}
}
}
这里Main.fxml
定义了用户看到的主要应用程序,成功登录并定义了自己的控制器类等。
答案 1 :(得分:0)
解决方案
不要在Controller中继承Stage。
JavaFX将隐式为您的应用程序创建一个Stage并将其传递给您的应用程序(应用程序启动方法中的primaryStage
参数)。
示例
这是一个应该有效的快速更新。另一个替代方案是将舞台管理分解为詹姆斯的答案。
public class Main extends Application
{
@Override
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("frmLogin.fxml"));
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("JavaFX GUI");
primaryStage.setResizable(false);
primaryStage.show();
}
public static void main(String[] args)
{
Application.launch(args);
}
}
. . .
public class LoginController
{
@FXML
private TextField txtUsername;
@FXML
private TextField txtPassword;
@FXML
private void btnLogin_Clicked(ActionEvent e) throws Exception
{
if (txtUsername.getText().equals("admin") && txtPassword.getText().equals("pass"))
{
Messagebox.Show("Correct Login!");
}
else
{
Messagebox.Show("Incorrect Login");
}
}
}
除了:我不确定你的MessageBox
类是什么,但是JavaFX 8u40有一个标准消息框样式功能的内置Alert对话框,所以将是首选的方法。