QFileSystemModel rowCount не работает должным образом
Я попробую пример в моделировании / программировании вида.
http://doc.qt.io/qt-5/model-view-programming.html
Чтобы продемонстрировать, как данные могут быть извлечены из модели с использованием модельных индексов, мы установили QFileSystemModel без представления и отобразили имена файлов и каталогов в виджете. Хотя это не показывает нормальный способ использования модели, он демонстрирует соглашения, используемые моделями при работе с модельными индексами.
Мы строим модель файловой системы следующим образом:
QFileSystemModel *model = new QFileSystemModel;
QModelIndex parentIndex = model->index(QDir::currentPath());
int numRows = model->rowCount(parentIndex);
В этом случае мы устанавливаем QFileSystemModel по умолчанию, получаем родительский индекс, используя конкретную реализацию index(), предоставляемую этой моделью, и подсчитываем количество строк в модели, используя функцию rowCount().
Это мой код:
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);
Но RowCount всегда равен 0.
В папке "build-DemostrateQModelIndex-Desktop_Qt_5_5_1_GCC_64bit-Debug" находятся файлы и папка внутри. Я ожидаю, что количество строк должно быть количеством элементов внутри.
Я также попытался инициализировать QFileSystemModel;
QFileSystemModel* model = new QFileSystemModel;
model->setRootPath(QDir::rootPath());
QModelIndex parentIndex = model->index(QDir::currentPath());
qDebug() << "RowCount is " << model->rowCount(parentIndex);
RowCount все еще 0.
Обновление 1: применение предложения от Йоханнеса Шауба. Я добавляю QEventLoop
к моему коду.
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();
}
Я все еще получаю количество строк 0.
3 ответа
QFileSystemModel использует отложенную и отложенную загрузку. Вам нужно следить за его сигналами, которые будут излучаться постоянно, пока не будет загружен весь каталог.
В частности, документы говорят
В отличие от QDirModel, QFileSystemModel использует отдельный поток для заполнения себя, поэтому он не приведет к зависанию основного потока при запросе файловой системы. Вызовы rowCount() будут возвращать 0, пока модель не заполнит каталог.
В вашем случае вы, вероятно, могли бы запустить локальный QEventLoop и соединить соответствующие сигналы (directoryLoaded) модели со слотом quit() цикла событий, чтобы дождаться заполнения. Я не уверен, могут ли canFetchMore и fetchMore использоваться для этого сценария, а также блокировать ожидание населения (на самом деле, его основное использование - ленивая загрузка, когда пользователь прокручивает вниз в бесконечном списке, как, например, поток пинволлов Facebook). Стоит попытаться, по крайней мере.
@Kuba правильно отмечает, что локальный цикл обработки событий не является обязательным. Если вы можете позволить себе оставить контекст, в котором вы создаете QFileSystemModel
(например, сохраняя его как член-указатель) и действуя в слоте как обычная функция-член.
Принцип использования:
- Создайте модель и установите ее корневой путь. На этом этапе вы можете предположить, что модель все еще пуста или загружено очень мало данных.
- Пусть модель загружает данные в отдельный внутренний поток. Подключите
directoryLoaded
сигнал в слот. Когда модель загрузит корневой путь, сигнал будет отправлен. - В слоте проверьте, полностью ли загружена интересующая вас папка. Сначала не будет. Причина в том, что модель загружается с использованием ленивых методов, и, вероятно, будет готова только корневая папка.
- Если ваша папка не полностью готова, попросите модель загрузить ее. Это делается с помощью
model.canFetchMore
а такжеmodel.fetchMore
с индексом интересующей папки и немедленным возвратом (или вы можете попытаться работать с уже готовыми записями в папке, но эта альтернатива требует управления ходом готовности модели). - Когда слот готов (скорее всего, сразу после звонка
model.fetchMore
, тестcanFetchMore
вернусьFalse
это означает, что интересующая вас папка полностью загружена иmodel.rowCount
теперь вернет правильное значение. Если вы заинтересованы в другой папке, используйтеmodel.canFetchMore
а такжеmodel.fetchMore
снова с индексом новой папки.
Вместо того, чтобы использовать model.canFetchMore
Вы также можете сравнить путь к интересующей папке с аргументом, переданным в слот. Эта строка указывает путь, по которому был отправлен сигнал.
Вы указали, что используете C++, у меня нет кода на этом языке, однако следующий код на Python может быть легко переведен (self
знак равно this
и строки с отступом эквивалентны паре скобок при разделении блока)
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