Обновление QListView занимает слишком много времени, если дано 100 тыс. Элементов

У меня проблема с чтением файла, в частности, я хочу сделать небольшой словарь. В файле, который мне нужно прочитать, есть такой контент:

a   Ph  P6
a   snsr    CA
a b c   fb  Dj
a b c - book    i+  BS
A except B gate oOPa    y
a font  kQ  BU
[....]

Он имеет около 109 000 строк, а размер файла - около 2 МБ. В моем приложении QT я написал так, чтобы читать и добавлять элементы в QListWidget:

QString sWord;
QFile inFile("C:\\EV\\ev.index");

inFile.open(QIODevice::ReadOnly|QIODevice::Text);
QTextStream in(&inFile);
while(!in.atEnd())
{
     sWord = in.readLine();
     myListWidget->addItem(sWord); //myListWidget is a QListWidget
}

Но это читается слишком долго! Сначала я думаю, что причина в том, что мое приложение читает строку за строкой, поэтому я снова кодировал его так:

QString data;
QStringList listWord;
QFile inFile("C:\\EV\\ev.index");


inFile.open(QIODevice::ReadOnly|QIODevice::Text);
QTextStream in(&inFile);
data.append(in.readAll());
listWord.append(data.split('\n'));
myListWidget->addItems(listWord);
inFile.close();

Это работает быстрее!(Около 5 секунд с момента запуска приложения), все еще долго, я хочу, чтобы оно читалось быстрее. Что мне нужно сделать?

1 ответ

  1. Макет виджета списка занимает слишком много времени. Установите список виджетов uniformItemSizes свойство к истине. Это позволяет избежать дорогостоящих операций макета. Другим способом было бы установить layoutMode собственность на QListView::Batched, Это позволяет избежать дорогой выкладки всех предметов одновременно.

  2. Не используйте QListWidget если нижние накладные расходы QListView сделал бы.

  3. Добавления большого количества элементов должны быть пакетными, то есть не вставляйте элементы в модель один за другим. Вставка элементов из каждого пакета в элементарной операции, которая испускает rowsInserted или же columnsInserted сигнал только один раз.

  4. Вы не должны загружать файлы в потоке графического интерфейса. Это является источником плохого пользовательского опыта во многих приложениях, и его следует избегать с кучей презрения. Не делай этого.

Ниже приведен минимальный пример, который учитывает все это.

// https://github.com/KubaO/stackrun/tree/master/questions/filemodel-18548048
#include <QtWidgets>
#include <QtConcurrent>

void makeLines(QBuffer &buf, int count = 1000000) {
   buf.open(QIODevice::WriteOnly | QIODevice::Text);
   char line[16];
   for (int i = 0; i < count; ++i) {
      int n = qsnprintf(line, sizeof(line), "Item %d\n", i);
      buf.write(line, n);
   }
   buf.close();
}

struct StringListSource : QObject {
   Q_SIGNAL void signal(const QStringList &);
   void operator()(const QStringList &data) { emit signal(data); }
   Q_OBJECT
};

int main(int argc, char *argv[]) {
   QApplication app(argc, argv);
   QListView view;
   QStringListModel model;
   StringListSource signal;
   QObject::connect(&signal, &StringListSource::signal, &model, &QStringListModel::setStringList);
   QtConcurrent::run([&signal]{
      QBuffer file;
      signal({"Generating Data..."});
      makeLines(file);
      signal({"Loading Data..."});
      QStringList lines;
      if (file.open(QIODevice::ReadOnly | QIODevice::Text))
         while (!file.atEnd())
            lines.append(QString::fromLatin1(file.readLine()));
      file.close();
      signal(lines);
   });
   view.setModel(&model);
   view.setUniformItemSizes(true);
   view.show();
   return app.exec();
}
#include "main.moc"
Другие вопросы по тегам