[英]Return an image from a thread
我基本上是想讓用戶從FileChooser輸入文件路徑,然后將其傳遞給任務,以便可以對其進行操作並將其轉換為可以在JavaFX ImageView中顯示的圖像。 我的問題是,我的任務正在線程中運行,而我的方法要等到線程完成執行以返回所需的圖像后,才能執行。 有什么辦法可以做到這一點?
//帶有fileChooser的JavaFX Controller
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 Controller
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");
}
}
}
對代碼進行的相當簡單的更改將允許您執行以下操作:
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);
}
}
請注意,我清理了代碼的各個方面,以實現常見或最佳實踐。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.