我试图在JavaFX中单击按钮时检索XLS文件并将其加载到TableView中。我使用Task类和ExecutorService来启动新线程。我需要reader类是可重用的,但是FileChooser没有出现。
这是我尝试编写一些并发代码。我想知道我做错了什么,我将如何改进我的代码,因为一切都是事件驱动的?
控制器类代码
public void retrieveCustomersFromXLS() {
try {
loader.setOnSucceeded(workerStateEvent -> {
File file = null;
try {
file = loader.get();
} catch (Exception e) {
e.printStackTrace();
}
if (file != null && file.exists()) {
reader.setWorkingFile(file);
executor.submit(reader);
}
});
reader.setOnSucceeded(workerStateEvent1 -> {
Object[][] XLSFile = new Object[0][];
try {
XLSFile = reader.get();
} catch (Exception e) {
e.printStackTrace();
}
if (XLSFile != null) {
tableInterface.setEntries(XLSFile);
tableInterface.setEntryType("customers");
executor.submit(tableInterface);
}
});
tableInterface.setOnSucceeded(workerStateEvent2 -> {
customerList = FXCollections.observableArrayList(tableInterface.getCustomerEntries());
column_customerReference.setCellValueFactory(new PropertyValueFactory<customers, Integer>("customerReference"));
column_customerName.setCellValueFactory(new PropertyValueFactory<customers, String>("customerName"));
column_customerAddress.setCellValueFactory(new PropertyValueFactory<customers, String>("customerAddress"));
column_customerPost.setCellValueFactory(new PropertyValueFactory<customers, Integer>("customerPost"));
column_customerRegion.setCellValueFactory(new PropertyValueFactory<customers, String>("customerRegion"));
column_customerID_DDV.setCellValueFactory(new PropertyValueFactory<customers, String>("customerDDV"));
table_customerImports.setItems(customerList);
});
executor.submit(loader);
} catch (Exception e) {
e.printStackTrace();
}
}
阅读器类文件
@Override
protected File call() throws Exception {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Choose Excel file");
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Excel", "*.xlsx", "*.xls", "*.csv"));
File selectedFile = fileChooser.showOpenDialog(new Stage());
if (selectedFile != null) {
path = selectedFile.getAbsolutePath();
file = new File(path);
}
return file;
}
您必须在 JavaFX Application Thread 上调用 FileChooser#showXXXDialog
方法。如果您观察到任务失败,您将看到一个 IllegalStateException,
其中包含一条消息,指出您尝试在错误的线程上执行操作。此外,你不需要后台任务来首先提示用户输入文件。
下面是一个提示用户输入文本文件的示例,在任务
中读取文本文件,并将结果放入列表视图
。
应用程序.java
package com.example;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class App extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
Scene scene = new Scene(FXMLLoader.load(getClass().getResource("/App.fxml")));
primaryStage.setScene(scene);
primaryStage.setTitle("FileChooser Example");
primaryStage.show();
}
}
App.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/13" xmlns:fx="http://javafx.com/fxml/1" spacing="5" prefWidth="600"
prefHeight="400" alignment="CENTER" fx:controller="com.example.Controller">
<padding>
<Insets topRightBottomLeft="5"/>
</padding>
<Button text="Open File..." onAction="#handleOpenFile"/>
<Separator/>
<ListView fx:id="listView" VBox.vgrow="ALWAYS"/>
</VBox>
Controller.java
package com.example;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javafx.collections.FXCollections;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
public class Controller {
private final Executor executor = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r, "controller-thread");
t.setDaemon(true);
return t;
});
@FXML private ListView<String> listView;
@FXML
private void handleOpenFile(ActionEvent event) {
event.consume();
FileChooser chooser = new FileChooser();
chooser.getExtensionFilters()
.add(new ExtensionFilter("Text Files", "*.txt", "*.json", "*.xml", "*.html", "*.java"));
File file = chooser.showOpenDialog(listView.getScene().getWindow());
if (file != null) {
ReadFileTask task = new ReadFileTask(file.toPath());
task.setOnSucceeded(wse -> listView.setItems(FXCollections.observableList(task.getValue())));
task.setOnFailed(wse -> task.getException().printStackTrace());
executor.execute(task);
}
}
private static class ReadFileTask extends Task<List<String>> {
private final Path file;
private ReadFileTask(Path file) {
this.file = Objects.requireNonNull(file);
}
@Override
protected List<String> call() throws Exception {
return Files.readAllLines(file);
}
}
}
问题内容: 标题可能有点含糊,所以让我对其定义更好一些。我有一段有效的代码(在下面):我正在开发的游戏的简单主菜单。除“开始”按钮外,其他所有内容均正常运行。 我想要做的是单击“开始”按钮,并在同一阶段(窗口)中出现一个新场景。我不想看到一个新窗口打开。我已经与Java经验丰富的人进行了交谈,他们告诉我为MenuFX和GameFX创建单独的类。如果是这种情况,我需要从MenuFX类中调用GameF
问题内容: 关于此事,我几乎遍历了每篇文章,但大多数都没有解释如何正确执行。问题: 我创建了一个javaFX应用程序,一个骰子游戏,人类玩家与计算机,但是在玩游戏的任何时候,人类玩家都应该能够单击“新游戏”按钮,并且应该从头开始重新启动游戏。 我尝试再次启动该阶段,但是在javafx中,我们不能两次调用launch方法。 1)有没有一种方法可以实现此功能而无需重新启动整个应用程序? 2)如果没有,
问题内容: 我是Swing的新手。 我要在单击按钮(完成按钮)后更新表格。我认为数据正确,但屏幕无法正常工作。 以下是我程序的说明 选中复选框,然后单击完成按钮 最底层应更改。 没有主 这是我的代码: 问题答案: 而不是这样做… 只需更新现有模型 或简单地 假设您要继续向表中添加新行。如果您要这样做,还可以先清除表,然后再向其中添加新行。 Swing的工作原理是MVC(模型-视图- 控制器 ),该
问题内容: 我在执行后台任务时使JavaFX UI保持活动状态时遇到问题。我已经设置了这个非常简单的代码- 我希望发生的事情是让进度条每1秒钟更新一次,直到任务完成。而是,UI完全冻结10秒钟,之后进度条显示为完成。明确地说- 问题不仅在于所有更新最终一次出现,而且UI直到那时都完全没有响应。 我已经阅读了有关此主题的其他任何问题,但找不到答案。我究竟做错了什么? 谢谢。 问题答案: 使用 sta
我对javafx和场景构建器非常陌生。当单击按钮时,我试图创建一个新标签。以下是按钮创建标签的方法: 但它不起作用:(是否因为我没有在fxml中创建lbl1?是否可以在java代码中创建标签而不在fxml中创建?请帮助我!
问题内容: 我正在使用此处找到的自定义表格模型。我已经使用该帖子中提供的建议更新了我的代码,并遇到了一个新问题。我对我的代码所做的改变是一个注入到我,以避免与线程的问题。完成此操作后,通过按按钮更新我的表的代码已停止工作。 用于初始化的代码如下: 我用来更新的代码如下: 我也尝试过使用,但这也不起作用。截至目前,更新的唯一方法是关闭并重新打开程序。具有我正在使用的,随着用户添加更多玩家,尺寸会增加