我基本上试图让用户从FileChooser输入文件路径然后将其传递给任务,以便可以对其进行操作并将其转换为可以在JavaFX ImageView中显示的图像。我的问题是我在线程中运行任务,并且我的方法不会等到线程完成执行以返回所需的图像。有没有办法实现这个目标?
//带有fileChooser的JavaFX控制器
public class JavaCVTestController implements Initializable{
@FXML
ImageView image;
@FXML
Button btnUpload;
FileChooser fileChooser = new FileChooser();
String selectedFile = null;
@Override
public void initialize(URL location, ResourceBundle resources) {
this.image.setPreserveRatio(true);
}
@FXML
private void uploadImage(ActionEvent Event) throws IOException, Exception{
selectedFile = fileChooser.showOpenDialog(null).getAbsolutePath();
System.out.println(selectedFile);
FXMLLoader loader = new FXMLLoader(getClass().getResource("ProgressBar.fxml"));
Parent root = (Parent) loader.load();
ProgressBarController pBarController = loader.getController();
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
image.setImage(pBarController.loadImage2(selectedFile));
}
}
//用于进度条弹出的JavaFX控制器
public class ProgressBarController implements Initializable{
@FXML
private ProgressBar pBar;
@FXML
private Label task;
RandomAccessFile raf;
TiffDecoder decoder;
BufferedImage bufferedImage;
Image image;
@Override
public void initialize(URL location, ResourceBundle resources) {
}
public Image loadImage2 (String filePath) throws InterruptedException, ExecutionException {
ExecutorService service = Executors.newFixedThreadPool(1);
Task<Image> task = new UploadTask(filePath);
pBar.progressProperty().bind(task.progressProperty());
this.task.textProperty().bind(task.messageProperty());
Thread thread = new Thread(task);
thread.start();
return task.get();
//NEED TO RETURN IMAGE back to previous controller somehow without interrupting the task
}
private class UploadTask extends Task<Image> {
private String filePath;
private RandomAccessFile raf;
private TiffDecoder decoder;
private BufferedImage bufferedImage;
private Image image;
public UploadTask(String filePath){
this.filePath = filePath;
}
@Override
protected Image call() throws Exception {
updateMessage("Loading file into memory");
generateRaf(filePath);
updateProgress(10, 100);
updateMessage("Decoding image format");
decodeTiff(raf);
updateProgress(30, 100);
updateMessage("Buffering image to stream");
bufferImage(decoder);
updateProgress(600, 100);
updateMessage("Converting to image");
image = convertImageToFXImage(bufferedImage);
updateProgress(90, 100);
updateMessage("Finished");
updateProgress(100, 100);
return image;
}
private void generateRaf(String filePath) throws FileNotFoundException{
this.raf = new RandomAccessFile(filePath, "r");
}
private void decodeTiff(RandomAccessFile raf) throws Exception{
this.decoder = new TiffDecoder(raf);
}
private void bufferImage(TiffDecoder decoder) throws Exception{
bufferedImage = decoder.read();
}
private Image convertImageToFXImage(BufferedImage bufferedImage){
return SwingFXUtils.toFXImage(bufferedImage, null);
}
@Override
protected void failed() {
System.out.println("Upload failed");
}
@Override
protected void succeeded() {
System.out.println("Upload succeeded");
}
}
}
答案 0 :(得分:1)
对您的代码进行相当简单的更改将允许您执行此操作:
public class ProgressBarController {
// ...
public ReadOnlyObjectProperty<Image> loadImage2 (String filePath) throws InterruptedException, ExecutionException {
ExecutorService service = Executors.newFixedThreadPool(1);
Task<Image> task = new UploadTask(filePath);
pBar.progressProperty().bind(task.progressProperty());
this.task.textProperty().bind(task.messageProperty());
Thread thread = new Thread(task);
thread.start();
return task.valueProperty();
}
// ...
}
然后简单地
@FXML
private void uploadImage(ActionEvent Event) throws IOException, Exception{
selectedFile = fileChooser.showOpenDialog(null).getAbsolutePath();
System.out.println(selectedFile);
FXMLLoader loader = new FXMLLoader(getClass().getResource("ProgressBar.fxml"));
Parent root = (Parent) loader.load();
ProgressBarController pBarController = loader.getController();
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
image.imageProperty().bind(pBarController.loadImage2(selectedFile));
}
但我认为你可能想要重构这一点,以便正确区分问题(单一责任原则)。基本上,您的问题出现是因为您无权访问图像视图的访问权限;这是因为进度条控制器(错误地)封装了任务。您的进度条控制器不应该真正负责加载图像(再次:单一责任原则);你可以让它从进度条中公开progress属性。类似的东西:
public class ProgressBarController {
@FXML
private ProgressBar pBar;
@FXML
private Label task;
public DoubleProperty progressProperty() {
return pBar.progressProperty();
}
public StringProperty textProperty() {
return task.textProperty();
}
}
将UploadTask
提升为独立类:
public class UploadTask extends Task<Image> {
private File file ;
private BufferedImage bufferedImage ;
public UploadTask(File file){
this.file = file;
}
@Override
protected Image call() throws Exception {
updateMessage("Loading file into memory");
RandomAccessFile raf = generateRaf(file);
updateProgress(10, 100);
updateMessage("Decoding image format");
TiffDecoder decoder = decodeTiff(raf);
updateProgress(30, 100);
updateMessage("Buffering image to stream");
BufferedImage bufferedImage = bufferImage(decoder);
updateProgress(600, 100);
updateMessage("Converting to image");
Image image = convertImageToFXImage(bufferedImage);
updateProgress(90, 100);
updateMessage("Finished");
updateProgress(100, 100);
return image;
}
private RandomAccessFile generateRaf(File file) throws FileNotFoundException{
return new RandomAccessFile(file, "r");
}
private TiffDecoder decodeTiff(RandomAccessFile raf) throws Exception{
return new TiffDecoder(raf);
}
private BufferedImage bufferImage(TiffDecoder decoder) throws Exception{
return decoder.read();
}
private Image convertImageToFXImage(BufferedImage bufferedImage){
return SwingFXUtils.toFXImage(bufferedImage, null);
}
@Override
protected void failed() {
System.out.println("Upload failed");
}
@Override
protected void succeeded() {
System.out.println("Upload succeeded");
}
}
现在做
public class JavaCVTestController {
@FXML
private ImageView image;
@FXML
private Button btnUpload;
private ExecutorService exec = Executors.newCachedThreadPool();
private FileChooser fileChooser = new FileChooser();
// can't you do this in the FXML?
public void initialize(URL location, ResourceBundle resources) {
this.image.setPreserveRatio(true);
}
@FXML
private void uploadImage(ActionEvent Event) throws IOException, Exception{
File selectedFile = fileChooser.showOpenDialog(image.getScene().getWindow());
FXMLLoader loader = new FXMLLoader(getClass().getResource("ProgressBar.fxml"));
Parent root = (Parent) loader.load();
ProgressBarController pBarController = loader.getController();
Task<Image> uploadTask = new UploadTask(selectedFile);
pBarController.progressProperty().bind(uploadTask.progressProperty());
pBarController.textProperty().bind(uploadTask.messageProperty());
uploadTask.setOnSucceeded(e -> image.setImage(uploadTask.getValue()));
Stage stage = new Stage();
stage.setScene(new Scene(root));
stage.show();
exec.execute(uploadTask);
}
}
请注意,我清理了常见或园艺最佳实践的代码的各个方面。