问题
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
andmodel.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 testcanFetchMore
will returnFalse
, meaning the folder you're interested in is fully loaded andmodel.rowCount
will now return the correct value. If you're interested in another folder, usemodel.canFetchMore
andmodel.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