Java表单问题

时间:2015-03-23 23:21:33

标签: java intellij-idea javafx

我最近已经深入研究了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()时显示空白? 任何帮助都会被贬低。

2 个答案:

答案 0 :(得分:0)

看起来你混淆了构成应用程序的不同部分。

FXML通常代表"视图&#34 ;;即UI可见的部分。它定义了显示哪些控件以及它们的布局方式。

控制器实现连接到(控制)视图的逻辑。因此,它通常以各种方式处理用户输入并更新视图。

Stage是一个窗口。

所以,我不认为你的控制器是Stage是真的有意义。在某些情况下,您可以将控制器作为UI元素的子类,但这些是JavaFX的一些高级用法,即使这样,您通常也会子类化布局窗格,而不是Stage

以下是您在load上致电FXMLLoader时发生的情况:

  1. FXMLLoader创建与FXML文件中定义的元素对应的Node s(UI元素)层次结构
  2. 如果FXML文件在其根元素中定义了fx:controller属性,则FXMLLoader 构造该类的新实例。然后,它将具有fx:id属性的任何元素注入该控制器实例中的字段,其名称与fx:id值匹配。它还注册映射到控制器实例中的方法的任何事件处理程序。
  3. FXMLLoader' load()方法返回与FXML文件的根元素对应的对象。
  4. 因此,在您的代码中,您最终会得到两个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对话框,所以将是首选的方法。