JavaFX 控制器类不起作用 [英] JavaFX controller class not working

查看:45
本文介绍了JavaFX 控制器类不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

打包应用程序;导入 javafx.event.ActionEvent;导入 javafx.scene.control.Label;导入 javafx.scene.control.TextArea;导入 java.io.IOException;导入 javafx.application.Application;导入 javafx.fxml.FXML;导入 javafx.fxml.FXMLLoader;导入 javafx.stage.Stage;导入 javafx.scene.Parent;导入 javafx.scene.Scene;公共类 Main 扩展应用程序 {@覆盖公共无效开始(阶段primaryStage){尝试 {父根 = FXMLLoader.load(getClass().getResource("Root.fxml"));场景场景 = 新场景(root,504,325);scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());primaryStage.setScene(场景);primaryStage.show();} 捕获(异常 e){e.printStackTrace();}}公共静态无效主(字符串 [] args){发射(参数);}公共线程线程=新线程(新的webimporter());@FXML公共标签运行标签;@FXML公共文本区域 txtArea;@FXMLvoid runClick(ActionEvent event) 抛出 IOException{changeLabelValue("进口商正在运行...");线程开始();}@FXMLprotected void stopClick(ActionEvent event){changeLabelValue("进口商停止...");线程中断();}@FXMLvoid changeLabelValue(String newText){runningLabel.setText(newText);}void changeTextAreaValue(String newText1){txtArea.setText(newText1);}}

解决方案

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

犯罪的原因是:

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

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

JavaFX 的多线程记录器是

textlogger/Root.fxml

<儿童><HBox 对齐="BASELINE_LEFT" minHeight="-Infinity" minWidth="-Infinity" 间距="10.0"><儿童><Button mnemonicParsing="false" onAction="#run" text="Run"/><Button mnemonicParsing="false" onAction="#stop" text="Stop"/><Label fx:id="runningLabel"/></儿童><填充><Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/></填充></HBox><TextArea fx:id="textArea" editable="false" prefHeight="200.0" prefWidth="200.0"/></儿童><填充><Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/></填充></VBox>

textlogger.ImportController.java

包文本记录器;导入 javafx.event.ActionEvent;导入 javafx.fxml.FXML;导入 javafx.scene.control.Label;导入 javafx.scene.control.TextArea;导入 java.io.IOException;公共类导入控制器{@FXML私有标签运行标签;@FXML私有文本区域文本区域;私人 WebImporter 进口商;@FXMLvoid run(ActionEvent event) 抛出 IOException {changeLabelValue("进口商正在运行...");如果(进口商 == 空){importer = new WebImporter(textArea);线程线程=新线程(进口商);线程.setDaemon(真);线程开始();}}@FXML无效停止(ActionEvent事件){changeLabelValue("进口商停止...");如果(进口商!= null){进口商.cancel();进口商 = 空;}}私有无效changeLabelValue(字符串newText){runningLabel.setText(newText);}}

textlogger.WebImporter.java

import javafx.application.Platform;导入 javafx.concurrent.Task;导入 javafx.scene.control.TextArea;导入 java.time.LocalTime;公共类 WebImporter 扩展了 Task{私人最终 TextArea textArea;公共 WebImporter(TextArea textArea) {this.textArea = textArea;}@覆盖protected void call() 抛出异常 {尝试 {而 (!isCancelled()) {线程睡眠(500);Platform.runLater(() ->textArea.setText(textArea.getText() + LocalTime.now() + "
"));}} catch (InterruptedException e) {Thread.interrupted();}返回空;}}

textlogger.TextLoggingSample.java

import javafx.application.Application;导入 javafx.fxml.FXMLLoader;导入 javafx.scene.Parent;导入 javafx.scene.Scene;导入 javafx.stage.Stage;公共类 TextLoggingSample 扩展应用程序 {@覆盖公共无效开始(阶段阶段){尝试 {FXMLLoader 加载器 = 新 FXMLLoader();父根 = loader.load(getClass().getResourceAsStream(根.fxml"));场景场景 = 新场景(根);stage.setScene(场景);舞台表演();} 捕获(异常 e){e.printStackTrace();}}公共静态无效主(字符串 [] args){发射(参数);}}

I'm really struggling to understand JavaFX controllers, my aim is to write to a TextArea to act as a log.

My code is below, but I want to be able to change values ETC from another class that I can call when needed. I have tried to create a controller class that extents Initializable but i cant get it to work. Could some one steer me in the correct direction?

I want to move the @FXML code at the bottom to another class and it update the Scene.

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);
    }
}

解决方案

Don't make the Application class a controller. It's a sin. There are other questions and answers which address this, but my search skills cannot find them at this time.

The reason it is a sin is:

  1. You are only supposed to have one Application instance, and, by default, the loader will make a new instance, so you end up with two application objects.
  2. Referencing the member objects is confusing, because the original launched application doesn't have the @FXML injected fields, but the loader created application instance does have @FXML inject fields.

Also, unrelated advice: Don't start trying to write multi-threaded code until you have the application at least working to the extent where it displays your UI.

A multi-threaded logger for JavaFX is in the answer to Most efficient way to log messages to JavaFX TextArea via threads with simple custom logging frameworks, though unfortunately it is not straight-forward in its implementation and comes with little documentation.


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() + "
"
                        )
                );
            }
        } 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);
    }
}

这篇关于JavaFX 控制器类不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆