Results 1 to 8 of 8

Thread: QTreeView + own model + dynamic filling

  1. #1
    Join Date
    Feb 2010
    Posts
    7
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default QTreeView + own model + dynamic filling

    Hi!
    I've created an own model for treeview. At first I load data that is ysed to show the first level of ierarchy. And I know if element has children or has not.
    Clild elements should be loaded and shown only after expanding the node.
    So, to enable expand and form visual style, i add a "fake" child element "Loading.." for each node that should have children.

    My model is based on example from Blanshed & Sammerfield book. I load data using lists, it looks like this:
    Qt Code:
    1. void modelClients::setLists( treeNodeClient *node,
    2. const QList<int> &p_IDs,
    3. const QList<QString> &p_Names)
    4. {
    5. // Clearing existing node
    6. qDeleteAll(node->children);
    7. node->children.clear();
    8.  
    9. // Every adding element
    10. for (int i = 0; i < p_IDs.count(); i++)
    11. {
    12. // Creating new element and adding it to existing
    13. node->children.append( new treeNodeClient(p_IDs[i], p_Names[i], node) );
    14.  
    15. // If condition is true, add a fake child item - loading
    16. if (*condition*)
    17. node->children.last()->children.append(new treeNodeClient(-1, tr("Loading..."), node->children.last() ));
    18. }
    19.  
    20. // Reset the model
    21. reset();
    22. }
    To copy to clipboard, switch view to plain text mode 

    So, to fill the first level I use this code:
    Qt Code:
    1. mdlClients = new modelClients(this);
    2. ui->trvClients->setModel(mdlClients);
    3.  
    4. mdlClients->setLists(mdlClients->rootNode, mm_IDs, mm_Names);
    To copy to clipboard, switch view to plain text mode 

    And I thought that to fill other nodes I should use this construction:
    Qt Code:
    1. void wgtManager::on_trvClients_expanded(QModelIndex index)
    2. {
    3. ...
    4.  
    5. treeNodeClient *node = static_cast<treeNodeClient*>(index.internalPointer());
    6. mdlClients->setLists(node, mm_IDs, mm_Names);
    7. }
    To copy to clipboard, switch view to plain text mode 

    Please, give me an advice, how to form children dynamically while expanding a node!
    Thanks!

  2. #2
    Join Date
    Nov 2009
    Posts
    129
    Thanks
    4
    Thanked 29 Times in 29 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTreeView + own model + dynamic filling

    Quote Originally Posted by Urvin View Post
    Please, give me an advice, how to form children dynamically while expanding a node!
    Implement the virtual functions QAbstractItemModel::canFetchMore, QAbstractItemModel::fetchMore, QAbstractItemModel::hasChildren and QAbstractItemModel::rowCount.

    The idea is this: if you know an item has children but haven’t yet fetched them, return 0 from rowCount but true from canFetchMore and hasChildren. Such a node will be shown with an expansion box even though it has no child rows (yet). If the user clicks the box, canFetchMore and then fetchMore will be called and you can populate the next level of the model.

    There is a point of possible confusion. Qt’s Model Subclassing Reference notes that you must call QAbstractItemModel::beginInsertRows and QAbstractItemModel::endInsertRows within QAbstractItemModel::fetchMore, and the documentation of those functions says you must call beginInsertRows “before inserting data into the model's underlying data store” and endInsertRows after. Obviously, the model can’t tell by some sort of magic whether you have updated the underlying data store, and in some cases you might need to update first to find out how many rows will be added, which you need to know to call beginInsertRows. In practice, what this means is that beginInsertRows and endInsertRows call other model functions (such as rowCount), and you must make sure that all the virtual functions you re-implement return a consistent, unchanging view of the model from the beginning of fetchMore until the return from beginInsertRows, and again from the call to endInsertRows through the return from fetchMore. As long as you can do that, update the underlying data store in whatever way works efficiently.

  3. #3
    Join Date
    Feb 2010
    Posts
    7
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QTreeView + own model + dynamic filling

    I am very ashamed, but I can not understand. = (
    Should my data source be implemented in model?
    Maybe there is a good example?

  4. #4
    Join Date
    Nov 2009
    Posts
    129
    Thanks
    4
    Thanked 29 Times in 29 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTreeView + own model + dynamic filling

    I’m sorry this was unclear. I’m unfamiliar with the book and example you mentioned, so there is probably some underlying framework into which you need to fit your code, and I don’t know what it is.

    Would you show us the declaration (code from the header file) for modelClients? I assumed it must be a direct subclass of QAbstractItemModel — if it isn’t, then that would explain why what I said made no sense.

  5. #5
    Join Date
    Feb 2010
    Posts
    7
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QTreeView + own model + dynamic filling

    So, here's my item:
    Qt Code:
    1. class treeNodeClient
    2. {
    3. public:
    4. treeNodeClient(treeNodeClient *parentnode = 0, int pid = 0, const QString &pname = "", const QString &pphone = "",
    5. const QString &pemail = "", const QString &preferal = "",
    6. const bool &phaschildren = false);
    7. ~treeNodeClient();
    8.  
    9. int id;
    10. QString name;
    11. QString phone;
    12. QString email;
    13. QString referal;
    14. bool haschildren; // true if node can have children. but we don't know how many yet
    15.  
    16. int row() const;
    17.  
    18. treeNodeClient *parent;
    19. QList<treeNodeClient*> children;
    20. };
    To copy to clipboard, switch view to plain text mode 

    Model:
    Qt Code:
    1. class modelClients: public QAbstractItemModel
    2. {
    3. public:
    4. modelClients(QObject *parent = 0);
    5. ~modelClients();
    6.  
    7. int rowCount(const QModelIndex &parent) const;
    8. int columnCount(const QModelIndex & /* parent */) const;
    9. QVariant data(const QModelIndex &index, int role) const;
    10. Qt::ItemFlags flags(const QModelIndex &index) const;
    11. QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    12. QModelIndex index(int row, int column, const QModelIndex &parent) const;
    13. QModelIndex parent(const QModelIndex &index) const;
    14.  
    15. bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const;
    16. bool canFetchMore ( const QModelIndex & parent ) const ;
    17.  
    18. treeNodeClient *rootNode; // root node is created in constructor, is newer shown in treeview
    19. };
    To copy to clipboard, switch view to plain text mode 

    Functions:
    Qt Code:
    1. int modelClients::rowCount(const QModelIndex &parent) const
    2. {
    3. treeNodeClient *parentNode;
    4. if (!parent.isValid()) parentNode = rootNode;
    5. else parentNode = static_cast<treeNodeClient*>(parent.internalPointer());
    6.  
    7. return parentNode->children.count();
    8. }
    9.  
    10. bool modelClients::hasChildren ( const QModelIndex & parent ) const
    11. {
    12. if (!parent.isValid()) return false;
    13. treeNodeClient *node = static_cast<treeNodeClient*>(parent.internalPointer());
    14.  
    15. return node->haschildren;
    16. }
    To copy to clipboard, switch view to plain text mode 

    I can't imagine what to write in canFetchMore and fetchMore
    Last edited by Urvin; 16th February 2010 at 16:33.

  6. #6
    Join Date
    Nov 2009
    Posts
    129
    Thanks
    4
    Thanked 29 Times in 29 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTreeView + own model + dynamic filling

    Quote Originally Posted by Urvin View Post
    I can't imagine what to write in canFetchMore and fetchMore
    Back in your first post, you had code like this:
    Qt Code:
    1. if (*condition*)
    2. node->children.last()->children.append(new treeNodeClient(-1, tr("Loading..."), node->children.last() ));
    To copy to clipboard, switch view to plain text mode 
    which I presume now reads:
    Qt Code:
    1. node->children.last()->hasChildren = *condition*;
    To copy to clipboard, switch view to plain text mode 
    instead. You’ll then want something like this:
    Qt Code:
    1. bool modelClients::canFetchMore(const QModelIndex& parent) const {
    2. if (!parent.isValid()) return false;
    3. treeNodeClient *node = static_cast<treeNodeClient*>(parent.internalPointer());
    4. return parentNode->hasChildren && !parentNode->children.count();
    5. }
    6.  
    7. void modelClients::fetchMore (const QModelIndex& parent) {
    8. if (!canFetchMore(parent)) return;
    9. treeNodeClient *node = static_cast<treeNodeClient*>(parent.internalPointer());
    10. //
    11. // get the information you need to populate node
    12. //
    13. beginInsertRows(node, 0, mm_IDs.count()-1);
    14. setLists(node, mm_IDs, mm_Names);
    15. endInsertRows();
    16. }
    To copy to clipboard, switch view to plain text mode 
    for canFetchMore and fetchMore.

  7. #7
    Join Date
    Feb 2010
    Posts
    7
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QTreeView + own model + dynamic filling

    Ok) Thanks!

    Now I got something wrong with hasChildren function
    Qt Code:
    1. bool modelClients::hasChildren ( const QModelIndex & parent ) const
    2. {
    3. if (!parent.isValid()) return false;
    4. treeNodeClient *node = static_cast<treeNodeClient*>(parent.internalPointer());
    5.  
    6. return node->haschildren;
    7. }
    To copy to clipboard, switch view to plain text mode 

    If I write "if (!parent.isValid()) return false" than my tree will newer be shown.
    If I delete function from the model class, first level ierarchy can be shown, but no node can be expanded;
    If I write "if (!parent.isValid()) return true", first level of ierarchy is shown correctly, but the second inserts twice

    Here is my whole code in attachment
    Attached Files Attached Files

  8. #8
    Join Date
    Nov 2009
    Posts
    129
    Thanks
    4
    Thanked 29 Times in 29 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTreeView + own model + dynamic filling

    In modelClients::fetchMore you should have beginInsertRows(parent,0,2) rather than beginInsertRows(parent,0,3). The third argument to QAbstractItemModel::beginInsertRows is the index of the last row to be inserted, not the number of rows to be inserted.

    Models are strange and confusing in that way: many trivial mistakes are not diagnosed as errors, but instead cause bizarre behavior that is hard to connect to the cause. There is a project called ModelTest that can often catch obscure errors in model implementations.

Similar Threads

  1. Filling QTreeWidget / Using QTreeView
    By stefanborries in forum Qt Programming
    Replies: 1
    Last Post: 15th April 2009, 15:25
  2. QTreeView and QAbstractItem Model.
    By Terabyte in forum Qt Programming
    Replies: 1
    Last Post: 13th January 2009, 13:18
  3. QTreeView with Model-View help
    By MathStuf in forum Qt Programming
    Replies: 10
    Last Post: 26th April 2008, 06:23
  4. using QTreeView with a Database model
    By darksaga in forum Qt Programming
    Replies: 1
    Last Post: 17th January 2007, 23:29
  5. how to use QTreeView with Database model
    By mikro in forum Newbie
    Replies: 3
    Last Post: 13th April 2006, 16:12

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.