如何使用JavaFX中的后台工作在GUI中进行更改?

时间:2018-04-03 19:05:19

标签: user-interface javafx task runnable

从所有搜索和阅读中可以清楚地看到,我需要调用 Platform.runLater()来更改GUI。我似乎还需要使用 Runnable 界面。也许我也应该使用任务

但我无法弄清楚我应该如何使用它们。另外,我不确定应该把它放在哪个类中。我是JavaFX的新手。

我的试用版JavaFX项目只有一个Label和一个TextField。标签包含一个问题,TextField用于回答。很简单。

我在这里遇到了问题:

答案检查方法是在一个单独的类中。我无法弄清楚如何访问GUI / FXML的组件并更改它们。其他类中的方法是静态的,而GUI / FXML的组件是非静态的。

由于我的实际项目会有很多测验,所以我热衷于使用单独的课程来检查答案。

这里只有3个小班是相关的:

  1. 包含主要方法的“Launcher”类。
  2. FXML文件的“ViewController”类以及一些方法。
  3. “Ans”类,其中包含检查答案输入的方法。
  4. 我应该在哪个类中放置Platform.runLater()?代码怎么样?

    我将只分享“Ans”和“ViewController”类的代码。

    答案(背景工作应该发生在这个文件中。在评论中,我已经提到了我想要做但却无法做到的事情。例如,我想设置那里的标签文字,但我不能。因为我不知道怎么做,我只是把System.out.Println放在那里。在旁边的评论中,我已经提到了我真正想做的事情。)

    package com.dan.ans;
    
    import com.dan.qn.Qn;
    import com.dan.view.ViewController;
    public class Ans {
    public static void checkAns() {
    
        // Checks if the ans is correct.
        if (ViewController.getTextFieldInput().equalsIgnoreCase(Qn.getAns())) {
    
            System.out.println("Correct!");     // Here I want the label to say 'Correct!' rather than it be print out in the console.
    
            Qn.setQuestion();                   // This gets the next question from the database. But again, I don't know how to make the changes show on the screen. (In the actual code I'd have a separate Label for each of these things)
    
        } else { // Runs if it's not correct.
    
            System.out.println("Incorrect!");    // Here I want the label to say 'Incorrect' rather than it be print out in the console.
        }
      }
    }
    

    的ViewController

    package com.dan.view;
    
    import java.io.IOException;
    import java.net.URL;
    import java.util.ResourceBundle;
    
    import com.dan.ans.Ans;
    import com.dan.qn.Qn;
    
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Label;
    import javafx.scene.control.TextField;
    
    public class ViewController implements Initializable {
    
    private static String textFieldInput;      // I don't know how to access the typed info in the textField from another class. So I store it here and get it from it.
    
    // This is the getter I use for it. (See above)
    public static String getTextFieldInput() {
        return textFieldInput;
    }
    
    @FXML
    private Label label;
    
    @FXML
    private TextField textField;
    
    @Override
    public void initialize(URL location, ResourceBundle resources) {
    
        Qn.setQuestion();                       // This method is in the Qn class. It retrieves data from the db file and keeps them in variables.
    
        label.setText(Qn.getQn());              // This sets the label's text using the retrieved data. So you see the first question when the program opens.
    }
    
    // Event Listener on TextField[#textField].onAction
    public void enter(ActionEvent event) throws IOException {
    
        textFieldInput = textField.getText();    // Stores the typed info in the variable to be accessed from elsewhere.
    
        Ans.checkAns();                         // Runs the checkAns to check if the typed answer is correct or not.
    
      }
    
    }
    

    “Launcher”方法看起来就像任何带有主类的方法一样。所以我这里没有分享它的代码。

    有人可以告诉我如何从其他类如“Ans”更新GUI中的组件吗?我很确定我应该使用Platform.runLater()和Runnable。也可能是任务。我已经看过几个例子,但我不知道如何在这个背景下使用它。

    提前多多感谢! :)

1 个答案:

答案 0 :(得分:1)

这里的问题并不是特别清楚。自然(对我而言,无论如何)方法只是使checkAnswer(...)方法简单地“做它在盒子上所说的内容”的方法,即将答案作为参数,检查它,并返回一个调用者的值,表明它是否正确。

这样你也可以避免所有丑陋的static黑客攻击。

public class Ans {

    public boolean checkAns(String answer) {
        // not really sure what Qn is here, but you can also clean this up and
        // get rid of the static methods
        if (answer.equalsIgnoreCase(Qn.getAns()) {
            // not sure if this really belongs here?
            Qn.setQuestion(); // really takes no parameters? Sets it to what, then?
            return true ;
        } else {
            return false ;
        }
    }
}

然后在你的控制器中,你可以做到

public class ViewController implements Initializable {

    private Ans ans ;

    @FXML
    private Label label;

    @FXML
    private TextField textField;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        ans = new Ans();
        // ...
    }

    // ...

    public void enter(ActionEvent event) {
        if (ans.checkAns(textField.getText())) {
            // update UI to show answer was correct, etc
        } else {
            // update UI to show answer was incorrect...
        }
    }

    // ...
}

请注意,这可以让您保持适当的关注点分离:Ans类不需要知道关于UI的任何内容(它根本不应该知道),以及所有UI-特定代码封装在它所属的控制器类中。

为什么你要问Platform.runLater(...)并使用Task并不是很清楚,因为你发布的代码中没有任何代码涉及任何后台线程(即这些代码似乎没有一个可观的数量的时间)。例如,如果checkAns(...)方法正在进行某些远程查找并且确实需要时间来运行,那么您将在Task中执行它并从任务的onSucceeded处理程序更新UI。见,例如, Using threads to make database requests。您的问题似乎更多地是关于基本的OO设计以及如何定义不同对象之间的关系;我认为你根本不会询问线程。