JavaFX 控制器类不工作

Posted

技术标签:

【中文标题】JavaFX 控制器类不工作【英文标题】:JavaFX controller class not working 【发布时间】:2015-11-11 22:32:24 【问题描述】:

我真的很难理解 JavaFX 控制器,我的目标是写入 TextArea 以充当日志。

我的代码如下,但我希望能够从另一个类中更改值 ETC,我可以在需要时调用它。我试图创建一个扩展 Initializable 的控制器类,但我无法让它工作。有人能引导我走向正确的方向吗?

我想将底部的@FXML 代码移动到另一个类并更新场景。

package application;
import javafx.event.ActionEvent;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;

import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;


public class Main extends Application 
    @Override
    public void start(Stage primaryStage) 
        try 
            Parent root = FXMLLoader.load(getClass().getResource("Root.fxml"));
            Scene scene = new Scene(root,504,325);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();
         catch(Exception e) 
            e.printStackTrace();
        
    

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

    public Thread thread = new Thread(new webimporter());

    @FXML
    public Label runningLabel;

    @FXML 
    public TextArea txtArea;

    @FXML
    void runClick(ActionEvent event) throws IOException
        changeLabelValue("Importer running...");
        thread.start();

       

    @FXML
    protected void stopClick(ActionEvent event)
        changeLabelValue("Importer stopped...");
        thread.interrupt();
               

    @FXML
    void changeLabelValue(String newText)
        runningLabel.setText(newText);
    

    void changeTextAreaValue(String newText1)
        txtArea.setText(newText1);
    

【问题讨论】:

【参考方案1】:

不要让 Application 类成为控制器。这是一种罪过。还有其他问题和答案可以解决这个问题,但我的搜索技能目前无法找到它们。

它是罪的原因是:

    您应该只有一个应用程序实例,并且默认情况下,加载程序会创建一个新实例,因此您最终会得到两个应用程序对象。 引用成员对象令人困惑,因为最初启动的应用程序没有@FXML 注入字段,但加载程序创建的应用程序实例确实有@FXML 注入字段。

另外,不相关的建议:不要开始尝试编写多线程代码,直到您的应用程序至少可以显示您的 UI。

Most efficient way to log messages to JavaFX TextArea via threads with simple custom logging frameworks 的答案是用于 JavaFX 的多线程记录器,但不幸的是,它的实现并不直接,而且文档很少。


textlogger/Root.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="400.0" spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="textlogger.ImportController">
   <children>
      <HBox alignment="BASELINE_LEFT" minHeight="-Infinity" minWidth="-Infinity" spacing="10.0">
         <children>
            <Button mnemonicParsing="false" onAction="#run" text="Run" />
            <Button mnemonicParsing="false" onAction="#stop" text="Stop" />
            <Label fx:id="runningLabel" />
         </children>
         <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </padding>
      </HBox>
      <TextArea fx:id="textArea" editable="false" prefHeight="200.0" prefWidth="200.0" />
   </children>
   <padding>
      <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
   </padding>
</VBox>

textlogger.ImportController.java

package textlogger;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;

import java.io.IOException;

public class ImportController 
    @FXML
    private Label runningLabel;

    @FXML
    private TextArea textArea;

    private WebImporter importer;

    @FXML
    void run(ActionEvent event) throws IOException 
        changeLabelValue("Importer running...");

        if (importer == null) 
            importer = new WebImporter(textArea);
            Thread thread = new Thread(
                    importer
            );
            thread.setDaemon(true);
            thread.start();
        
    

    @FXML
    void stop(ActionEvent event)
        changeLabelValue("Importer stopped...");
        if (importer != null) 
            importer.cancel();
            importer = null;
        
               

    private void changeLabelValue(String newText)
        runningLabel.setText(newText);
    


textlogger.WebImporter.java

import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.control.TextArea;

import java.time.LocalTime;

public class WebImporter extends Task<Void> 

    private final TextArea textArea;

    public WebImporter(TextArea textArea) 
        this.textArea = textArea;
    

    @Override
    protected Void call() throws Exception 
        try 
            while (!isCancelled()) 
                Thread.sleep(500);

                Platform.runLater(
                        () -> textArea.setText(
                                textArea.getText() + LocalTime.now() + "\n"
                        )
                );
            
         catch (InterruptedException e) 
            Thread.interrupted();
        

        return null;
    

textlogger.TextLoggingSample.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class TextLoggingSample extends Application 
    @Override
    public void start(Stage stage) 
        try 
            FXMLLoader loader = new FXMLLoader();
            Parent root = loader.load(
                getClass().getResourceAsStream(
                        "Root.fxml"
                )
            );

            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();
         catch(Exception e) 
            e.printStackTrace();
        
    

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

【讨论】:

我可以让它显示并正常工作,但我不知道如何从我在线程中创建的类中写入 TextArea。 如果你不提供mcve,你会让我做更多的工作来帮助你解决问题。 当你无法掌握一个概念时,很难完全解释它。 是的,我知道,提出好问题比写答案更难。希望这里的信息对您有所帮助。 谢谢jewelsea,您解决了我的问题。在没有人指导的情况下学习 Java 并非易事。我买的《Beginning Programming with Java for DUMMIES》这本书非常好。它教会我使用 Application 类作为控制器。我以后不会这样做了。我设法弄清楚如何在场景构建器中指定新控制器。您帮助我学习了如何将 TextArea 解析到对我帮助无穷无尽的课程中。我不明白“extends Task ”,但我猜是多态性或您可以将类复制到自己的类中的一种方式。

以上是关于JavaFX 控制器类不工作的主要内容,如果未能解决你的问题,请参考以下文章

动态访问/遍历/操作从控制器类外部的 FXML 创建的 JavaFX 节点

JavaFX TabPane从外部控制器中选择选项卡

Symfony SerializerInterface 将 json 反序列化为类不起作用

一个控制器到 2 个 fxmls (JavaFX)

一个控制器到 2 个 fxmls (JavaFX)

JavaFX:从线程更新控制器类中的 UI 元素