我正在开发一个小型 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()
方法永远不会启动。
我不知道您是否向我们提供了足够的信息来诊断您的问题。
您声称“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>