GoThirteenM
GoThirteenM

Reputation: 1

I would like to dynamicaly create nodes in a javaFX from a template

I am having trouble figuring out how to dynamically create nodes in JavaFX, I am trying to make an interface for a messaging program, and I would like for each message to be contained in its own node. I will not know how many messages will be sent, so I need to create new nodes as needed.

This is what I have so far I want to make it so I can add multiple MessageNode objects and have them display

package stackkoverflow.stackoverflow;

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class MessageControler {
    @FXML
    private Label sender;
    @FXML
    private Label message;

    private MessageNode messagenode;

    public MessageControler(MessageNode messagenode){
        this.messagenode = messagenode;
    }

    @FXML
    private void initialize(){
        sender.textProperty().bind(messagenode.senderProperty());
        message.textProperty().bind(messagenode.messageProperty());
    }

}
package stackkoverflow.stackoverflow;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class MessageNode {

    private StringProperty sender = new SimpleStringProperty();
    private StringProperty message = new SimpleStringProperty();

    public MessageNode(String sender, String message){
        this.sender.set(sender);
        this.message.set(message);
    }

    public String getSender(){
        return sender.get();
    }
    public String getMessage(){
        return message.get();
    }
    public void setSender(String sender) {
        this.sender.set(sender);
    }
    public void setMessage(String message) {
        this.message.set(message);
    }
    public StringProperty senderProperty(){
        return sender;
    }
    public StringProperty messageProperty(){
        return message;
    }



}
package stackkoverflow.stackoverflow;

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

import java.io.IOException;

public class test extends Application {


    @Override
    public void start(Stage primaryStage) {
        MessageNode messageNodeTest = new MessageNode("user","hello world");
        MessageNode messageNodeTest1 = new MessageNode("user","hello world");
        MessageNode messageNodeTest2 = new MessageNode("user","hello world");
        MessageNode messageNodeTest3 = new MessageNode("user","hello world");

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Display.fxml"));
            MessageControler controller = new MessageControler(messageNodeTest);

            loader.setController(controller);

            primaryStage.setScene(new Scene(loader.load()));
            primaryStage.show();

        }catch (IOException ie){
            ie.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

}

Upvotes: 0

Views: 307

Answers (1)

James_D
James_D

Reputation: 209724

You can load the FXML and display each instance in a ListCell, adding the MessageNodes to a ListView<MessageNode>.

First, change your MessageController class so the MessageNode (note: I would rename this class Message, since it's data and not scene graph nodes) can be changed. This is important, because you only want to load the FXML once for each cell, not once for every item:

import javafx.fxml.FXML;
import javafx.scene.control.Label;

public class MessageController {
    @FXML
    private Label sender;
    @FXML
    private Label message;

    private MessageNode messageNode ;

    public void setMessageNode(MessageNode messageNode){
        this.messageNode = messageNode ;
        sender.textProperty().unbind();
        message.textProperty().unbind();
        if (messageNode == null) {
            sender.setText("");
            message.setText("");
        } else {
            sender.textProperty().bind(messageNode.senderProperty());
            message.textProperty().bind(messageNode.messageProperty());
        }
    }

}

Now you can do this:

// injected by FXML or just created in code, as needed:
ListView<MessageNode> listView ;

// ...

listView.setCellFactory(lv -> new ListCell<>() {

    private Node graphic ;
    private MessageController controller ;

    {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("Display.fxml"));
            graphic = loader.load();
            controller = loader.getController();
        } catch (Exception exc) {
            exc.printStackTrace();
        }
    }

    @Override
    protected void updateItem(MessageNode message, boolean empty) {
        super.updateItem(message, empty);
        controller.setMessageNode(message);
        if (empty || message == null) {
            setGraphic(null);
        } else {
            setGraphic(graphic);
        }
    }
});

And of course do

listView.getItems().add(new MessageNode(...));

any time you need.

Upvotes: 1

Related Questions