2

So I am working on a javaFX application and I want to create multiple <ImageView> using for loop!

Is that possible to make for/foreach loop in a .fxml file ?

If yes , then how ?

Also i have another question! how to send data from the controller to sample.fxml file ? for exemple i want to send a table form controller.java to sample.fxml file and use that table+for loop to make <ImageView> in the fxml file!

Note: I am using the fxml to display the image because I am using those images as buttons.

Here is the code of sample.fxml :

<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<GridPane fx:controller="sample.Controller"
          xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">


    <ImageView fitHeight="120" fitWidth="120" fx:id="panda" GridPane.columnIndex="0" GridPane.rowIndex="0" onMousePressed="#mousePressed">
        <image>
            <Image  url="@pics/panda.png">

            </Image>
        </image>
    </ImageView>

</GridPane>

Here is the code of Controller.java :

package sample;

import javafx.scene.input.MouseEvent;
import javafx.scene.media.AudioClip;

public class Controller {

    public void play_audio()
    {
        AudioClip sound = new AudioClip(this.getClass().getResource("voices/panda.mp3").toString());
        sound.play();
    }

    public void mousePressed() {
        play_audio();
    }
}

Code of Main.java :

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));

        primaryStage.setTitle("Animal Sound");


        Scene scene = new Scene(root, 790, 675);
        scene.getStylesheets().add("sample/styles.css");
        primaryStage.setScene(scene);

        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}
Dhia Djobbi
  • 1,176
  • 2
  • 15
  • 35
  • I'm not clear why do you want to do it in the fxml file? Why not just populate the unknown elements from the controller? – matt Apr 18 '20 at 07:58
  • 1
    I am using the fxml file to use those images images as buttons. – Dhia Djobbi Apr 18 '20 at 08:03
  • https://stackoverflow.com/a/14190310/2067492 they talk about passing parameters. I haven't found anything on flow control, so I think you'll want to do your work from the controller. – matt Apr 18 '20 at 08:29
  • unrelated: java naming conventions! you are nearly following them, except for the underscores - use camel-case instead – kleopatra Apr 18 '20 at 09:59

1 Answers1

5

I don't think flow control is manageable in an fxml file. Also you don't really pass arguments to an fxml file.

I think you've separated this well, and a little more paring down should get it to work. I would recommend to specify the sounds and the images from the controller. So I would make the controller for each button.

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

public class AudioButtonController {
    String sound;
    @FXML
    ImageView image;
    public void setAudioLocation(String resourcePath){
        sound = resourcePath;
    }
    public void setImageLocation(String img){
        image.setImage( new Image( img ) );
    }
    public void mousePressed() {
        System.out.println(sound);
    }
}

Now your fxml for each button can be.

<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<HBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.AudioButtonController">
  <ImageView 
      fitHeight="120" fitWidth="120" fx:id="image" onMousePressed="#mousePressed">
  </ImageView>
</HBox>

Here is an example main class that starts up and loads 2 audio buttons, but it could be used to load N buttons.

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class Main extends Application{

@Override
    public void start(Stage primaryStage) throws Exception{
        FlowPane root = new FlowPane(5, 5);

        primaryStage.setTitle("Animal Sound");

        String[] imgs = { "https://conserveblog.files.wordpress.com/2016/05/flagship-panda-thumbnail.jpeg?w=188", "http://news.bbc.co.uk/media/images/38625000/jpg/_38625095_021223panda150.jpg" };
        for(String img: imgs){
            FXMLLoader loader = new FXMLLoader( getClass().getResource("audio_button.fxml") );
            Parent audioButton = loader.load();
            AudioButtonController abc = loader.getController();
            abc.setAudioLocation("not supported");
            abc.setImageLocation(img);
            root.getChildren().add(audioButton);
        }



        Scene scene = new Scene(root, 790, 675);
        primaryStage.setScene(scene);

        primaryStage.show();
    }

}

This is a bit cumbersome for this example. If your button had more layout controls to it, and your outer layout was more complicated, then this could save some time.

matt
  • 10,892
  • 3
  • 22
  • 34
  • I cant manualy create fxml for each buttons I dont know how manny button i have. Thats why i want to work with for loop in fxml( in the controlleur i am going to read the numbers of buttons from a file for exemple 20 button and i want to use For in fxml file to generate them ! – Dhia Djobbi Apr 18 '20 at 10:16
  • 1
    @Dhia Not everything can be done in FXML. The more dynamic parts of your view should be implemented in code. You can of course mix this with FXML files by implementing the dynamic parts in the controller. – Slaw Apr 18 '20 at 10:23
  • I want to make the columIndex and rowindex dynamic in the FXML file so the buttons doesnt get on top of each other ! I wanna make for exemple Gridpane.rowIndex=i in FXML ! I is a variable created in the contolleur ! How? Also wanted to say sorry cuz i am new in javafx/fxml :/ – Dhia Djobbi Apr 18 '20 at 10:28
  • @DhiaDjobbi I have updated the answer to now be a complete self contained example. If you run that you will get a window with 2 different images. I used 1 fxml file loaded it for as many times as I need, and each time it got added to the layout. – matt Apr 18 '20 at 11:11
  • 1
    @DhiaDjobbi you changed your comment quite a bit, you don't need to specify the rowIndex in your fxml, when you add the component to your scene, via the controller and you know 'i' you tell the gridpane. Only put fixed data in the fxml file. Then modify from your controller. – matt Apr 18 '20 at 12:21