Kylar Stern
Kylar Stern

Reputation: 77

JavaFX imageview setImage returns null and doesn't work

I'm trying to set the imageView img_1 with the 1st image of my database. For some reason it doesn't work and I can't figure out why. The method loadImage is called in a different class.

public class MainMenuController implements Initializable 
{
    /**
     * Initializes the controller class.
    */
    @Override
       public void initialize(URL url, ResourceBundle rb) {
       // TODO
    }

    //DBConnect dbimg = new DBConnect();
    @FXML
    private void openSecondWindow(ActionEvent event) {
    try {
        GUIController ctrl = new GUIController();
        ctrl.loadImg();
        //ctrl.firstScreen();
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

I also tried setting the image in a separate method, but I need it called at the same time as the whole stage scene etc is created, even after calling it like that from a second method it doesn't work.

Here is the class holding the setImage

@FXML
private ImageView img_1;

@FXML
private AnchorPane stck1;

ResultSet rs = null;
Statement stmnt = null;
Connection con = null;

String host = "jdbc:derby://localhost:1527/InteractiveGameDatabase;allowMultiQueries=true";
String unm = "Kylar";
String pswrd = "aswzxc";

BufferedImage imgt = null;
InputStream fis = null;
int xcoord;
int ycoord;
int newcoord;

String SQL = "SELECT*FROM location";


public ImageView loadImg() throws IOException {

    try {

        Stage stage = new Stage();
           AnchorPane stck1 = ((AnchorPane) FXMLLoader.load(InteractiveFictionGame2.class.getResource("GUI.fxml")));

        stck1.getChildren().addAll();
        Scene scene = new Scene(stck1);
        stage.setTitle("Interactive Fiction Game");
        stage.setScene(scene);
        stage.sizeToScene();
        stage.show();

        String SQL = "SELECT*FROM location";
        con = DriverManager.getConnection(host, unm, pswrd);
        stmnt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
        rs = stmnt.executeQuery(SQL);
        rs.next();
        fis = rs.getBinaryStream(4);
        imgt = javax.imageio.ImageIO.read(fis);
        Image newImg = SwingFXUtils.toFXImage(imgt, null);

Setting the image gives me a value null when called, the default value for imageview is null but I am actually loading an image even checked with newImg.isError() - which came back as "image loaded = true" . The next method call on button click is to set the imageView again and that works.

        img_1.setImage(newImg)
        rs.close();
        stmnt.close();
        con.close();
    } catch (SQLException e) {
        System.out.println(e.getMessage());
    }
    return img_1;
}

This is the second method which works

public ImageView goNorth() throws IOException { try {

        String SQLNorth = "select vista from location where ycoordinate = ? and xcoordinate = ?";
        System.out.println("coords are" + xcoord + ycoord);
        newcoord = ycoord + 1;
        System.out.println("New coord x and y are" + xcoord + newcoord);

        con = DriverManager.getConnection(host, unm, pswrd);
        stmnt2 = con.prepareStatement(SQLNorth);
        stmnt2.setInt(1, newcoord);
        stmnt2.setInt(2, xcoord);
        rs = stmnt2.executeQuery();
        rs.next();
        fis2 = rs.getBinaryStream(1);
        imgt2 = javax.imageio.ImageIO.read(fis2);
        Image newImg = SwingFXUtils.toFXImage(imgt2, null);
        img_1.setImage(newImg);


    } catch (SQLException e) {
        System.out.println(e.getMessage());
    }
    return img_1;
}

I don't understand exactly how am I to fetch the controller the whole class is the controller ?! What is the correct way to do it, I was just looking at the getClass() method and I can't understand am I calling the getClass on a class or on the whole package and in the path specifying which class I'm setting as the controller ?

@FXML
 private void openSecondWindow(ActionEvent event) {
        try {
            FXMLLoader loader;
            loader = new FXMLLoader(GUIController.class.getClass().getResource("GUI.fxml").toExternalForm());
            Parent parent =loader.load();
            GUIController ctrl = loader.getController();
            ctrl.loadImg();
            //ctrl.firstScreen();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

Upvotes: 0

Views: 3485

Answers (2)

Tomasz Mularczyk
Tomasz Mularczyk

Reputation: 36179

I think this would be more proper way if your goal is to open new window with new scene. First, make the new stage, load fxml and set the scene in MainMenuController. This will keep things separate.

@FXML
 private void openSecondWindow(ActionEvent event) {
        try {
            Stage stage = new Stage();
            FXMLLoader loader = new FXMLLoader(getClass().getResource("GUI.fxml"));
            Parent parent = loader.load();
            stage.setTitle("Interactive Fiction Game");      
            stage.setScene(new Scene(parent));
            GUIController ctrl = loader.getController();
            ctrl.loadImg();
            //ctrl.firstScreen();

            stage.show();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }

In this code I see you are overriting stck1 when there is no need to, stck1 is already initialized variable.

public ImageView loadImg() throws IOException {

    try {


        String SQL = "SELECT*FROM location";
        con = DriverManager.getConnection(host, unm, pswrd);
        stmnt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
        rs = stmnt.executeQuery(SQL);
        rs.next();
        fis = rs.getBinaryStream(4);
        imgt = javax.imageio.ImageIO.read(fis);
        Image newImg = SwingFXUtils.toFXImage(imgt, null);

Upvotes: 0

ItachiUchiha
ItachiUchiha

Reputation: 36722

The problem is GUIController ctrl = new GUIController();

The problem with the first approach is that fields annotated with @FXML only gets instantiated when you load the fxml. Initializing controller with new doesn't do it.

Instead of initializing a controller, fetch it from the FXMLLoader

FMLLoader loader = new FXMLLoader(getClass().getResource("SOME_PATH").toExternalForm());
Parent parent = loader.load();
GUIController ctrl = loader.getController();

EDIT - Answers to further questions

I can't understand am I calling the getClass on a class

You don't have to. You either use

getClass().getResource("SOME_PATH")

or you use

GUIController.class.getResource("SOME_PATH")

both will give you the same result.

in the path specifying which class I'm setting as the controller

Since you haven't added any fxml in your question and I will make a guess and say that GUI.fxml just looks as:

<AnchorPane fx:id="vbox" prefHeight="117.0" prefWidth="285.0" xmlns="http://javafx.com/javafx/8" 
        xmlns:fx="http://javafx.com/fxml/1" fx:controller="package.GUIController">
    <children>
        ...
    </children>
</AnchorPane>

Your controller is the class specified in fx:controller="package.GUIController" and loader.getController() will return an instance of the GUIController class.

Upvotes: 1

Related Questions