Reputation: 1
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
Reputation: 209724
You can load the FXML and display each instance in a ListCell
, adding the MessageNode
s 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