Issue
so I have two Controllers: the MainController
and an ImageContainer
both have a FXML layout. In my MainController
i set up a SplitPane
and inside of it a FlowPane
now I want to load the layout of the ImageContainer in the flowpane at runtime:
PROBLEM
How do I place the layout inside the flowpane with pre filled values in textFields, set an image etc.?
Idea
ImageContainer must extend Pane, and in the MainController I have to call the constructor of the ImageContainer and add the ImageContainer to the flowpane:
ImageContainer imgC = new ImageContainer(4,2,"location");
fp_contentFlowPane.getChildren().add(imgC);
Caused by: java.lang.NullPointerException
Caused by: java.lang.reflect.InvocationTargetException
If anyone has an ideas, help is appreciated!
Code snippet Part of ImageContainer Contoller:
public class ImageContainer extends Pane {
public HBox hbx_elementContainer;
public Label lb_likeCount;
public Label lb_commentCount;
public Label lb_location;
public ImageContainer(int likeCount, int commentCount, String location) {
this.lb_likeCount.setText(String.valueOf(likeCount));
this.lb_commentCount.setText(String.valueOf(commentCount));
this.lb_location.setText(location);
Image image = new Image("/sampleFoto.JPG");
iv_feedImage.setImage(image);
}
}
Code snippet Part of MainController Note this is not the whole code:
public class MainScreenController{
public TextField tf_userName;
public ListView lv_listView;
public FlowPane fp_contentFlowPane;
public SplitPane sp_splitPane;
public void onItemClicked(MouseEvent mouseEvent) throws IOException {
int index = lv_listView.getSelectionModel().getSelectedIndex();
if (mouseEvent.getButton().equals(MouseButton.SECONDARY)) {
if (index >= 0) {
lv_listView.getItems().remove(index);
userList.remove(index);
}
}
else{
//fp_contentFlowPane.getChildren().add(new
ImageContainer(5,5,"test"));
ImageContainer imgC = new ImageContainer(4,2,"location");
fp_contentFlowPane.getChildren().add(imgC);
}
}}
Code snippet Main
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/sample.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Get Viral");
primaryStage.setScene(new Scene(root, 1000, 700));
primaryStage.show();
primaryStage.getIcons().add(new Image("/iconSpectures.jpg"));
}
public static void main(String[] args) {
launch(args);
}
}
FXML of ImageContainer:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.text.Font?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="200.0" prefWidth="200.0"
xmlns="http://javafx.com/javafx/8.0.172-ea"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.ImageContainer">
<bottom>
<HBox fx:id="hbx_elementContainer" prefHeight="31.0" prefWidth="600.0"
BorderPane.alignment="CENTER">
<children>
<Label fx:id="lb_likeCount" contentDisplay="TOP" text="Label">
<HBox.margin>
<Insets right="10.0" />
</HBox.margin></Label>
<Label fx:id="lb_commentCount" text="Label">
<HBox.margin>
<Insets right="20.0" />
</HBox.margin></Label>
<Label fx:id="lb_location" text="Label" />
<Label fx:id="lb_accountHolder" text="Label" />
<Button mnemonicParsing="false" text="Download">
<font>
<Font name="Arial Bold" size="11.0" />
</font>
<HBox.margin>
<Insets right="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</bottom>
<center>
<AnchorPane prefHeight="200.0" prefWidth="200.0"
BorderPane.alignment="CENTER">
<children>
<ImageView fx:id="iv_feedImage" fitHeight="150.0"
fitWidth="200.0"
pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</center>
</BorderPane>
Solution
If you want your ImageContainer
to make use of your FXML then you can simply load it in the constructor using FXMLLoader
and get rid of the fx:controller="sample.ImageContainer"
from your FXML.
Here's a post about when to use which method of setting a controller for an fxml file to use (fx:controller
vs FXMLLoader
); Because your ImageContainer
constructor requires arguments, it's easier imo to use the FXMLLoader
method.
public class ImageContainer extends Pane {
private static final PATH_FXML = "/internal/path/to/layout.fxml"
@FXML public HBox hbx_elementContainer;
@FXML public Label lb_likeCount;
@FXML public Label lb_commentCount;
@FXML public Label lb_location;
public ImageContainer(int likeCount, int commentCount, String location) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(PATH_FXML));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException e) {
throw new RuntimeException(e);
}
this.lb_likeCount.setText(String.valueOf(likeCount));
this.lb_commentCount.setText(String.valueOf(commentCount));
this.lb_location.setText(location);
Image image = new Image("/sampleFoto.JPG");
iv_feedImage.setImage(image);
}
}
For some extra fun stuff: If you define getters and setters on a custom Control, then you can use them in the attributes of that control in FXML.
It's not exactly necessary for your use case, but you can do stuff like this.
Custom Control:
package path.to.my_package;
public class MyControl extends Control {
private String myField;
public String getMyField() { return myField; }
public void setMyField(String myField) { this.myField = myField; }
}
FXML:
<?import path.to.my_package.MyControl ?>
<BorderPane xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1">
<center>
<MyControl myField="myValue"/>
</center>
</BorderPane>
Answered By - xtratic