我正在使用JavaFX创建一个Desktop UI.该应用程序将打开一个窗口,用户在关闭窗口之前将在其中输入一些信息.我返回数据的最初 idea 是让这个打开的窗口将信息保存到类变量中.我将使用getters从创建UI应用程序的类中检索数据.然而,在窗口关闭后,变量似乎被重置为其原始值,并且我无法检索数据.下面是我正在努力实现的伪代码.

用户界面的类.

public class MyScreen extends Application {
    private String userText;

    public void openWindow() {
        launch();
        System.out.println("3. " + userText); // Outputs empty string.
    }

    @Override
    private void start(Stage stage) {
        // Create window controls
        button.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(final ActionEvent event) {
                // Do stuff with user data
                System.out.println("1. " + userText); // Outputs empty string
                userText = textField.getText();
                System.out.println("2. " + userText); // Outputs user inputted text.
                stage.close();
            }
        })
    }

    public getUserText() {
        return userText;
    }
}

调用类.

public class MyMainClass {
    public static void main(String args[]) {
        MyScreen screen = New MyScreen();
        screen.openWindow();
        System.out.println("4. " + screen.getUserText());
    }
}

运行我的进程的样例输出:

> 1.
> 2. sample text
> 3.
> 4.

从实例化一个JavaFX UI的类返回数据的正确方法是什么?

推荐答案

我将对Slaw,here&Amp;here的两条 comments 做出回答.

JavaFX “magic”

JavaFX是一个复杂的框架,它比您在您自己的源代码中看到的要"神奇"得多.

其中一个神奇之处在于,当您的JavaFX应用程序启动时,Application的子类将通过reflection自动实例化.

所以你的代码行MyScreen screen = New MyScreen();是多余的,应该删除.JavaFX框架已经创建了MyScreen的一个实例作为Application的子类.因此,您的应用程序有两个MyScreen Go实例,一个由JavaFX框架隐式创建,另一个由您在该行代码中创建.

这就解释了为什么您无法获得userText字段的值.您的代码调用的是MyScreenyour实例,而不是JavaFX框架的MyScreen实例.userText字段确实设置了,但设置在后者,而不是前者.

this hack

如果您really想要在您的给定方法中跟踪应用程序中的状态,我见过一个黑客攻击,其中人们对其Application子类的隐式实例化对象进行了Singleton次引用.他们在子类Application上添加static变量,这是子类类型的变量.然后,在其Application#start覆盖实现中,它们将this赋值给该变量.

public class MyScreen extends Application {
    public static MyScreen myInstanceOfMyScreen;
    private String userText;

    @Override
    private void start(Stage stage) {
        …
        this.myInstanceOfMyScreen = this ;  // A hack, not necessarily recommended. 
    }

    public getUserText() {
        return userText;
    }
        

然后其他类就可以访问这static个单例.

// Some code in some other class
String userText = MyScreen.myInstanceOfMyScreen.getUserText() ;

但这种方法很可能表明您的应用程序中存在糟糕的设计.

JavaFX生命周期

要了解有关JavaFX应用程序生命周期的更多信息,请参阅另一个问题的my lengthy Answer.

警告:我不是JavaFX方面的专家.要获得更多专业知识,请查找jewelseaSlawJames_D和其他方面的帖子.并阅读the documentation.

GUI app versus console app

您设计应用程序的方法似乎很奇怪,将基于JavaFX的图形用户界面应用程序作为更大的"外部"应用程序的子 routine 运行.

图形用户界面应用程序是独立的.图形用户界面的生命周期应该是应用程序的生命周期.如果图形用户界面的所有元素都已经关闭,没有更多的窗口和菜单栏,那么应用程序应该结束.

您将Application个子类命名为MyScreen这一事实表明,您认为JavaFX只是您应用程序的一部分.相反,您应该将JavaFX作为您的entire应用程序.

如果您的目标是构建一个从用户那里收集输入的控制台应用程序,那么可以使用与控制台相关的Java类(如Scanner)在控制台上与用户交互.试图将图形用户界面应用程序与控制台应用程序混合在一起是没有意义的,从MacOS、Windows、Linux等现代操作系统的架构设计来看是没有意义的.

唯一例外是希望在终端屏幕中运行图形用户界面的面向控制台的环境.这类应用程序被称为text-based user-interface,微软因其COW(Character-Oriented Windows)应用程序(如Microsoft Works for MS-DOS)而闻名.但这类应用程序应该在终端屏幕/窗口中运行.相反,JavaFX应用程序应该在MacOS/Windows/Linux/等图形环境中运行.仅供参考,Java生态系统确实提供了一些框架来构建基于文本的UI应用程序,例如Lanterna.

通信数据

如果您需要共享超出图形用户界面限制的用户输入,请使用外部系统.例如,将数据发布到message queue,发送邮箱,插入数据库,将文件写入存储.

Example app

以下是一个JavaFX应用程序示例:

  1. 收集来自用户的输入.
  2. 将数据报告到消息队列、发送邮箱并写入数据库.
  3. 退出/退出应用程序.

screenshot of example app soliciting the user for their favorite color, along with a button to submit that data and then exit the app

请注意,在向该队列、邮箱和数据库报告时,该图形用户界面保持可见.如果出现任何错误,您可以使用该图形用户界面来通知用户问题.

package work.basil.example.exfxgatherinput;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;

public class GatherInputApp extends Application
{
    @Override
    public void start ( Stage stage ) throws IOException
    {
        // Scene
        Scene scene = this.makeScene ( );

        // Stage
        stage.setTitle ( "Give me your input" );
        stage.setHeight ( 300 );
        stage.setWidth ( 500 );

        stage.setScene ( scene );
        stage.show ( );
    }

    private Scene makeScene ( )
    {
        // Data input
        Label inputLabel = new Label ( "Favorite color:" );
        TextField inputTextField = new TextField ( );
        HBox inputBox = new HBox ( );
        inputBox.setAlignment ( Pos.CENTER );
        inputBox.getChildren ( ).addAll ( inputLabel , inputTextField );
        inputBox.setSpacing ( 10 );

        // Submit data
        Button button = new Button ( );
        button.setText ( "Submit input, quit app" );
        button.setOnAction ( ( event ) ->
        {
            String favoriteColor = inputTextField.getText ( );
            System.out.println ( "Reporting input to a message queue… " + favoriteColor );
            System.out.println ( "Sending input in an email… " + favoriteColor );
            System.out.println ( "Writing input to a database… " + favoriteColor );
            Platform.exit ( );  // Ends the JavaFX app, after firing hooks for app-shutdown. 
        } );

        VBox vbox = new VBox ( inputBox , button );
        vbox.setPadding ( new Insets ( 20 , 20 , 20 , 20 ) );
        vbox.setSpacing ( 10 );
        vbox.setAlignment ( Pos.CENTER );

        return new Scene ( vbox );
    }

    public static void main ( String[] args ) { launch ( ); }
}

运行时:

Reporting input to a message queue… purple
Sending input in an email… purple
Writing input to a database… purple

Process finished with exit code 0

顺便说一句,以编程方式退出图形用户界面应用程序被认为是粗鲁的.在图形环境中,用户负责.一般来说,应用程序应该保持打开和运行,直到user人决定退出/退出.

Java相关问答推荐

Selenium Java:无法访问IFRAME内部的元素

无法找到符号错误—Java—封装

Java中不同包中的类之间的配置共享

Select 按位运算序列

ittext pdf延迟签名,签名无效

Junit with Mockito for java

如何才能使我的程序不会要求两次输入?

AssertJ Java:多条件断言

如何在JavaFX中制作鼠标透明stage

Java SSLKeyManager出厂密码

如何创建模块信息类文件并将其添加到JAR中?

如何在EL处理器中定义带有命名空间的变量?

如何使这两种方法合二为一?

如果第一位数字和最后一位数字相差超过一位,您将如何获得随机数?

Spring Validator批注不起作用

在Spring Boot中使用咖啡因进行缓存-根据输出控制缓存

Java递归泛型是否可以被视为继承和重写的语法糖

ReturnedRect在升级后反转

使用StringBuilder和append方法创建字符串时Java字符串内部方法的问题

Spring Boot应用程序中的自定义constraintvalidator不会被调用