Rewrite the fetchmore example

- Start in root folder so that large directories (/bin/, Windows)
  are easily reachable
- Remove the line edit and navigate by double clicking instead
  since this is more in line with expectations
- Use a QPlainTextEdit for logging
- Make the log message more informative
- Add icons

Change-Id: Ia3cd7fc143efef80772923291f0b711913aa47be
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
This commit is contained in:
Friedemann Kleint 2021-04-22 11:29:08 +02:00
parent 43d6778ce5
commit 2393a40ccd
6 changed files with 87 additions and 53 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -34,15 +34,9 @@
\image fetchmore-example.png
This example consists of a dialog where you can enter a directory
name in the \uicontrol Directory edit field. The application loads and
visualizes all files it finds as you are typing. It is not required
to press [Enter] to launch the search.
When you have large - or perhaps even infinite - data sets, you
will need to add items to the model in batches, and preferably only
when the items are needed by the view (i.e., when they are visible
when the items are needed by the view (i.e., when they become visible
in the view).
In this example, we implement \c FileListModel - an item view
@ -50,6 +44,15 @@
Window, which sets up the GUI and feeds the model with
directories.
The UI consists of a dialog with a list showing the contents
of the root directory. Directories can be navigated by double-clicking.
At the bottom, there is a log window displaying messages when the view
asks the model for more data.
To exercise it, navigate to a large directory (say \c /bin), and scroll
to the bottom. Log messages appear showing the data being retrieved.
Let's take a tour of \c {FileListModel}'s code.
\section1 FileListModel Class Definition

View File

@ -54,8 +54,10 @@
#include <QDir>
#include <QPalette>
static const int batchSize = 100;
FileListModel::FileListModel(QObject *parent)
: QAbstractListModel(parent), fileCount(0)
: QAbstractListModel(parent)
{}
//![4]
@ -67,24 +69,33 @@ int FileListModel::rowCount(const QModelIndex &parent) const
QVariant FileListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
return {};
if (index.row() >= fileList.size() || index.row() < 0)
return QVariant();
const int row = index.row();
if (row >= fileList.size() || row < 0)
return {};
if (role == Qt::DisplayRole) {
return fileList.at(index.row());
} else if (role == Qt::BackgroundRole) {
int batch = (index.row() / 100) % 2;
if (batch == 0)
return qApp->palette().base();
else
return qApp->palette().alternateBase();
switch (role) {
case Qt::DisplayRole:
return fileList.at(row).fileName();
case Qt::BackgroundRole: {
const int batch = row / batchSize;
const QPalette &palette = QGuiApplication::palette();
return (batch % 2) != 0 ? palette.alternateBase() : palette.base();
}
return QVariant();
case Qt::DecorationRole:
return iconProvider.icon(fileList.at(row));
}
return {};
}
//![4]
QFileInfo FileListModel::fileInfoAt(const QModelIndex &index) const
{
return fileList.at(index.row());
}
//![1]
bool FileListModel::canFetchMore(const QModelIndex &parent) const
{
@ -99,19 +110,20 @@ void FileListModel::fetchMore(const QModelIndex &parent)
{
if (parent.isValid())
return;
int remainder = fileList.size() - fileCount;
int itemsToFetch = qMin(100, remainder);
const int start = fileCount;
const int remainder = int(fileList.size()) - start;
const int itemsToFetch = qMin(batchSize, remainder);
if (itemsToFetch <= 0)
return;
beginInsertRows(QModelIndex(), fileCount, fileCount + itemsToFetch - 1);
beginInsertRows(QModelIndex(), start, start + itemsToFetch - 1);
fileCount += itemsToFetch;
endInsertRows();
emit numberPopulated(itemsToFetch);
emit numberPopulated(path, start, itemsToFetch, int(fileList.size()));
}
//![2]
@ -121,7 +133,8 @@ void FileListModel::setDirPath(const QString &path)
QDir dir(path);
beginResetModel();
fileList = dir.entryList();
this->path = path;
fileList = dir.entryInfoList(QDir::NoDot | QDir::AllEntries, QDir::Name);
fileCount = 0;
endResetModel();
}

View File

@ -52,7 +52,8 @@
#define FILELISTMODEL_H
#include <QAbstractListModel>
#include <QStringList>
#include <QFileInfoList>
#include <QFileIconProvider>
//![0]
class FileListModel : public QAbstractListModel
@ -65,8 +66,10 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QFileInfo fileInfoAt(const QModelIndex &) const;
signals:
void numberPopulated(int number);
void numberPopulated(const QString &path, int start, int number, int total);
public slots:
void setDirPath(const QString &path);
@ -76,8 +79,10 @@ protected:
void fetchMore(const QModelIndex &parent) override;
private:
QStringList fileList;
int fileCount;
QFileInfoList fileList;
QString path;
QFileIconProvider iconProvider;
int fileCount = 0;
};
//![0]

View File

@ -56,37 +56,43 @@
Window::Window(QWidget *parent)
: QWidget(parent)
{
FileListModel *model = new FileListModel(this);
model->setDirPath(QLibraryInfo::path(QLibraryInfo::PrefixPath));
model = new FileListModel(this);
model->setDirPath(QDir::rootPath());
QLabel *label = new QLabel(tr("&Directory:"));
QLineEdit *lineEdit = new QLineEdit;
label->setBuddy(lineEdit);
QListView *view = new QListView;
view = new QListView;
view->setModel(model);
logViewer = new QTextBrowser(this);
logViewer->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
logViewer = new QPlainTextEdit(this);
logViewer->setReadOnly(true);
logViewer->setSizePolicy(QSizePolicy(QSizePolicy::Preferred,
QSizePolicy::Preferred));
connect(lineEdit, &QLineEdit::textChanged,
model, &FileListModel::setDirPath);
connect(lineEdit, &QLineEdit::textChanged,
logViewer, &QTextEdit::clear);
connect(model, &FileListModel::numberPopulated,
this, &Window::updateLog);
connect(view, &QAbstractItemView::activated,
this, &Window::activated);
QGridLayout *layout = new QGridLayout;
layout->addWidget(label, 0, 0);
layout->addWidget(lineEdit, 0, 1);
layout->addWidget(view, 1, 0, 1, 2);
layout->addWidget(logViewer, 2, 0, 1, 2);
auto *layout = new QVBoxLayout(this);
layout->addWidget(view);
layout->addWidget(logViewer);
setLayout(layout);
setWindowTitle(tr("Fetch More Example"));
}
void Window::updateLog(int number)
void Window::updateLog(const QString &path, int start, int number, int total)
{
logViewer->append(tr("%1 items added.").arg(number));
const int last = start + number - 1;
const QString nativePath = QDir::toNativeSeparators(path);
const QString message = tr("%1..%2/%3 items from \"%4\" added.")
.arg(start).arg(last).arg(total).arg(nativePath);
logViewer->appendPlainText(message);
}
void Window::activated(const QModelIndex &index)
{
const QFileInfo fi = model->fileInfoAt(index);
if (fi.isDir()) {
logViewer->clear();
model->setDirPath(fi.absoluteFilePath());
}
}

View File

@ -54,9 +54,13 @@
#include <QWidget>
QT_BEGIN_NAMESPACE
class QTextBrowser;
class QModelIndex;
class QListView;
class QPlainTextEdit;
QT_END_NAMESPACE
class FileListModel;
class Window : public QWidget
{
Q_OBJECT
@ -65,10 +69,13 @@ public:
Window(QWidget *parent = nullptr);
public slots:
void updateLog(int number);
void updateLog(const QString &path, int start, int number, int total);
void activated(const QModelIndex &);
private:
QTextBrowser *logViewer;
QPlainTextEdit *logViewer;
FileListModel *model;
QListView *view;
};
#endif // WINDOW_H