QModelIndex is invalid in QTreeView based on Qt SimpleTreeModel example (source code pasted)



  • I'm creating a file browser based on the Qt4.8 example SimpleTree
    And I rewrote my own setUpModelData as shown in the function FileTreeModel::setupModelData below (totally less than 60 lines)

    Basically, the argument root contains the user-specified root path, like "D:\qt_project\prj1", and setUpModelData will create a tree model from the real root directory D:\ to this user-specified path, with all sibling items added.

    The problem is, whenever I expanded any directory under D:, I got a segment fault.
    With all the addresses dumped, I could see that the childItem in the function TreeModel::parent is none of the dumped address, i.e., such childItem retrieved from index.internalPointer is invalid.

    How come internalPointer returns an invalid TreeItem pointer ?

    QModelIndex TreeModel::parent(const QModelIndex &index) const
    {
        if (!index.isValid())
            return QModelIndex();
    
        TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
        TreeItem *parentItem = childItem->parent();
    
        if (parentItem == rootItem)
            return QModelIndex();
    
        return createIndex(parentItem->row(), 0, parentItem);
    }
    
    QModelIndex FileTreeModel::setupModelData(TreeItem *root) {
        QFileInfo fi_root = QFileInfo(root->data().toString());
        TreeItem *activeItem = root;    // always points to the current child
        QDir it_dir = fi_root.dir();    // check with the locating dir
        QList<TreeItem *> lstParents;     // to calculate the model index
        bool rootDirNotMet = true;
        do {
            TreeItem *startItem = new TreeItem(it_dir.dirName());      // create the father node
            startItem->setData(QVariant(it_dir.path()));
            startItem->setIcon(QIcon(":/images/parent"));
            lstParents.append(activeItem);
            QString addr; addr.setNum((long)(void *)activeItem, 16);
            qDebug() << (activeItem->data().toString() + " @@ " + addr);    // dump all address for each path
            this->listSubDir(it_dir, startItem, activeItem);
            activeItem = startItem;
            if (!rootDirNotMet) break;   // ensure the root dir is also processed when cdUp failed
            rootDirNotMet = it_dir.cdUp();
        }  while(1);
        qDebug() << it_dir.absolutePath();
        activeItem->setParent(rootItem);             // setParent sets parentItem in the TreeItem
        activeItem->setText(it_dir.absolutePath());
        rootItem->appendChild(activeItem);
        QModelIndex itemIndex = QModelIndex(); // index(0, 0, QModelIndex());        // calculate from root index
        do {
            itemIndex = this->index(lstParents.takeLast()->row(), 0, itemIndex);
        } while (!lstParents.isEmpty());
        return itemIndex;   // return the index of the user-specified root
    }   // setupModelData
    
    void FileTreeModel::listSubDir(QDir &dir, TreeItem *parent, TreeItem *registered_child = 0) {
        if (parent->childCount() > 1) return;       // this dir has already been listed
        if (parent->hasChildren() && parent->child(0)->text().compare("")) return;  // the only child is not dummy
        QDirIterator it(dir.path(), QDirIterator::NoIteratorFlags);      // check this parent node
        while (it.hasNext()) {      // check each child
            QString full_path;
            QFileInfo fi = QFileInfo(full_path = it.next());
            if (!fi.fileName().compare(".") || !fi.fileName().compare("..")) continue;        // ignore "." and ".."
            TreeItem *siblingItem;
            if (registered_child && registered_child->data().toString() == full_path) {     // this is registered child
                siblingItem = registered_child;
                parent->appendChild(siblingItem);
            } else if (parent->childCount() == 1 && parent->child(0)->text().compare("") == 0) { // can reuse the dummy item
                siblingItem = parent->child(0);
                siblingItem->setText(fi.fileName());
            } else {    // need a new node for the item
                siblingItem = new TreeItem(fi.fileName());
                parent->appendChild(siblingItem);
            }   // else for a new node
            if (fi.isDir()) {  // is directory
                siblingItem->setIcon(QIcon(":/images/parent"));
                TreeItem *dummyItem = new TreeItem("");     // dummy child to mark the folder to expand
                siblingItem->appendChild(dummyItem);
            } else {    // a file
                siblingItem->setIcon(QIcon(":/images/child"));
            } // else of if dir
            siblingItem->setData(full_path);
            siblingItem->setParent(parent);
            QString addr; addr.setNum((long)(void *)siblingItem, 16);
            qDebug() << (siblingItem->data().toString() + " ## " + addr);    // dump all address for each found child
        }   // while it.hasNext
    }   // listSubDir
    


  • The reason that I added dummy child is to make all directories expandable, a lazy expansion.



  • The dummy child is the culprit. It did not set the parent so the parent is invalid.



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.