MFC How to make ctreectrl virtual? - c++

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.

Related

How to properly populate/navigate this tree structure using path strings?

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

Forcing QGraphicsItem to use z value and ignore the parent child relationship

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.

How to change the selection from one item to the selected item in tree control?

I had a tree control which is being populated some values.And In this few tree nodes consists of
check boxes whereas few doesn't. My problem is Initially when the tree is enumerated the default
selection is on the first root node and this root node consists of three children where each child
consists of check box. Here is my problem exactly is,
Now when I expand the tree and tried to click on the child item which consist of check box(clicking on the check box)
Until the mouse left button down the focus comes to the item we are checking and when the left button click up then
the selection is reverting back to the root item (or to the item which is previously selected).
In order to resolve this this is something I tried,
//TVN_ITEMCHANGED
void CDriverSetupView::OnTvnItemChangedTree(NMHDR *pNMHDR, LRESULT *pResult)
{
NM_TREEVIEW* pNewTreeView = (NM_TREEVIEW*)pNMHDR;
if(NULL != pNewTreeView->itemNew.hItem)
{
m_TreeCtrl.Select(pNewTreeView->itemNew.hItem,TVGN_CARET | TVGN_FIRSTVISIBLE | TVGN_DROPHILITE);
m_TreeCtrl.SelectItem(pNewTreeView->itemNew.hItem);
m_TreeCtrl.SelectDropTarget(pNewTreeView->itemNew.hItem);
}
}
If I am doing like this then I am able to get the selection to whatever the child I am checking everything is cool.
But Initially when launch my application then the tree is is getting expanded and the selection is not on the root item
,it is moving on to the last item .
Please find the below images for better understanding,
When the tree is enumerated without the piece of code in OnTvnItemChangedTree,the tree looks like this,
Now when mouse left button down on the first checkbox the selection seems that it changed to checkbox
item ,
Now when mouse left button up on the checkbox the selection again revert back to the previous node,
Now when I use the piece of code within OnTvnItemChangedTree then I am able to get the selection to the checked node but initially when I launch my application then the tree is getting expanded and the selection is on to the last child item which is as follows,
In the above image I am able to get what I want but the tree is getting expanded and the selection is on to the last item,I know this is because in the pNewTreeView->itemNew.hItem at last after the initialization that item consists handle to the last item ,but how can we make such that initially the tree should not get expanded and selection should properly work when I check on any node then the selection should get changed to the checked item.
Can anyone please let me know how can make the selection to be remained on to the root item and the tree Initial status should
be as not expanded.
I'm probably misunderstanding the question because the solution seems so obvious, but why don't you just collapse the tree and set the focus to the first item when you create it? So after you've added all children?
Finally I solved it .In order to avoid that expand while at the time Initialization and moving the focus from one item to the checked item can be achieved as follows,
For NM_CLICK notification add this piece of code ,which works like charm.
void CMyTreeCtrl::OnNMClickTree(NMHDR *pNMHDR, LRESULT *pResult)
{
if(NULL != pNewTreeView->itemNew.hItem)
{
m_TreeCtrl.Select(pNewTreeView->itemNew.hItem,TVGN_CARET | TVGN_FIRSTVISIBLE | TVGN_DROPHILITE);
m_TreeCtrl.SelectItem(pNewTreeView->itemNew.hItem);
}
}
The only mistake I had done was added this code in OnTvItemChanged Instead I added in OnNMClickTree ,Now finally I achieved what exactly I want.

QTreeView Move Item with Button

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)

JavaFX getChildren() List behaviour

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.