views:

284

answers:

2

EDIT2: model.hasChildren(parentIndex) returns True, but model.rowCount(parentIndex) returns 0. Is QFileSystemModel just fubar in PyQt?

EDIT: With a bit of adaptation this all works exactly as it should if I use QDirModel. This is deprecated, but maybe QFileSystemModel hasn't been fully implemented in PyQt?


I'm learning the Qt Model/View architecture at the moment, and I've found something that doesn't work as I'd expect it to. I've got the following code (adapted from Qt Model Classes):

from PyQt4 import QtCore, QtGui

model = QtGui.QFileSystemModel()

parentIndex = model.index(QtCore.QDir.currentPath())
print model.isDir(parentIndex) #prints True
print model.data(parentIndex).toString() #prints name of current directory

rows = model.rowCount(parentIndex)
print rows #prints 0 (even though the current directory has directory and file children)

The question:

Is this a problem with PyQt, have I just done something wrong, or am I completely misunderstanding QFileSystemModel? According to the documentation, model.rowCount(parentIndex) should return the number of children in the current directory. (I'm running this under Ubuntu with Python 2.6)

The QFileSystemModel docs say that it needs an instance of a Gui application, so I've also placed the above code in a QWidget as follows, but with the same result:

import sys
from PyQt4 import QtCore, QtGui

class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        model = QtGui.QFileSystemModel()

        parentIndex = model.index(QtCore.QDir.currentPath())
        print model.isDir(parentIndex)
        print model.data(parentIndex).toString()

        rows = model.rowCount(parentIndex)
        print rows


def main():
    app = QtGui.QApplication(sys.argv)
    widget = Widget()
    widget.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
A: 

I've solved it.

The reason to use QFileSystemModel as opposed to QDirModel is because QFileSystemModel loads the data from the filesystem in a separate thread. The problem with that is that if you try to print the number of children just after it's been constructed is that it won't have loaded the children yet. The way to fix the above code is to add the following:

self.timer = QtCore.QTimer(self)
self.timer.singleShot(1, self.printRowCount)

to the end of the constructor, and add a printRowCount method which will print the correct number of children. Phew.

Skilldrick
A: 

Since you've already figured it out, just a couple of extra thoughts on what was going on with your model: QFileSystemModel::rowCount returns rows from the visibleChildren collection; I guess you're correctly identified the problem: at the time when you're checking row count it was not yet populated. I've changed your example without using timers; pls, check if it works for you:

class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)

        self.model = QtGui.QFileSystemModel()
        self.model.setRootPath(QtCore.QDir.currentPath())

    def checkParent(self):
        parentIndex = self.model.index(QtCore.QDir.currentPath())      

        print self.model.isDir(parentIndex)
        print self.model.data(parentIndex).toString()

        rows = self.model.rowCount(parentIndex)
        print "row count:", rows

def main():
    app = QtGui.QApplication(sys.argv)
    widget = Widget()
    widget.show()
    app.processEvents(QtCore.QEventLoop.AllEvents)  
    widget.checkParent()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

I believe your code should work correctly on any UI event after widget constructed is shown on the screen

regards

serge_gubenko
Thanks for the answer. Yes, adding in processEvents() achieves the same result without a timer.
Skilldrick