JavaFX TaskWorker 将无法启动

问题描述 投票:0回答:1

我正在开发一个小型 JavFXML 桌面应用程序,其中包含一个 TaskWorker。目标是在单击按钮时运行任务工作线程,但什么也没有发生,并且任务工作线程也没有被调用。鼠标点击代码是这样的:

public class TableViewController implements Initializable{
    ....

 @FXML private void handleGoButton (ActionEvent event) {
    TaskWorker taskworker = new TaskWorker(50);  
    new Thread(taskworker).start(); 
  }

最初的目标是在任务工作人员内部运行进度指示器和文件复制语句,但为了尝试理解这个问题,我删除了大部分代码,并将其替换为一个打印出索引值的简单循环。因此,任务工作者看起来像这样:

public class TaskWorker extends Task<Void> {
  public int value;  
  
  public TaskWorker (int value) {
    this.value = value;
    System.out.println("Value = " + this.value );
  }
  
  @Override
  protected Void call() throws Exception {
     
    
    for (int i=0; i < this.value; i++){
      System.out.println("Value of i = " + i );   
      Thread.sleep(400); 
    }
    return null;
  }
}

单击鼠标时,我期望输出确认 TaskWorker 中的构造函数获取了传递的值,并且输出显示了传递的值的索引值。 Taskworker 确实在构造函数中获取了值:

compile:
run:
Value = 50
BUILD SUCCESSFUL (total time: 18 seconds)

但是

call()
方法永远不会启动。

java javafx concurrency java-threads
1个回答
0
投票

信息不足

我不知道您是否向我们提供了足够的信息来诊断您的问题。

您声称“Value = 50”输出证明您的

TaskWorker
正在构建,因此证明
handleGoButton
已连接到您的 FXML 文件。但您没有提供MCVE,因此我们无法验证您的断言。

Initializable

我不知道这是否会影响您的问题,但我想知道您的

TableViewController implements Initializable
Initializable
的 Javadoc 表示该接口已过时:

注意 此接口已被自动注入

location
resources
属性到控制器中所取代。
FXMLLoader
现在将自动调用控制器定义的任何适当注释的无参数
initialize()
方法。建议尽可能使用注射方式。

示例应用程序

我不是 JavaFX 方面的专家,但我确实阅读了 JavaFX 8 手册的 1 JavaFX 中的并发 页。想必在那之后的大部分时间仍然适用于 JavaFX 23。

根据阅读内容,我构建了一个您可能感兴趣的完整示例应用程序。

你说:

最初的目标是在任务工作线程中运行进度指示器和文件复制语句

该文档提供了一个示例,说明

ProgressBar
可以按照您的意愿进行操作。我在构建下面的示例时使用了该文档。

我首先使用 IntelliJ 2024.3 提供的新项目模板创建一个 JavaFX 项目。然后我修改了代码以添加

ProgressBar
,并以描述性方式重命名变量。

您的代码使用

new Thread
。但在现代 Java 中,我们很少直接处理
Thread
类。通常最好使用 Java 5+ 内置的 Executors 框架。所以在这里我在我的
ExecutorService
子类中建立了一个
Application
。不幸的是我通常不使用 FXML 也不使用控制器。所以我不知道如何优雅地将
ExecutorService
子类中的
Application
对象(需要在我们应用程序的生命周期挂钩期间初始化并最终关闭)与控制器(需要使用它)进行通信。作为黑客,我制作了
ExecutorService
对象
static
。希望您知道除了
static
之外更好的方法。

我的 FXML。

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ProgressBar?>
<VBox alignment="CENTER"
      spacing="20.0"
      xmlns:fx="http://javafx.com/fxml"
      fx:controller="work.basil.example.exfxtask.HelloController">
    <padding>
        <Insets bottom="20.0"
                left="20.0"
                right="20.0"
                top="20.0"/>
    </padding>

    <Label fx:id="messageText"/>
    <Button fx:id="startButton"
            text="Start"
            onAction="#onStartButtonClicked"/>
    <ProgressBar fx:id="fileProgress"/>
</VBox>

我的控制器。

package work.basil.example.exfxtask;

import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;

import java.time.Duration;
import java.time.ZonedDateTime;

public class HelloController
{
    @FXML
    private Label messageText;
    @FXML
    public Button startButton;
    @FXML
    public ProgressBar fileProgress;

    @FXML
    protected void onStartButtonClicked ( )
    {
        messageText.setText( "Started " + ZonedDateTime.now( ).toString( ) );
        startButton.setDisable( true );

        Task < Void > task = new Task <>( )
        {
            @Override
            public Void call ( )
            {

                final int max = 100;
                for ( int i = 1 ; i <= max ; i++ )
                {
                    try { Thread.sleep( Duration.ofMillis( 100 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
                    if ( isCancelled( ) )
                    {
                        break;
                    }
                    updateProgress( i , max );
                }
                Platform.runLater( new Runnable( )
                {
                    @Override
                    public void run ( )
                    {
                        messageText.setText( "Finished " + ZonedDateTime.now( ).toString( ) );
                        startButton.setDisable( false );
                    }
                } );
                return null;
            }
        };
        fileProgress.progressProperty( ).bind( task.progressProperty( ) );
        HelloApplication.executorService.submit( task );

    }
}

我的

Application
子类。

package work.basil.example.exfxtask;

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

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HelloApplication extends Application
{
    public static final ExecutorService executorService = Executors.newCachedThreadPool( );

    @Override
    public void init ( ) throws Exception
    {
        super.init( );
    }

    @Override
    public void start ( Stage stage ) throws IOException
    {
        FXMLLoader fxmlLoader = new FXMLLoader( HelloApplication.class.getResource( "hello-view.fxml" ) );
        Scene scene = new Scene( fxmlLoader.load( ) , 400 , 240 );
        stage.setTitle( "Hello!" );
        stage.setScene( scene );
        stage.show( );
    }

    @Override
    public void stop ( ) throws Exception
    {
        super.stop( );
        HelloApplication.executorService.shutdown( );
    }

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

这是我的 POM。我使用了与 JavaFX 库捆绑在一起的 JDK。因此,我为 JavaFX 元素赋予了

scope
provided
。我用一个聚合器依赖项替换了两个 JUnit 依赖项。我已将各种项目的版本更新到最新。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>work.basil.example</groupId>
    <artifactId>ExFxTask</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>ExFxTask</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>23</version>
            <scope>provided</scope>
        </dependency>

   <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-fxml -->
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>23</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.11.1</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
                <configuration>
                    <source>23</source>
                    <target>23</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.8</version>
                <executions>
                    <execution>
                        <!-- Default configuration for running with: mvn clean javafx:run -->
                        <id>default-cli</id>
                        <configuration>
                            <mainClass>work.basil.example.exfxtask/work.basil.example.exfxtask.HelloApplication</mainClass>
                            <launcher>app</launcher>
                            <jlinkZipName>app</jlinkZipName>
                            <jlinkImageName>app</jlinkImageName>
                            <noManPages>true</noManPages>
                            <stripDebug>true</stripDebug>
                            <noHeaderFiles>true</noHeaderFiles>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
© www.soinside.com 2019 - 2024. All rights reserved.