I want to define a global search in my program. My program has many nodes in a scene and there are a lot of common things on different nodes that could be searched. I think of defining a class searchable and a method for searching in each node.
So when I search by a class selector I would be able to reach all the nodes to highlight them for the user.
For example if Scene or Node has a method like this:
scene.getBySelector(".searchable").filter( (p)-> (Searchable)p.search()).forEach((p) -> (Searchable)p.setHighlited());
It is certainly can be done by iterating a scene or node children recursively but it looks to me so heavy so I'd like to know if there exists such a thig:
CSSUtils.getBySelector(".searchable").filter((p) -> p.getScene() == myScene)...
Node has methods lookup(...) and lookupAll(...) which I think are what you are looking for.
Related
I want to define a global search in my program. My program has many nodes in a scene and there are a lot of common things on different nodes that could be searched. I think of defining a class searchable and a method for searching in each node.
So when I search by a class selector I would be able to reach all the nodes to highlight them for the user.
For example if Scene or Node has a method like this:
scene.getBySelector(".searchable").filter( (p)-> (Searchable)p.search()).forEach((p) -> (Searchable)p.setHighlited());
It is certainly can be done by iterating a scene or node children recursively but it looks to me so heavy so I'd like to know if there exists such a thig:
CSSUtils.getBySelector(".searchable").filter((p) -> p.getScene() == myScene)...
Node has methods lookup(...) and lookupAll(...) which I think are what you are looking for.
I have a tree like this:
As you can see there is GridPane with 10 columns. Each of them include BorderPane wrapped into AnchorPane. Each BorderPane is composed of 2 labels and 1 radioButton. Below you can see how it look like:
I want to ask you how to get acces from code side to these elements. I know that I can use getChildren() method on GridPane but then I get only AnchorPanes from GridPane columns. I want to go deeply, and for example set text into one of the labels.
I want to add that set id in Scene Builder is not what I want cause there will be many columns and I'm going to fill it in some loop.
Could you help me with this ?
One more thing: I build the view in Scene Builder.
You you can set a css id for the nodes within your loop at creation time. You can later lookup the nodes by the id you set. A lookup will also work on a scene to find any node or matching set of nodes within the scene.
HBox parent = new HBox();
for (int i = 0; i < N_COLS, i++) {
Node childNode = createNode();
childNode.setId("child" + i);
parent.getChildren().add(childNode);
}
. . .
Node redheadedStepchild = parent.lookup("#child5");
Of course, you can always access the child the standard object accessor way too:
Node redheadedStepchild = parent.getChildren().get(5);
If the structure is nested as you have in your question, then you can do things such as:
Node redheadedGrandchild = grandparent.getChildren().get(3).getChildren().get(5);
Such searches get convoluted over large structures and probably are best avoided as your code would get more brittle. So a css based lookup or tree traversal would probably be preferred, or a direct injection of a reference via an fx:id and #FXML, which wouldn't work well in your case because you create the items in code in a loop, hence the lookup method is probably best for you.
We created a small painting application in JavaFX. A new requirement arose, where we have to warn the user, that he made changes, which are not yet persisted and asking him, if the user might like to save first before closing.
Sample Snapshot:
Unfortunately there are a lot of different Nodes, and Nodes can be changed in many ways, like for example a Polygon point can move. The Node itself can be dragged. They can be rotated and many more. So before firing a zillion events for every possible change of a Node object to the canvas I`d like to ask, if anyone might have an idea on how to simplify this approach. I am curious, if there are any listeners, that I can listen to any changes of the canvas object within the scene graph of JavaFX.
Especially since I just want to know if anything has changed and not really need to know the specific change.
Moreover, I also do not want to get every single event, like a simple select, which causes a border to be shown around the selected node (like shown on the image), which does not necessary mean, that the user has to save his application before leaving.
Anyone have an idea? Or do I really need to fire Events for every single change within a Node?
I think you are approaching this problem in the wrong way. The nodes displayed on screen should just be a visual representation of an underlying model. All you really need to know is that the underlying model has changed.
If, for example, you were writing a text editor, the text displayed on the screen would be backed by some sort of model. Let's assume the model is a String. You wouldn't need to check if any of the text nodes displayed on screen had changed you would just need to compare the original string data with the current string data to determine if you need to prompt the user to save.
Benjamin's answer is probably the best one here: you should use an underlying model, and that model can easily check if relevant state has changed. At some point in the development of your application, you will come to the point where you realize this is the correct way to do things. It seems like you have reached that point.
However, if you want to delay the inevitable redesign of your application a little further (and make it a bit more painful when you do get to that point ;) ), here's another approach you might consider.
Obviously, you have some kind of Pane that is holding the objects that are being painted. The user must be creating those objects and you're adding them to the pane at some point. Just create a method that handles that addition, and registers an invalidation listener with the properties of interest when you do. The structure will look something like this:
private final ReadOnlyBooleanWrapper unsavedChanges =
new ReadOnlyBooleanWrapper(this, "unsavedChanged", false);
private final ChangeListener<Object> unsavedChangeListener =
(obs, oldValue, newValue) -> unsavedChanges.set(true);
private Pane drawingPane ;
// ...
Button saveButton = new Button("Save");
saveButton.disableProperty().bind(unsavedChanges.not());
// ...
#SafeVarArgs
private final <T extends Node> void addNodeToDrawingPane(
T node, Function<T, ObservableValue<?>>... properties) {
Stream.of(properties).forEach(
property -> property.apply(node).addListener(unsavedChangeListener));
drawingPane.getChildren().add(node);
}
Now you can do things like
Rectangle rect = new Rectangle();
addNodeToDrawingPane(rect,
Rectangle::xProperty, Rectangle::yProperty,
Rectangle::widthProperty, Rectangle::heightProperty);
and
Text text = new Text();
addNodeToDrawingPane(text,
Text::xProperty, Text::yProperty, Text::textProperty);
I.e. you just specify the properties to observe when you add the new node. You can create a remove method which removes the listener too. The amount of extra code on top of what you already have is pretty minimal, as (probably, I haven't seen your code) is the refactoring.
Again, you should really have a separate view model, etc. I wanted to post this to show that #kleopatra's first comment on the question ("Listen for invalidation of relevant state") doesn't necessarily involve a lot of work if you approach it in the right way. At first, I thought this approach was incompatible with #Tomas Mikula's mention of undo/redo functionality, but you may even be able to use this approach as a basis for that too.
I have a flex tree component that has its data bind to a ArrayCollection. I also implemented a custom ITreeDataDescriptor to filter the tree. Everything works fine except the first level nodes will not disappear (be filtered) if there is no child node under it. It does work from the second level down.
any suggestion how it can be done?
Only want to filter out the first level node when all its children node are been filtered out.
pretty much like this example, except Parent would disappear when children are gone
the source is an ArrayCollection and it's pretty much like the following
var dataSource:ArrayCollection = new ArrayCollection();
dataSource.addItem(myObject1);
dataSource.addItem(myObject2);
dataSource.addItem(myObject3);
dataSource.addItem(myObject4);
and in myObject1 ~ myObject4 there are children ArrayCollection with the same type.
This is hard to answer without any code, but here are some suggestions on a approach:
make sure you have a root node so that you can also filter out the nodes at level 1 (the children of the root node)
do a recursive check in the getChildren() method of the ITreeDataDescriptor implementation to see if all children of a node are removed/hidden
this question is about best practices. I'm implementing a 3D interval Kd-Tree and, because of the recursive structure of the tree I would be tempted to create a unique class, KdTree to represent the tree itself, the nodes and the leaves.
However: elements are contained only at leaves, some general tree parameters (such as the maximum number of elements before splitting the space) are meant to be the same for all the tree and finally splitting planes have no sense at all in leaves.
That said: should I make up three classes (KdTree, KdNode, KdLeaf) or just pretend that each node or leaf is in fact a Kd-Tree (which, in fact, is precisely the case) and duplicate data?
Tommaso
I would say there is no need for a Tree class. The top element is a node like all the rest.
To differentiate the leaves and the branch nodes, I'd go for
namespace KdTree
{
abstract class Node
{
virtual EnumLeafNodes(LeafNodeCallback callback);
virtual GetLeafCount();
}
class Leaf : Node
{
// implement virtuals by returning/counting leaf values
}
class Branch : Node
{
// implement virtuals by delegating to child nodes
// direct children:
Node[] children;
}
}
Note that this is very much pseudocode (C#-ish). The idea behind this design is that you use virtual functions to differentiate the behavior between branches and leaf nodes, and the branches can delegate to their child nodes. This is a trivial example on what is know as the Visitor pattern.
Create and use the classes KdNode and KdLeaf privately within the context of KdTree. This will make your life easier, and hide the complexity from other parts of the program
It seems the lead and tree are nodes that are simply at the beginning of the end of the "branch".
In these cases, I just name them "nodes" and when parsing through them, I would refer to them as KdParentNode, KdNode and KdChildNode. If a node does not have a parent, It's the tree (root) node, and if it does not have children, it's a leaf node.