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:
parent
43d6778ce5
commit
2393a40ccd
Binary file not shown.
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user