java getchildren用法,在javaFx中,为什么我们需要调用“getChildren()”当我们向窗口添加元素时?...

For example, when we add a new button to a pane, we need to write the following code:

StackPane pane = new StackPane();

pane.getChildren().add(new Button("OK"));

Why do we need to call "getChildren()?" what does it even do? Why can't we say:

StackPane pane = new StackPane();

pane.add(new Button("OK"));

We're adding the button to the pane. We're not adding it to its children,

解决方案

The short answer is simply "you have to do it that way, because that's how the API was written". Of course, what you are probably really asking is why the API was written like that. I think that really amounts to two (related) questions. One is about the method name, and what that method does, and one is about the actual API design.

In general, in computing, it is often beneficial to reuse existing solutions to problems. (Knowing when it is beneficial to do this is something of an art, but in both the cases here it's pretty clearly a benefit.) In two somewhat different ways, this API design reuses existing solutions to well-known problems, and consequently makes it easier to understand and use for programmers who have encountered those solutions before.

The Scene Graph

For the big picture, think about the overall structure of a general user interface. There is a large container of some kind (think of the root of the scene in JavaFX), which contains various UI components. Some of those might be simple controls, such as buttons and labels, etc, and some of them might be other containers, which in turn contain various UI components. And some of those, of course, may also be containers, and so on. Without imposing some kind of structure, this could get complex and difficult to use.

To understand the structure, we make it abstract. There is a root node, which has a collection of zero or more other nodes. Each of those has a collection of zero or more other nodes, and so on. This is a very well known abstract structure in computing, called a "tree", which basically every computer programmer (no matter which language they program in) is familiar with. So if we think of it as a tree structure, because we are already familiar with that, we can make the complexity easier to work with. In order to think of it as a tree structure, we use standard names for the tree-like aspects. Each node (except the root node) has exactly one "parent" (the container to which it belongs): so you'll find a method in the Node class ("node" is another piece of terminology from tree structures) called getParent(), which gives access to the parent node (the container containing the current node). Similarly, UI elements (nodes) that contain other nodes have a method called getChildren() that returns a collection of all the nodes contained in the current node. The Oracle JavaFX tutorial has a section on the Scene graph describing this, with lots of nice diagrams and related code.

So, in short, the reason there is a method called getChildren() is because we think of the collection of all the things in the UI as a tree structure, and this method name describes exactly what that method does in the context of the collection of all the UI elements being a tree. The terms "node", "parent" and "child" are instantly recognizable to programmers with a little bit of experience, and help them to understand the overall structure and to work with it. They can basically instantly infer that getChildren() returns a list of all the UI elements immediately contained in that container (the container is the StackPane in your example).

API design of Panes (such as StackPane)

To think about the API design, think about all the things you might want to do in terms of manipulating what is contained in your StackPane. As you observe, you might want to add a new UI element ("node") to the StackPane, so you might want a method called add(...) that accepts a Node. But there are a whole bunch of other things you might need or want to do too:

Remove a node from the StackPane

Add a whole collection of nodes to the StackPane

Remove a whole collection of nodes from the StackPane

Remove all the nodes from (clear) the StackPane

Since the order of nodes in the stack pane is important (it defines the z-order, i.e. if the nodes overlap it defines which are drawn in front and which behind), you might want to insert a node at a specific position (in front of something but behind something else)

Remove the node at the "back", or at the front, or at some specified position

and many, many others

So the designers of the StackPane class could have just written all these methods, but there's a better way.

If you think about implementing StackPane, you need some way to keep track of the nodes (UI elements) it contains. The order of these nodes is important, so we must keep track of that, and we need to have a nice way to define all the functionality listed above. The authors of the StackPane class (or its superclass, Pane) could have built a data structure to do this from scratch, but one already exists in the standard libraries. A data structure that holds a collection of objects of some specific type, and keeps track of their order, is called a List1, and the List interface is one that every single Java programmer is familiar with.

So if you think of the actual implementation of the StackPane, you could define methods for all the functionality listed above in the stack pane itself. This would end up looking something (really it would be more complex than this, I just want enough here to make the point) like

public class StackPane {

private final List children = new ArrayList<>(); // or some other list implementation...

public void add(Node node) {

children.add(node);

}

public boolean remove(Node node) {

return children.remove(node);

}

public void add(int index, Node node) {

children.add(index, node);

}

public boolean remove(int index) {

return children.remove(index);

}

public void addAll(Collection nodes) {

children.addAll(nodes);

}

// lots more methods like this...

// lots of layout code omitted...

}

I think you get the point. All this code is not really doing anything; it is simply invoking behavior that is already defined. So instead of this bloated API, it's possible to provide exactly the same functionality to the user of StackPane simply by providing access to the list itself2:

public class StackPane {

private final List children = new ArrayList<>();

public List getChildren() {

return children ;

}

// layout code omitted...

}

Now the class is much less bloated, the API is less bloated, and additionally, the user receives a List, which as pointed out earlier is a very well known type of object. The new programmer to JavaFX, assuming they have some (any) Java experience, will already be familiar with the API for List and will not need to learn much that is new in order to use it. So the programmer can now do (with code laid out unconventionally and the thoughts of the programmer inserted):

StackPane pane = new StackPane();

Button button = new Button("OK");

pane.getChildren()

// oooh, a List, I know how those work

.add(button);

List lotsOfLabels = Arrays.asList(new Label("One"), new Label("Two"), new Label("Three"));

pane.getChildren()

// still a list, I know more things I can do here:

.addAll(lotsOfLabels);

pane.getChildren().remove(button);

pane.getChildren().clear();

and we have a happy programmer who immediately knows the API, and is instantly productive on a first encounter with managing the scene graph in JavaFX, and consequently a happy boss who sees great productivity from the programming team.

So in summary, by simply exposing the List of child nodes, the API can expose all the functionality it needs for manipulating the contents of the StackPane, without adding a huge list of methods to the StackPane class and do it in a way that leverages the existing knowledge of every Java programmer.

Footnotes

Actually, Panes require a little more functionality than is defined in List: they need a convenient way of knowing when the list changes, by nodes being added or removed (because the pane needs to recompute its layout when this happens). So the JavaFX team defined a subinterface of List, called ObservableList, which has all the functionality of List and adds functionality for "observing" the list.

There is one thing that the JavaFX team will have had to think hard about here: is all the functionality defined by List appropriate for the collection of child nodes? If the List interface defined some methods that really didn't make sense here, it would probably be a bad idea to use this implementation, and the more bloated API suggested in the first code block might actually be a better choice.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值