1

私はJavaFXを初めて使用するので、初心者を許してください。

だから私は画像ビューアを作っています。MVC パラダイムを使用して GUI を設計するのはこれが初めてなので、何をしているのかよくわかりません。

私が達成しようとしていること:

普通の画像ビューアです。写真を見たいときに開く標準の Windows プログラムのように。

私がしたこと:

だから私は現在2つのビューを持っています:

  1. Root.fxml ビュー。これは、FileChooser をトリガーし、MainApp.java の currentImage 変数をユーザーが選択したものに設定する MenuItem "Open" を持つ MenuBar だけが上にある BorderPane です。

  2. (root.setCenter) の内部にネストされており、ImageViewer.fxml ビューがあります。これは、ImageView のみを含む AnchorPane です。

FXML に問題はなく、すべてのコントローラーと変数が正しくバインドされていることを 100% 確信しています。これは、MainApp またはコントローラーの問題である必要があります。

Image を RootViewController から ImageViewerController に渡す方法がわかりません。ImageViewerController イニシャライザーで mainApp.currentImage のリスナーを初期化しようとすると、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());
    }
}
4

1 に答える 1

1

すべてを初期化すると、はメイン アプリの現在のオブジェクトImageViewControllerを監視します。メニューから新しい画像を選択すると、メイン アプリで新しいオブジェクトが設定されます。ただし、はまだ元のオブジェクトでを監視しています。それは決して変わらない。imageProperty MyImageMyImageImageViewControllerimagePropertyMyImageimageProperty

おそらくcurrentImagefinal にして、プロパティを変更するだけです。

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)));
    }
}
于 2015-11-23T13:31:53.930 に答える