QFileSystemModel rowCount does not work as expected

不羁岁月 提交于 2019-12-12 12:15:59

问题


I am try an example in Model/View Programming.

http://doc.qt.io/qt-5/model-view-programming.html

To demonstrate how data can be retrieved from a model, using model indexes, we set up a QFileSystemModel without a view and display the names of files and directories in a widget. Although this does not show a normal way of using a model, it demonstrates the conventions used by models when dealing with model indexes.

We construct a file system model in the following way:

QFileSystemModel *model = new QFileSystemModel;
QModelIndex parentIndex = model->index(QDir::currentPath());
int numRows = model->rowCount(parentIndex);

In this case, we set up a default QFileSystemModel, obtain a parent index using a specific implementation of index() provided by that model, and we count the number of rows in the model using the rowCount() function.

This is my code:

QFileSystemModel* model = new QFileSystemModel;
QModelIndex parentIndex = model->index(QDir::currentPath());
qDebug() << QDir::currentPath();
// "/media/Local Data/Files/Programming/C++/build-DemostrateQModelIndex-Desktop_Qt_5_5_1_GCC_64bit-Debug"
qDebug() << "RowCount is " << model->rowCount(parentIndex);

But RowCount is always 0.

In the "build-DemostrateQModelIndex-Desktop_Qt_5_5_1_GCC_64bit-Debug" folder, there is files and folder inside. I expect row count should be the number of items inside.

I also tried initialized the QFileSystemModel;

QFileSystemModel* model = new QFileSystemModel;
model->setRootPath(QDir::rootPath());
QModelIndex parentIndex = model->index(QDir::currentPath());
qDebug() << "RowCount is " << model->rowCount(parentIndex);

RowCount is still 0.

Update 1: Applying the suggestion from Johannes Schaub. I add an QEventLoop to my code.

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QFileSystemModel* model = new QFileSystemModel;
    model->setRootPath(QDir::rootPath());
    QModelIndex parentIndex = model->index(QDir::currentPath());
    qDebug() << QDir::currentPath();
    // "/media/Local Data/Files/Programming/C++/build-DemostrateQModelIndex-Desktop_Qt_5_5_1_GCC_64bit-Debug"
    qDebug() << "First RowCount Call is " << model->rowCount(parentIndex);

    QEventLoop loop;
    QObject::connect(model, &QFileSystemModel::directoryLoaded, &loop, &QEventLoop::quit);
    loop.exec();
    qDebug() << "RowCount Call after eventloop is  " << model->rowCount(parentIndex);

    return a.exec();
}

I still get a row count of 0.


回答1:


QFileSystemModel utilizes lazy and deferred loading. You need to watch on its signals, which will be emitted constantly until the entire directory has been loaded.

In particular, the docs say

Unlike QDirModel, QFileSystemModel uses a separate thread to populate itself so it will not cause the main thread to hang as the file system is being queried. Calls to rowCount() will return 0 until the model populates a directory.

In your case, you could probably run a local QEventLoop and connect the respective signals (directoryLoaded) of the model with the quit() slot of the event loop to wait for the population. I am unsure whether canFetchMore and fetchMore can be used for this scenario aswell to block on waiting for the population (afaik its main use is lazy loading when the user scrolls down in an infinite list, like for example a facebook pinwall stream). It's worth an attempt, at least.

@Kuba notes correctly that a local event loop is not intrinsically required. If you can afford leaving the context in which you create the QFileSystemModel (by storing it as a pointer member for example), and acting on the slot as a normal member function.




回答2:


The principle to use is:

  • Create the model and set its root path. At this stage you can assum the model is still empty or very few data have been loaded.
  • Let the model load data in its separate internal thread. Connect the directoryLoaded signal to a slot. When the model will have loaded the root path, the signal will be sent.
  • In the slot, check if the folder you are interested in is fully loaded. It won't at first. The reason is the model loads using lazy methods, and likely only the root path folder will be ready.
  • If your folder is not fully ready, asks the model to load it. This is done by using model.canFetchMore and model.fetchMore with the index of the folder of interest, and returning immediately (or you could try to work with folder entries already ready, but this alternative requires to manage the progress of the model readiness).
  • When the slot is ready (likely just after calling model.fetchMore, the test canFetchMore will return False, meaning the folder you're interested in is fully loaded and model.rowCount will now return the correct value. If you're interested in another folder, use model.canFetchMore and model.fetchMore again with the index of the new folder.

Instead of using model.canFetchMore, you may also compare the path of the folder of interest with the argument passed to the slot. This string indicates the path the signal was sent for.


You indicated you're using C++, I don't have a code in this language, however the following code in Python can be easily translated (self = this, and indented lines are equivalent to a pair of brackets in delimiting a block)


class MyWidget(QPlainTextEdit):

    def __init__(self):

        # Init superclass
        super(MyWidget, self).__init__()
        self.setReadOnly(True)
        self.show()

        # FS model, set root path
        self.model = QFileSystemModel()
        path = "C:/"
        self.model.setRootPath(path)

        # Perform next tasks after model root path is loaded
        self.model.directoryLoaded.connect(self.on_loaded)

    def on_loaded(self, loaded_path):
        # Folder to list
        folder_path = "C:/Users"  # <--- we are interested in this folder,
                                  #      not the root folder
        folder_index = self.model.index(folder_path)

        # Check the folder we are interested in is completely loaded
        if self.model.canFetchMore(folder_index):
            self.model.fetchMore(folder_index)
            return

        # Folder is now loaded, list children
        num_rows = self.model.rowCount(folder_index)
        for row in range(num_rows):
            # Child data
            num_columns = self.model.columnCount(folder_index)
            if num_columns > 0:
                # Child name in first column
                index = self.model.index(row, 0, folder_index)
                text += index.data(Qt.DisplayRole)

                # etc


来源:https://stackoverflow.com/questions/33544645/qfilesystemmodel-rowcount-does-not-work-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!