5

I'm learning basic JavaFX right now, and I don't understand this statement from the book I'm reading: "No, a node such as a text field can be added to only one pane and once. Adding a node to a pane multiple times or to different panes will cause a runtime error." I can see from the UML diagram the book provides that it is a composition, but I don't understand why (library class code implementation) that is.

For instance, why does this result in a compile error? Isn't a new text field instantiated within the pane since it's a composition?

FlowPane pane = new FlowPane();
StackPane pane2 = new StackPane();
TextField tf = new TextField();
pane.getChildren().add(tf);
pane.getChildren().add(tf);

Also, why does the following run but not show the text field placed in pane?

FlowPane pane = new FlowPane();
StackPane pane2 = new StackPane();
TextField tf = new TextField();
pane.getChildren().add(tf);
pane2.getChildren().add(tf);

primaryStage.setScene(new Scene(pane));
primaryStage.show();
4
  • 1
    Where does that statement come from? Some context would be useful. Commented Dec 29, 2014 at 21:38
  • It's from a textbook Commented Dec 29, 2014 at 21:46
  • You can look at JavaFX source code and figure out why. Commented Dec 29, 2014 at 23:46
  • 2
    You don't really need to look at the source code. You can just look at the API documentation and see that it wouldn't make sense to allow this. For example, there would be no meaningful semantics for method calls such as tf.getBoundsInParent() if this code were allowed. Commented Dec 30, 2014 at 1:39

2 Answers 2

6

This is basically a (deliberate) consequence of the way the API is designed. Each Node has a collection of properties, including a parent property (the - one and only one - parent of the node in the scene graph), along with properties such as layoutX and layoutY which are the coordinates of the node in relation to its parent. Consequently, a node can only belong to one parent, and can only be added to a parent once (as it can only have one location in the parent). Organizing things this way enables a very efficient layout process.

Another way to think of this: suppose your first code block did what you wanted; so the text field tf appeared twice in the flow pane. What result would you expect to get from tf.getBoundsInParent()? Since tf appears twice in the parent, the API would not be able to give a sensible value for this call.

There are a couple of inaccuracies in statements you make in your question:

For instance, why does this result in a compile error? Isn't a new text field instantiated within the pane since it's a composition?

First, technically, this is aggregation, not composition; though I'm not sure understanding the difference will aid your understanding of what is happening at this point.

Second, there is no compile error here; you get an error at runtime (the pane detects that the same node has been added twice; the complier has no way to check this).

Third, parents do not instantiate copies of the nodes you add to them. If so, you wouldn't be able to change the properties of nodes that were displayed. For example, if the FlowPane in your example instantiated a new TextField when you called pane.getChildren().add(tf);, and then displayed that new text field, then if you subsequently called tf.setText("new text"), it would have no effect, as it would not be changing the text of the text field that pane was displaying.

When you call pane.getChildren().add(...) you pass a reference to the node you want to be added; it is that node that is then displayed as a child of the pane. Any other implementation would produce pretty counter-intuitive behavior.

In your second code block:

pane.getChildren().add(tf);
pane2.getChildren().add(tf);

the second call implicitly sets the parent property of tf to pane2; consequently tf is no longer a child of pane. So this code has the effect of removing tf from the first parent, pane. As far as I am aware, this side-effect is not documented, so you probably should avoid writing code like this.

Sign up to request clarification or add additional context in comments.

Comments

0

Try this:

TextField tf = new TextField();
TextField tf2 = new TextField();
pane.getChildren().add(tf);
pane.getChildren().add(tf2);

The reason you cannot add the same node twice is that only one node with the same specifications and dimensions can be viewable in the gui. It would be like copying an identical blue circle onto an original blue circle. To the user it looks the same, but it takes up more memory.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.