JavaFX控制器类无法正常工作

JavaFX控制器类无法正常工作

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

问题描述

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



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



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

 包裹申请; 
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;


公共类主扩展应用程序{
@Override
public void start(Stage primaryStage){
try {
Parent root = FXMLLoader .load(的getClass()的getResource( Root.fxml));
场景场景=新场景(root,504,325);
scene.getStylesheets()。add(getClass()。getResource(application.css)。toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(例外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事件)抛出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不要让Application类成为控制器。这是一种罪过。还有其他问题和答案可以解决这个问题,但我的搜索技能目前还无法找到。



它是罪的原因是:


  1. 你应该只是有一个Application实例,默认情况下,加载器将创建一个新实例,因此最终会得到两个应用程序对象。

  2. 引用成员对象很困惑,因为原始启动的应用程序没有@FXML注入字段,但加载器创建的应用程序实例确实有@FXML注入字段。

此外,不相关的建议:在应用程序至少工作到这个程度之前,不要开始尝试编写多线程代码它显示你的UI。



JavaFX的多线程记录器是对



textlogger / Root.fxml

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

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

< VBox maxHeight = - InfinitymaxWidth = - InfinityminHeight = - InfinityminWidth = - InfinityprefWidth =400.0spacing =10.0xmlns =http: //javafx.com/javafx/8xmlns:fx =http://javafx.com/fxml/1fx:controller =textlogger.ImportController>
< children>
< HBox alignment =BASELINE_LEFTminHeight = - InfinityminWidth = - Infinityspacing =10.0>
< children>
< Button mnemonicParsing =falseonAction =#runtext =Run/>
< Button mnemonicParsing =falseonAction =#stoptext =Stop/>
< Label fx:id =runningLabel/>
< / children>
< padding>
< Insets bottom =10.0left =10.0right =10.0top =10.0/>
< / padding>
< / HBox>
< TextArea fx:id =textAreaeditable =falseprefHeight =200.0prefWidth =200.0/>
< / children>
< padding>
< Insets bottom =10.0left =10.0right =10.0top =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;

公共类ImportController {
@FXML
private Label runningLabel;

@FXML
private TextArea textArea;

私人WebImporter进口商;

@FXML
void run(ActionEvent事件)抛出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事件){
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;

公共类WebImporter扩展Task< Void> {

私人最终TextArea textArea;

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

@Override
protected Void call()抛出异常{
try {
while(!isCancelled()){
Thread 。睡眠(500);

Platform.runLater(
() - > textArea.setText(
textArea.getText()+ LocalTime.now()+\ n

);
}
} catch(InterruptedException e){
Thread.interrupted();
}

返回null;
}
}

textlogger.TextLoggingSample.java

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

公共类TextLoggingSample extends Application {
@Override
public void start(Stage stage){
try {
FXMLLoader loader = new FXMLLoader();
父root = loader.load(
getClass()。getResourceAsStream(
Root.fxml

);

场景场景=新场景(根);
stage.setScene(场景);
stage.show();
} catch(例外e){
e.printStackTrace();
}
}

public static void main(String [] args){
launch(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() + "\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);
    }
}

这篇关于JavaFX控制器类无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 10:11