Can't get QColumnView to display more than one row of data with my QAbstractItemModel-derived class



  • I'm implementing a custom model using QAbstractItemModel that I want to have displayed in a QColumnView. The data in the model is a simple hierarchy of directories and files, where each directory can contain files and other directories.

    My QAbstractItemModel-derived class is called MyModel. It relies on two other QObject-derived classes, Directory and Item. Directory has a few methods for returning the number of items it contains (including subdirectories), getting an item at a particular index, and so on. For the purposes of this code so far, File just has a name and is contained by instances of Directory. MyModel also contains a method called invisibleTopLevelDirectory() that returns the Directory that is the root of this hierarchy.

    The problem is that my QColumnView doesn't display the data correctly. Each column displays at most one row, regardless of how many rows it's supposed to have. I have no idea why! As near as I can tell I'm implemented my QAbstractItemModel-derived class correctly. Even more confounding is that if I use a QTreeView instead of a QColumnView, the tree view does display all of the data.

    Here is the relevant code:

    // Returns the instance of Directory at the given index, or NULL if the data
    // is not a Directory instance.
    Directory *directoryAtModelIndex(const QModelIndex &index)
    {
    	return qobject_cast<Directory *>((QObject *)index.internalPointer());
    }
    
    // Returns the instance of File at the given index, or NULL if the data
    // is not a File instance.
    File *fileAtModelIndex(const QModelIndex &index)
    {
    	return qobject_cast<File *>((QObject *)index.internalPointer());
    }
    
    QModelIndex MyModel::index(int row, int column, const QModelIndex &parent) const
    {
    	if (!hasIndex(row, column, parent)) {
            return QModelIndex();
    	}
    	
        Directory *parentDirectory;
    
    	if (!parent.isValid()) {
            parentDirectory = invisibleTopLevelDirectory();
        } else {
            parentDirectory = (Directory *)(parent.internalPointer());
    	}
    	
    	if (!parentDirectory) {
    		return QModelIndex();
    	}
    	
    	QObject *item = parentDirectory->itemAtIndex(row);
    	
    	if (item) {
    		return createIndex(row, column, item);
    	} else {
    		return QModelIndex();
    	}
    }
    
    QModelIndex MyModel::parent(const QModelIndex &index) const
    {
    	if (!index.isValid()) {
    		return QModelIndex();
    	}
    	
    	QObject *item = (QObject *)index.internalPointer();
    	Directory *parentItem = qobject_cast<Directory *>(item->parent());
    	
    	if (!parentItem || parentItem == invisibleTopLevelDirectory()) {
    		return QModelIndex();
    	}
    	
    	int listIndex = parentItem->indexOfItem(item);
    	
    	if (listIndex < 0) {
    		return QModelIndex();
    	} else {
    		return createIndex(listIndex, index.column(), parentItem);
    	}
    }
    
    int MyModel::rowCount(const QModelIndex &parent) const
    {
    	if (parent.column() > 0) {
    		return 0;
    	}
    	
    	if (!parent.isValid()) {
    		return invisibleTopLevelDirectory() ? invisibleTopLevelDirectory()->itemCount() : 0;
    	}
    	
    	Directory *parentItem = directoryAtModelIndex(parent);
    	
    	if (parentItem) {
    		return parentItem->itemCount();
    	} else {
    		return 0;
    	}
    }
    
    int MyModel::columnCount(const QModelIndex &parent) const
    {
    	Q_UNUSED(parent);
    	return 1;
    }
    
    QVariant MyModel::data(const QModelIndex &index, int role) const
    {
    	if (!index.isValid()) {
    		return QVariant();
    	}
    	
    	if (role == Qt::DisplayRole) {
    		if (Directory *item = directoryAtModelIndex(index)) {
    			return item->name;
    		} else if (File *item = fileAtModelIndex(index)) {
    			return item->name;
    		}	
    	}
    	
    	return QVariant();
    }
    

    I've poured over this code several times and I simply cannot figure out why my QColumnView does not ever display more than one row of data for any given column. I've used print statements to confirm that index() and data() are being called for rows passed the first, rowCount() is being called for all parent items and is returning the correct number of rows, and parent() is returning the correct row, column, and parent QModelIndex. This is particularly confirmed by the fact that if I use this same model in a QTreeView it works correctly.

    Can anyone figure out what I'm doing wrong?



  • Someone on stackoverflow was kind enough to point out my error. My parent method() should have been:

    QModelIndex MyModel::parent(const QModelIndex &index) const
    {
    	if (!index.isValid()) {
    		return QModelIndex();
    	}
    	
    	QObject *item = (QObject *)index.internalPointer();
    	Directory *parentItem = qobject_cast<Directory *>(item->parent());
    	
    	if (!parentItem || parentItem == invisibleTopLevelDirectory()) {
    		return QModelIndex();
    	}
    	
    	Directory *parentOfParentItem = qobject_cast<Directory *>(parentItem->parent());
    	
    	if (!parentOfParentItem) {
    		return QModelIndex();
    	}
    	
    	int listIndex = parentOfParentItem->indexOfItem(parentItem);
    	
    	if (listIndex < 0) {
    		return QModelIndex();
    	} else {
    		return createIndex(listIndex, index.column(), parentItem);
    	}
    }


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