JavaFX控制器类无法正常工作

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

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

我想将底部的@FXML代码移动到另一个类并更新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); } } 

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

它是罪的原因是:

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

此外,无关的建议:在应用程序至少工作到显示UI的程度之前,不要开始尝试编写multithreading代码。

JavaFX的multithreading记录器是通过具有简单自定义日志记录框架的线程将消息记录到JavaFX TextArea的最有效方法的答案,但不幸的是,它的实现并不简单,并且几乎没有文档。


样本输出

textlogger / Root.fxml

                        

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