Look at the following code:
public static void main(String[] args) {
Group group1 = new Group();
Group group2 = new Group();
Label label = new Label("test");
group1.getChildren().add(label);
group2.getChildren().add(label);
System.out.println("Size group1: " +group1.getChildren().size());
System.out.println("Size group2: " +group2.getChildren().size());
}
If the label gets added to group2 it automatically gets removed from group1. Does anyone know why this is intended?
Until now, I do not need the extra functionality e.g. bounds from the group class and use a simple ArrayList to store the references to the label objects.
From the Node documentation:
A node may occur at most once anywhere in the scene graph.
Specifically, a node must appear no more than once in all of the
following: as the root node of a Scene, the children ObservableList of
a Parent, or as the clip of a Node.
...
If a program adds a child node to a Parent (including Group, Region,
etc) and that node is already a child of a different Parent or the
root of a Scene, the node is automatically (and silently) removed from
its former parent.
...
It is possible to rearrange the structure of the scene graph, for
example, to move a subtree from one location in the scene graph to
another. In order to do this, one would normally remove the subtree
from its old location before inserting it at the new location.
However, the subtree will be automatically removed as described above
if the application doesn't explicitly remove it.
When a Node is added to a Scene, the JavaFX system sets and manages attributes specific to that node at that location in the Scene Graph. One example is the location of the node as determined by a parent layout manager and it's constraints. Another is the css style set inherited from parent nodes. Both of these kinds of data may vary depending on the Node's location in the Scene Graph.
If the system allowed you to also place the same Node at another location in the Scene Graph, it would overwrite system calculated attributes determined for the first location. Everything would become very confused - resulting in programs that are difficult to reason about and possessing subtle bugs.
Related
Update:
Turns out I was needlessly complicating things. For the purposes of a context menu, you really only need an arbitrary tree (with a Parent, FirstChild and NextSibling). The best way to visualize a tree for a context menu is just like any other tree, but branching out horizontally instead of vertically. There's never really any need to be able to walk the tree in 4 different directions (Up, Down, Left and Right), because all of the information you need is already there with Parent, FirstChild and NextSibling (all of which is fairly easy to determine if you already have a list of path strings).
This thread can safely be closed.
I'm not using XPath or any web or DOM-related libraries, but I would like to utilize an XPath-style means of populating the contents of a context menu widget:
struct ContextMenuNode
{
ContextMenuNode* Left; // Parent Menu
ContextMenuNode* Right; // Sub Menu
ContextMenuNode* Up; // Previous Sibling
ContextMenuNode* Down; // Next Sibling
FString Path; // An XPath-like string
FString Caption; // Display text of this menu item
}
What I would like to do is something like this:
// Defined in a class declaration:
TArray<ContextMenuNode*> MenuNodes;
// ...
/* This should create 2 unique nodes ("/File" doesn't exist yet within MenuNodes),
establish Left & Right relationships between them, and
return the newly created "/File/Open" node,
adding both nodes into MenuNodes
*/
auto openFileNode = AddNode("/File/Open");
/* Much like the previous line, this should
create 1 unique node (since "/File" should already exist from the previous call),
Left should be "/File", Up should be "/File/Open".
But also, we need to update THOSE nodes in relation to this node now...
Both "/File/Open" and "/File/Save" are Up/Down siblings with the same Left ("/File")
*/
auto saveFileNode = AddNode("/File/Save");
How can this be achieved, or is there simply a better way of going about this?
Useful links for those who are unfamiliar with UE4:
FString: https://api.unrealengine.com/INT/API/Runtime/Core/Containers/FString/index.html
TArray: http://api.unrealengine.com/INT/API/Runtime/Core/Containers/TArray/index.html
My application is displaying a Hugh amount of files system entries held in memory using a ctreectrl , adding all the items takes ~20seconds even when using SetRedraw(False) , so how to make a completely virtual(breadth,depth) ctreectrl & how to populate it ?
Edit#1
I want to display the displayed portion items expanded from the beginning , but I don't want to store them in the tree, for example
Root-->
Child1-->
SubChile1
Child2
Child3
you must not add all items at once. you must add only top level items with cChildren = I_CHILDRENCALLBACK
and handle WM_NOTIFY
with code == TVN_GETDISPINFO if mask & TVIF_CHILDREN set
cChildren (TRUE or FALSE)
with code == TVN_ITEMEXPANDING, action == TVE_EXPAND - expand
node - add only direct child items (one level) again with
cChildren = I_CHILDRENCALLBACK
and possible
with code == TVN_ITEMEXPANDED, action == TVE_COLLAPSE - collapse
node - remove all childs
sense of cChildren = I_CHILDRENCALLBACK - if you add folder to list, you not need at once initialize it (open handle, enum childs) - only when you first time got I_CHILDRENCALLBACK (this when your item become visible, but if containing folder large enough(like system32) - it have too many items, but visible only several top at begin, new begin visible when user scroll down)- open folder, determinate are it have subitems (and based on this set cChildren) but not full enumerate it (do this only on <TVN_ITEMEXPANDING, TVE_EXPAND>
I have no advice to make it virtual.
I use for large tree structures the possibility of collecting a child branch only when it is need. I trap TVN_ITEMEXPANDING
So how to do it: First read the first level (root), than keep all root node collapsed and read all child nodes of the root (just 1 level deep) and populate them.
When a node expands, you already have the nodes, now read the next level below the childs of the expanding node.
So you see only the expanded nodes plus one invisible level.
I do this in this way to show all nodes that are expandable with the + sign. All nodes without children nodes are shown without it as leafs.
The second way is not to fill the string data and let the tree load it via callback. But the impact is small. The real problem with the speed are the number of nodes.
I have problem using QGraphicsItem class.
There is a base_parent, base_part, part_1, part_2. The base_parent is the parent of the base_part. part_1 and part_2 are children of the base_part. What I want to do is to set the Z value of this items in a way that part_1 and part_2 stack behind the base_parent and the base_part stacks in front of the base_parent. So what I've implemented is something like this:
base_part->setParentItem(base_parent);
part_1->setParentItem(base_part);
part_2->setParentItem(base_part);
At first the tried setting the z value using setZValue() but obviously it didn't work.
base_parent->setZValue(0);
base_part->setZValue(1);
part_1->setZValue(-1);
part_2->setZValue(-2);
In the documentation it is said that:
An item's children are stacked on top of the parent
I was giving up but then I saw another parameter.
You can call setZValue() on an item to explicitly stack it on top of,
or under, other sibling items. The default Z value for an item is 0.
Items with the same Z value are stacked by insertion order.
You can call stackBefore() to reorder the list of children. This will
directly modify the insertion order.
You can set the ItemStacksBehindParent flag to stack a child item
behind its parent.
So I tried setting the ItemStacksBehindParent flag but it moved the stacked the whole child behind, meaning the base_part, part_1 and part_2 were stacked behind the base_parent.
Afterwards I found another flag, ItemNegativeZStacksBehindParent.
The item automatically stacks behind it's parent if it's z-value is negative. This flag enables setZValue() to toggle ItemStacksBehindParent. This flag was introduced in Qt 4.6.
So I tried again:
base_part->setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
part_1->setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
part_2->setFlag(QGraphicsItem::ItemNegativeZStacksBehindParent);
Using this flag stacks part_1 and part_2 behind the base_part but they are still stack in front of the base_parent.
I want to know if there's a way to force items to use only Z value and ignore the parent child relationship.
The main reason for insisting on hierarchical structure is that I want to animate the base_part and the part_1 and part_2 must move along the base_part, Of course I know my way around this problem, If only I set parent of the part_1 and part_2 to base_parent, I'll be able to get the result I wanted, but then I have to animate part_1 and part_2 as well which is a little nasty.
I'm using a QTreeView with a QStandardItemModel and I'm trying to figure out how to move items up and down the tree using buttons . I can do drag and drop no problem, but what I would like to do is have some buttons associated with "move up" and "move down" functions. I just cant find anything on the subject. There seems to be a "moveRow()" function for the model object, but I cant find any documentation on it so I'm not sure if its what I need. Any information you could give to point me in the right direction would be greatly appreciated!
PS Here are my QT Creator stats:
Qt Creator 2.6.2
Based on Qt 5.0.1 (64 bit)
Your hunch is correct. moveRow() is the right function to call.
To move items within one parent (it's a tree, after all), you'd do moveRow(parent, index.row(), parent, index.row() + delta), where delta is set to 1 or -1 depending on whether you move down or up, respectively.
If you want to allow items to be moved between parents, you'll need additional logic to figure out the destination parent if the item would be moved past its parent.
Do note that it's considered bad design if the move button are separate from the items to be moved. Your delegate should display up and down arrows for each item, in its row, so that you can move things with one click. When there is a contiguous selection, the delegates should merge the up/down arrows to cover all of the items. When the selection is non-contiguous, the up/down arrows should disappear.
With separate buttons, you need two clicks: first select the item, then click up/down. This sucks from user experience point of view.
moveRow doesn't seem to work in QTreeView.
Here's a simple (PyQt5) solution for moving an item "up one" relative to its sibling(s). It must have at least one sibling "above". Also this is only for moving between siblings, not where you want to move a row to a different parent. However, I think that these issues could be engineered without difficulty on the basis of this code.
One thing to be aware of here is that the QStandardItem doesn't change in operations like this, but that the associated QModelIndex does.
# in almost all QTreeView implementations the "tree" structure is at column 0...
curr_index = self.selectionModel().currentIndex().siblingAtColumn(0)
if curr_index.isValid():
curr_item = self.model().itemFromIndex(curr_index)
curr_row = curr_index.row()
# if this is the top sibling of its parent it cant be moved up...
if curr_row > 0:
parent_item = self.model().itemFromIndex(curr_index.parent())
# NB parent_item is None in the case of root children:
# in that case you therefore use "takeRow" and "insertRow" methods of the model, not the item!
take_row = self.model().takeRow if parent_item == None else parent_item.takeRow
insert_row = self.model().insertRow if parent_item == None else parent_item.insertRow
row_to_move = take_row(curr_row)
insert_row(curr_row - 1, row_to_move)
new_index = self.model().indexFromItem(curr_item)
# now set the (single) selection, and set current, back to the moved item
# (if you are implementing single-selection, obviously)
flag = QtCore.QItemSelectionModel.SelectionFlag
self.selectionModel().setCurrentIndex(new_index, flag.Clear | flag.SelectCurrent)
If I create a template in Sitecore that builds out a parent node with 2 child nodes and 4 grandchild nodes, is there any way to have all of those nodes open in the tree when I "insert" that newly created node in the content tree?
example;
-Parent
-Child
Grandchild
Grandchild
-Child
Grandchild
Grandchild
Currently when I insert a new multilevel template the tree focus jumps to that newly created template but it is closed.
example;
+Parent
I assume by multi-level template you're referring to a branch template. If so, I recommend you create an event handler for perhaps item:saved or item:created. Make sure it only runs when the item is of this template. In the handler try something like the following code. It may not be exact but might get you started and you may need to make it more recursive depending on what it does:
string rootId = // get ID of root item in the new tree of items
string message = String.Format("item:refreshchildren(id={0})", rootId);
Sitecore.Context.ClientPage.SendMessage(this, message);