2015-11-23 2 views
1

Я новичок в JavaFX, поэтому, пожалуйста, простите noobishness.JavaFX: передача изображения, извлеченного из FileChooser, запускаемого из представления Root в объект ImageView во вложенном виде

Так что я делаю Picture Viewer. Это моя первая разработка GUI с парадигмой MVC, поэтому я не очень уверен, что я делаю.

Что я пытаюсь выполнить:

Это просто обычный для просмотра изображений. Как и ваша стандартная программа Windows, которая открывается, когда вы хотите посмотреть картинку.

Что я сделал:

Так что я в настоящее время есть 2 просмотры:

  1. мнение о Root.fxml, который является BorderPane только с MenuBar на вершине с MenuItem "Открыть", что запускает FileChooser и устанавливает переменную currentAmage MainApp.java независимо от того, что пользователь выбрал.

  2. Вложенные внутри (root.setCenter) у меня есть изображение ImageViewer.fxml, , которое является AnchorPane, которое содержит только ImageView.

Я на 100% уверен, что с моим FXML нет ничего плохого, и что все контроллеры и переменные связаны правильно. Это должно быть проблемой в MainApp или контроллерах.

Я понятия не имею, как передать изображение с RootViewController на ImageViewerController. Когда я пытаюсь инициализировать прослушиватель mainApp.currentImage в инициализаторе ImageViewerController, я получаю исключение NullPointerException. Если я поместил его в метод setMainApp, он ничего не сделает. Вот мой код:

Кодекс:

MainApp.java

import sample.model.MyImage; 
import samlple.view.ImageViewerController; 
import sample.view.RootController; 
import javafx.application.Application; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Scene; 
import javafx.scene.layout.AnchorPane; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.FileChooser; 
import javafx.stage.Stage; 
import java.io.File; 
import java.io.IOException; 

public class MainApp extends Application { 
    final static File img = new File("C:\\test\\1.png"); // test initial image loading 
    private Stage primaryStage; 
    private BorderPane rootLayout; 
    private MyImage currentImage = new MyImage(img); 

    public MainApp() { 
    } 

    public MyImage getCurrentImage(){ 
     return this.currentImage; 
    } 
    public void setCurrentImage(MyImage myImage){ 
     currentImage = myImage; 
    } 

    public void start(Stage primaryStage) throws Exception{ 
     this.primaryStage = primaryStage; 
     this.primaryStage.setTitle("Hi"); 

     initRootLayout(); 
     showImageViewer(); 
    } 



    /** 
    * Initializes the root layout. 
    */ 
    public void initRootLayout() { 
     try { 
      // Load root layout from fxml file. 
      FXMLLoader loader = new FXMLLoader(); 
      loader.setLocation(MainApp.class.getResource("view/Root.fxml")); 
      rootLayout = loader.load(); 

      // Show the scene containing the root layout. 
      Scene scene = new Scene(rootLayout); 
      primaryStage.setScene(scene); 

      // Giving the controller access to the main app. 
      RootController controller = loader.getController(); 
      controller.setMainApp(this); 

      primaryStage.show(); 

     } catch (IOException e) { 
      e.printStackTrace(); 
      System.err.println("Root layout loading error."); 
     } 
    } 

    /** 
    * Shows the ImageViewer inside the root layout. 
    */ 
    public void showImageViewer() { 
     try { 
      // Load ImageViewer. 
      FXMLLoader loader = new FXMLLoader(); 
      loader.setLocation(MainApp.class.getResource("view/ImageViewer.fxml")); 
      AnchorPane imageViewer = loader.load(); 

      // Set the ImageViewer into the center of root layout. 
      rootLayout.setCenter(imageViewer); 

      // Giving the controller access to the main app. 
      ImageViewerController controller = loader.getController(); 
      controller.setMainApp(this); 

     } catch (IOException e) { 
      e.printStackTrace(); 
      System.err.println("ImageViewer layout loading error."); 
     } 
    } 

    /** 
    * Called when user clicks the "Open" menu item 
    */ 

    public void menuOpenImageFile() { 
     FileChooser fileChooser = new FileChooser(); 

     //Set extension filter 
     FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("Image types (*.jpg; *.gif; *.bmp; *.png)", "*.jpg", "*.png", "*.bmp", "*.gif"); 
     fileChooser.getExtensionFilters().add(extFilter); 

     //Show save file dialog 
     File imageFile = fileChooser.showOpenDialog(primaryStage); 
     MyImage myImageToSetAsCurrent = new MyImage(imageFile); 
     setCurrentImage(myImageToSetAsCurrent); 
    } 

    /** 
    * Returns the main stage. 
    * @return 
    */ 
    public Stage getPrimaryStage() { 
     return primaryStage; 
    } 

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

MyImage.java (класс имиджевая модель для хранения свойств):

package sample.model; 


import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.scene.image.Image; 

import java.io.File; 

public class MyImage { 
    private final ObjectProperty<File> imageFile; 
    private final ObjectProperty<Image> image; 

    public MyImage(){ 
     this(null); 
    } 

    public MyImage(File imageFile) { 
     this.imageFile = new SimpleObjectProperty<>(imageFile); 
     this.image = new SimpleObjectProperty<>(new Image("file:" + imageFile.toString())); 
    } 

    public File getImageFile() { 
     return imageFile.get(); 
    } 

    public ObjectProperty<File> imageFileProperty() { 
     return imageFile; 
    } 

    public void setImageFile(File myImageFile) { 
     this.imageFile.set(myImageFile); 
    } 

    public Image getImage() { 
     return image.get(); 
    } 

    public ObjectProperty<Image> imageProperty() { 
     return image; 
    } 

    public void setImage(Image myImage) { 
     this.image.set(myImage); 
    } 
} 

RootController.java

import samlple.MainApp; 
import javafx.fxml.FXML; 
import javafx.scene.control.MenuItem; 


public class RootController { 
    @FXML 
    private MenuItem open; 

    // Reference to the main application. 
    private MainApp mainApp; 

    /** 
    * The constructor. 
    * The constructor is called before the initialize() method. 
    */ 
    public RootController() { 
    } 

    /** 
    * Initializes the controller class. This method is automatically called 
    * after the fxml file has been loaded. 
    */ 
    @FXML 
    private void initialize() { 
    } 

    @FXML 
    private void openImageFile() { 
     mainApp.menuOpenImageFile(); 
    } 

    /** 
    * Is called by the main application to give a reference back to itself. 
    * 
    */ 
    public void setMainApp(MainApp mainApp) { 
     this.mainApp = mainApp; 

    } 
} 

ImageViewerController.java

import sample.MainApp; 
import javafx.fxml.FXML; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 


public class ImageViewerController { 
    @FXML 
    private ImageView imageView; 

    // Reference to the main application. 
    private MainApp mainApp; 

    /** 
    * The constructor. 
    * The constructor is called before the initialize() method. 
    */ 
    public ImageViewerController() { 
    } 

    /** 
    * Initializes the controller class. This method is automatically called 
    * after the fxml file has been loaded. 
    */ 
    @FXML 
    private void initialize() { 
     mainApp.getCurrentImage().imageProperty().addListener(((observable, oldValue, newValue) -> imageView.setImage(newValue))); //This keeps throwing NullPointerException! 
    } 

    /** 
    * Is called by the main application to give a reference back to itself. 
    * 
    */ 
    public void setMainApp(MainApp mainApp) { 
     this.mainApp = mainApp; 

     imageView.setImage(mainApp.getCurrentImage().imageProperty().get()); 
    } 
} 

ответ

1

При инициализации все, то ImageViewController наблюдает за imageProperty из текущегоMyImage объекта основного приложения. Когда вы выбираете новое изображение из своего меню, вы устанавливаете новый объект MyImage в главном приложении: однако ImageViewController по-прежнему наблюдает за imageProperty в исходном MyImage объекте. То, что imageProperty никогда не меняется.

Вы, вероятно, хотите сделать currentImage окончательным, и просто изменить свойство:

public class MainApp extends Application { 
    final static File img = new File("C:\\test\\1.png"); // test initial image loading 
    private Stage primaryStage; 
    private BorderPane rootLayout; 
    private final MyImage currentImage = new MyImage(img); 

    public MainApp() { 
    } 

    public MyImage getCurrentImage(){ 
     return this.currentImage; 
    } 
    // public void setCurrentImage(MyImage myImage){ 
    //  currentImage = myImage; 
    // } 

    // ... 

    public void menuOpenImageFile() { 
     FileChooser fileChooser = new FileChooser(); 

     //Set extension filter 
     FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("Image types (*.jpg; *.gif; *.bmp; *.png)", "*.jpg", "*.png", "*.bmp", "*.gif"); 
     fileChooser.getExtensionFilters().add(extFilter); 

     //Show save file dialog 
     File imageFile = fileChooser.showOpenDialog(primaryStage); 
     currentImage.setImageFile(imageFile); 
     currentImage.setImage(new Image(imageFile.toURI().toString())); 
    } 

} 

Примечание вас есть еще одна ошибка: вы звоните mainApp.getCurrentImage() в initialize() методе контроллера, который обязательно называется, прежде чем попасть возможность установить основное приложение. Вы должны зарегистрировать слушателя в методе setMainApp(...):

import sample.MainApp; 
import javafx.fxml.FXML; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 


public class ImageViewerController { 
    @FXML 
    private ImageView imageView; 

    // Reference to the main application. 
    private MainApp mainApp; 


    /** 
    * Is called by the main application to give a reference back to itself. 
    * 
    */ 
    public void setMainApp(MainApp mainApp) { 
     this.mainApp = mainApp; 

     imageView.setImage(mainApp.getCurrentImage().imageProperty().get()); 

     mainApp.getCurrentImage().imageProperty().addListener(((observable, oldValue, newValue) -> imageView.setImage(newValue))); 
    } 
}