Add/Remove node to wxDataViewCtrl

325 views Asked by At

I'm developing an application using wxWidgets v3.2.1 and using wxDataViewModel and wxDataViewCtrl to display a data model in tree fashion with multiple columns. I'm following the dataview example from wxWidget samples.

My application doesn't need a root node so I want to hide the root node. To do this, I followed this thread from wxWidget forum and updated the GetChildren method as follows:

unsigned int GetChildren(const wxDataViewItem &parent,
                        wxDataViewItemArray &array) const wxOVERRIDE
{
    DataModelNode *node = static_cast<DataModelNode *>(parent.GetID());

    if (node == nullptr)
    {
        return GetChildren(wxDataViewItem(m_Root), array);
        // array.Add(wxDataViewItem((void *)m_Root));
        // return 1;
    }
}

After the above change, the root is no longer visible but adding and removing nodes from the tree doesn't work as expected. Deleting a node doesn't remove the node immediately from the wxDataViewCtrl. Adding a child node doesn't add the node to the tree.

Tree with root node, behaving as expected Tree With root node

Tree with hidden root node, adding/removing node doesn't work Tree without root node

To demonstrate this issue I've created a sample application, the source code of which can be found here https://gist.github.com/aamirglb/8a597dcf48b4bc773746fb9c5a0b08f1.

I would like to have a tree without a root node and able to add/remove the nodes to the tree. Any help on resolving this issue is highly appreciated.

Update

I'm able to reproduce the same issue in dataview sample as well. I Updated MyMusicTreeModel::GetChildren as follows, then Add Mozart, Delete selected button doesn't work.

unsigned int MyMusicTreeModel::GetChildren(const wxDataViewItem &parent,
                                           wxDataViewItemArray &array) const
{
    MyMusicTreeModelNode *node = (MyMusicTreeModelNode *)parent.GetID();
    if (!node)
    {
        //// this line causes the issue ////////////////
        return GetChildren(wxDataViewItem(m_root), array);
        // array.Add(wxDataViewItem((void *)m_root));
        // return 1;
    }

    if (node == m_classical)
    {
        MyMusicTreeModel *model = const_cast<MyMusicTreeModel *>(this);
        model->m_classicalMusicIsKnownToControl = true;
    }

    if (node->GetChildCount() == 0)
    {
        return 0;
    }

    unsigned int count = node->GetChildren().GetCount();
    for (unsigned int pos = 0; pos < count; pos++)
    {
        MyMusicTreeModelNode *child = node->GetChildren().Item(pos);
        array.Add(wxDataViewItem((void *)child));
    }

    return count;
}

Update 2 Here is the the diff of dataview sample:

diff --git a/mymodels.cpp b/mymodels.cpp
index 5963dfd..052b009 100644
--- a/mymodels.cpp
+++ b/mymodels.cpp
@@ -304,8 +304,7 @@ unsigned int MyMusicTreeModel::GetChildren(const wxDataViewItem &parent,
     MyMusicTreeModelNode *node = (MyMusicTreeModelNode *)parent.GetID();
     if (!node)
     {
-        array.Add(wxDataViewItem((void *)m_root));
-        return 1;
+        return GetChildren(wxDataViewItem(m_root), array);
     }

     if (node == m_classical)
3

There are 3 answers

8
DailyLearner On BEST ANSWER

wxDataViewModel::Cleared() must be called after adding/remove a node from the data model. wxDataViewModel::Cleared() method will force the wxDataViewCtrl to reread the data from the model again. So after adding or removing the node, wxDataViewCtrl must be instructed to refresh itself with the latest data from the data model.

To hide the root node from wxDataViewCtrl, the wxDataViewModel::GetChildren() method must be implemented as follows:

unsigned int GetChildren(const wxDataViewItem &parent,
                                    wxDataViewItemArray &array) const wxOVERRIDE
{
    DataModelNode *node = static_cast<DataModelNode *>(parent.GetID());

    if (node == nullptr)
    {
        int count = m_Root->GetChildCount();
        for (int i = 0; i < count; ++i)
        {
            // Instead of root node, return the 1st level children
            array.Add(wxDataViewItem(static_cast<void *>(m_Root->GetNthChild(i))));
        }
        return count;
    }
}

Here is the link to the working version of the application:

https://gist.github.com/aamirglb/bc50b7bb794a84f0a2c871e7e961e993

And here the the output from the application:

enter image description here

8
VZ. On

It doesn't really make sense to say that you "don't need a root node" because there is always a root node in wxDVC. However this true root node is actually never shown, so you must be thinking of its child as the "root node that you don't need". And it's perfectly possible not to have this one, of course: you just need to return the real top-level nodes (directories in your case, AFAICS) as children of this root node.

However in no case does it make sense to forward GetChildren() to another parent, this breaks the definition of a tree and while I didn't follow the details, it's not surprising at all that doing it breaks things -- just don't do that.

0
ollydbg23 On

I think I have found the solution here.

I just make a collection of all the top level nodes, and now both the "Pop music" and "Classical music" are the children of the NULL node(the virtual root node).

I post the full patch file here: Re: wxDataViewCtrl how to Hide the RootItem in the wxWidgets' forum.

This avoids the Cleared() function calls mentioned in Aamir's answer.

EDIT: I added a tree structure about the node.

Here the the tree structure before and after my changes, see below(I draw it in ascii art flowchart)

                                                  
 +------+                                         
 | NULL |                                         
 +---/--+                                         
     |      +----------+        +---------+       
     \------| My Music |--/-----|Pop Music|       
            +----------+  |     +---------+       
                          |                       
                          |     +---------------+ 
                          ------|Classical Music| 
                                +---------------+ 
                                                  
                The wx dataview sample tree       
                                                  
                                                  
                                                  
      +------+                                    
      | NULL |                                    
      +---/--+                                    
          |        +---------+                    
          \--/-----|Pop Music|                    
             |     +---------+                    
             |                                    
             |     +---------------+              
             ------|Classical Music|              
                   +---------------+              
                                                  
                     The modified tree