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

int rowCount = ui->tableView->verticalHeader()->count();

Другие вопросы по тегам