Question

I have attempted multiple times to add buttons to a FlowPane via a for loop. However, when the loop is run in my start method, the buttons fail to be rendered. I have proivided my code for the controller class and the fxml layout file I have used.

Here is my code for the controller:

package dimension.audio.player;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.ResourceBundle;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableMap;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBuilder;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tooltip;
import javafx.scene.image.Image;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.media.Media;
import javafx.stage.Stage;

public class MediaViewer extends Application{
    ArrayList<String> list;

    File directory;

    Button lab;

    ArrayList<String> tagged = new ArrayList<String>();

    @FXML
    BorderPane layout = new BorderPane();

    @FXML
    FlowPane butLayout = new FlowPane(Orientation.HORIZONTAL);

    @FXML
    GridPane searchLayout;

    @SuppressWarnings("rawtypes")
    ObservableMap map;

    static Stage stage;
    static Scene scene;

    public void start(final Stage stage) throws Exception {
    MediaViewer.stage = stage;
    Parent root = FXMLLoader.load(new URL(this.getClass().getResource("library.fxml").toExternalForm()));

    if (MainController.getMedia() != null) {
        list = organizeDirectory(new File(MainController.getMedia().getSource()).getParentFile(), "mp3");
    } else {
        list = organizeDirectory(new File(System.getProperty("user.home") + "/Music/"), "mp3");
    }
    stage.setTitle("Library - " + directory.getAbsolutePath());
    stage.setResizable(false);
    scene = new Scene(root);
    addListItems(butLayout, stage, scene);
    }

    public ArrayList<String> organizeDirectory(File file, final String extension) {
    directory = file;
    if (!file.getName().contains("http")) {
        final ArrayList<String> filtered = new ArrayList<String>();
        File[] fileList = file.listFiles();
        if (fileList != null) {
        Path path = Paths.get(file.getAbsolutePath());
        try {
            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
                return FileVisitResult.CONTINUE;
            }

            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                if (file.getFileName().toString().endsWith(extension)) {
                filtered.add(file.toString());
                }
                return FileVisitResult.CONTINUE;
            }

            public FileVisitResult visitFileFailed(Path file, IOException e) {
                return FileVisitResult.CONTINUE;
            }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filtered;
        } else {
        return null;
        }
    } else {
        return null;
    }

    }

    public void addListItems(final Pane layout, final Stage stage, final Scene scene) {
    ArrayList<Node> but = new ArrayList<Node>();
    if (list != null) {
        for (final String s : list) {
        final String[] sList = s.split("\\\\");
        System.out.println(sList[sList.length - 1]);
        lab = new Button(sList[sList.length - 1]);
        lab.getStyleClass().add("lab");
        lab.setPrefHeight(10);
        lab.setPrefWidth(scene.getWidth());
        lab.setAlignment(Pos.CENTER_LEFT);
        lab.setStyle("-fx-border-color: black");
        lab.setStyle("-fx-backgound-color: lightgray");
        lab.setTooltip(new Tooltip(lab.getText()));
        lab.setOnMouseClicked(new EventHandler<MouseEvent>() {
            public void handle(MouseEvent arg0) {
            System.out.println("visible");
            }
        });

        scene.widthProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> arg0, Number arg1, Number arg2) {
            lab.setPrefWidth(scene.getWidth());
            }
        });
        but.add(lab);
        }
        layout.getChildren().setAll(but);
        stage.setScene(scene);
        stage.show();
    }
    }
}

Here is the fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>

<BorderPane id="layout" prefHeight="600.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="dimension.audio.player.MediaViewer">
  <!-- TODO Add Nodes -->
  <center>
    <ScrollPane hbarPolicy="NEVER" prefHeight="200.0" prefWidth="200.0">
      <content>
        <FlowPane id="butLayout" mouseTransparent="false" orientation="VERTICAL" pickOnBounds="false" prefHeight="549.0" prefWidth="599.0" style="" />
      </content>
    </ScrollPane>
  </center>
  <top>
    <GridPane id="searchLayout" alignment="CENTER_RIGHT" prefWidth="579.0" style="-fx-padding: 10">
      <children>
        <Label text="Search:" textAlignment="JUSTIFY" GridPane.columnIndex="0" GridPane.rowIndex="0" />
        <TextField prefWidth="525.0" GridPane.columnIndex="1" GridPane.rowIndex="0" />
      </children>
      <columnConstraints>
        <ColumnConstraints hgrow="SOMETIMES" maxWidth="320.0" minWidth="10.0" prefWidth="61.0" />
        <ColumnConstraints hgrow="SOMETIMES" maxWidth="609.0" minWidth="10.0" prefWidth="539.0" />
      </columnConstraints>
      <rowConstraints>
        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
      </rowConstraints>
    </GridPane>
  </top>
</BorderPane>
Was it helpful?

Solution

  1. Don't instantiate the @FXML-injected fields in your controller. The idea is that these are instantiated by the FXMLLoader those instances are injected for you.
  2. To inject the fields from your FXML file into the controller, you need the attribute fx:id="fieldName", e.g. <FlowPane fx:id="butLayout" ...>.

With the code you have, the fields are not being injected and you are not operating on the nodes in your scene graph (i.e. you're adding the buttons to the FlowPane you created in your controller, not the FlowPane you created in the FMXL file).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top