0

I am a new javafx user. I'm trying to create a basic application but I'm having some problems. I try, when closing a sub-window, to change the icons of my buttons by changing the Image inside my ImageView.

I have my main window :

<AnchorPane id="AnchorPane" prefHeight="651.0" prefWidth="823.0" 
   xmlns="http://javafx.com/javafx/10.0.1" 
   xmlns:fx="http://javafx.com/fxml/1" 
     fx:controller="amzevent.UI.FXMLMainUI">
    <children>
      <ScrollPane layoutX="14.0" layoutY="110.0" prefHeight="526.0" 
       prefWidth="796.0" />
        <ToolBar layoutX="14.0" layoutY="14.0" prefHeight="46.0" 
         prefWidth="796.0">
          <items>
            <Button minHeight="40.0" minWidth="40.0" mnemonicParsing="false" 
             prefHeight="34.0" prefWidth="40.0">
           <graphic>
              <ImageView fitHeight="30.0" fitWidth="30.0" 
               pickOnBounds="true" preserveRatio="true" 
               fx:id="bouton_retour">
                 <image>
                    <Image url="@../../resources/undo (1).png"   />
                 </image>
              </ImageView>
           </graphic>
           <tooltip>
              <Tooltip text="Annuler" />
           </tooltip>
        </Button>
     </items>
  </ToolBar>
  </children>
  </AnchorPane>

and the controller :

public class FXMLMainUI extends Controlleur implements Initializable {



@FXML 
private ImageView bouton_retour; 

@FXML
protected void ClickBoutonCreerSalle(ActionEvent event) {
    System.out.println("JavaMainUI : Click bouton créer salle");
    try {

        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("FXMLCreerSalle.fxml"));
        Parent root1 = (Parent) fxmlLoader.load();
        this.salle = new Stage();
        this.salle.setTitle("Nouvelle Salle");
        this.salle.setScene(new Scene(root1));
        this.salle.show();
    } catch (IOException ex) {
        Logger.getLogger(FXMLMainUI.class.getName()).log(Level.SEVERE, null, ex);
    }
    /*FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLMainUI.fxml"));
    try {
        Parent root = loader.load();
    } catch (IOException ex) {
        Logger.getLogger(FXMLMainUI.class.getName()).log(Level.SEVERE, null, ex);
    }*/
}


protected void CreerSalle(String nom_salle, int largeur_salle, int profondeur_salle) {
    super.CreerSalle(nom_salle, largeur_salle, profondeur_salle);
    System.out.println("JavaMainUI : Créer salle");
}


@FXML
protected void MettreBoutonCliquables() {
    System.out.println("JavaMainUI : MettreBoutonCliquables");
    Image img = new Image("resources/undo.png");
    this.bouton_retour.setImage(img);
}

@Override
public void initialize(URL url, ResourceBundle rb) {
    assert this.bouton_retour != null : "fx:id=\"bouton_retour\" was null check your FXML "; 
    this.bouton_retour = new ImageView();
    System.out.println("JavaMainUI : Initialize ");
}    
public FXMLMainUI()
{
}

}

the other view :

   <AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" 
   xmlns="http://javafx.com/javafx/10.0.1" 
   xmlns:fx="http://javafx.com/fxml/1" 
   fx:controller="amzevent.UI.FXMLCreerSalle">
    <children>
    <Button layoutX="486.0" layoutY="326.0" mnemonicParsing="false" 
       text="Button" onAction="#SoumettreNouvelleSalle" />
    <Label layoutX="118.0" layoutY="132.0" prefHeight="17.0" 
     prefWidth="59.0" text="Nom" />
     <Label layoutX="116.0" layoutY="183.0" prefHeight="17.0" 
   prefWidth="65.0" text="Largeur" />
    <TextField layoutX="208.0" layoutY="128.0" fx:id="field_nom"/>
    <TextField layoutX="208.0" layoutY="179.0" fx:id="field_largeur"/>
    <TextField layoutX="208.0" layoutY="233.0" fx:id="field_profondeur"/>
    <Label layoutX="116.0" layoutY="237.0" prefHeight="17.0" 
     prefWidth="65.0" 
  text="Profondeur" />
    <Label layoutX="363.0" layoutY="183.0" text="en metre" />
    <Label layoutX="363.0" layoutY="237.0" text="en metre" />
  </children>
  </AnchorPane> 

the other controller :

  public class FXMLCreerSalle extends FXMLMainUI implements Initializable {

@FXML
private TextField field_nom;

@FXML
private TextField field_largeur;

@FXML
private TextField field_profondeur;



@FXML
protected void SoumettreNouvelleSalle(ActionEvent event) {
    System.out.println("JavaMainUI : Soumettre nouvelle salle");
    if (!this.field_nom.getText().equals("") && !this.field_largeur.getText().equals("") && !this.field_profondeur.getText().equals("")) {
        String nom_salle = this.field_nom.getText();
        int largeur_salle = 0;
        int profondeur_salle = 0;
        try {
            largeur_salle = Integer.parseInt(this.field_largeur.getText());
            profondeur_salle = Integer.parseInt(this.field_profondeur.getText());
        }  catch (NumberFormatException e) {
            System.out.println("JavaMainUI : largeur et profondeur doivent etre des nombre entiers"); 
            return;
        }
        System.out.println("JavaMainUI : " + nom_salle); 
        System.out.println("JavaMainUI : " + largeur_salle);
        System.out.println("JavaMainUI : " + profondeur_salle);
        Stage stage = (Stage) this.field_nom.getScene().getWindow();
        // do what you have to do
        stage.close();
        super.CreerSalle(nom_salle, largeur_salle, profondeur_salle);
        super.MettreBoutonCliquables();
    }
}

@Override
public void initialize(URL url, ResourceBundle rb) {

    // TODO
    //retour_couleur = new Image("resources/undo.png");
    //this.retour = new ImageView();
    //this.boutton_retour = new ImageView();
}    

}

when the sub windows closes, it calls super.MettreBoutonCliquables(); to change the Image of the ImageView with a new source.

When i run my program everything works fine until this.bouton_retour.setImage(img); -> java.lang.NullPointerException

I tried to add the followed lines to reload my fxml main file but didn't change anything. FXMLLoader loader = new FXMLLoader(getClass().getResource("/amzevent/UI/FXMLMainUI.fxml")); Parent root = loader.load();

In my initialize funtion the bouton_retour is not null.

I have no idea how to fix this, If anyone's ever had this kind of problem before, I'm a taker.

maluss
  • 602
  • 1
  • 8
  • 14
  • *"when the sub windows closes, it calls super.MettreButonCliquables();"* Subwindow? How exactly is this called? In the fxml you specify the controller using `fx:controller`. Creating a subclass of `FXMLMainUI` does not "magically" connect an instance of this class with the instance of the subclass. The instance gets injected if and only if the subclass is used with a fxml also containing a `` element with `fx:id="bouton_retour"`. – fabian Nov 10 '18 at 21:10
  • the sub window is the one i created like :` FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("FXMLCreerSalle.fxml")); Parent root1 = (Parent) fxmlLoader.load(); this.salle = new Stage(); this.salle.setTitle("Nouvelle Salle"); this.salle.setScene(new Scene(root1));` the FXMLCreerSalle.fxml is a different fxml who holds its own controller that extends from FXMLMainUI . So i call my method like : super.MettreButonCliquables(); – maluss Nov 10 '18 at 21:16
  • Unless you've got a `` element in `FXMLCreerSalle.fxml`, there are 2 instances of `FXMLMainUI` (or a subclass) created here: one responsible for the `ImageView` and one for whatever is using `MettreButonCliquables`. Subclassing won't help you establish a connection between 2 controllers. You probably should pass `FXMLMainUI` to the other controller and use the instance passed to invoke the method or communicate via the model. (about passing the controller, see https://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml) – fabian Nov 10 '18 at 23:01
  • I edited my post with the other controller and the other view, i don't understand why there would be 2 instances of FXMLMainUI ? – maluss Nov 10 '18 at 23:26
  • Every time you use `FXMLLoader` to load a fxml file containing the `fx:controller` attribute, it creates a ***new instance*** of the class specified by the value of the attribute. Loading the first fxml an instance of `FXMLMainUI` is created and loading the second fxml an instance of `FXMLCreerSalle` is created. There is no relationship between those instances except for sharing the same (super)type. Elements created while loading an fxml are only injected to the controller created when loading the fxml in question (assuming the controller is created based on `fx:controller`). – fabian Nov 10 '18 at 23:48
  • Ok ! but I can't see why in my `FXMLMainUI` controller, i can't use the button_retour ImageView ? I can use it in my Initialize function, so, I assume that the `FXMLMainUI` controller is well connected to the good fxml file. Yes the controller is based on `fx:controller`. – maluss Nov 10 '18 at 23:58

0 Answers0