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> (cherry picked from commit 2393a40ccd455cc2dca410e8a1830856dbfde12d)
This commit is contained in:
parent
cd3ce03705
commit
6e73df64e2
Binary file not shown.
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
@ -34,15 +34,9 @@
|
|||||||
|
|
||||||
\image fetchmore-example.png
|
\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
|
When you have large - or perhaps even infinite - data sets, you
|
||||||
will need to add items to the model in batches, and preferably only
|
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 the view).
|
||||||
|
|
||||||
In this example, we implement \c FileListModel - an item 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
|
Window, which sets up the GUI and feeds the model with
|
||||||
directories.
|
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.
|
Let's take a tour of \c {FileListModel}'s code.
|
||||||
|
|
||||||
\section1 FileListModel Class Definition
|
\section1 FileListModel Class Definition
|
||||||
|
@ -54,8 +54,10 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
|
|
||||||
|
static const int batchSize = 100;
|
||||||
|
|
||||||
FileListModel::FileListModel(QObject *parent)
|
FileListModel::FileListModel(QObject *parent)
|
||||||
: QAbstractListModel(parent), fileCount(0)
|
: QAbstractListModel(parent)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//![4]
|
//![4]
|
||||||
@ -67,24 +69,33 @@ int FileListModel::rowCount(const QModelIndex &parent) const
|
|||||||
QVariant FileListModel::data(const QModelIndex &index, int role) const
|
QVariant FileListModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return QVariant();
|
return {};
|
||||||
|
|
||||||
if (index.row() >= fileList.size() || index.row() < 0)
|
const int row = index.row();
|
||||||
return QVariant();
|
if (row >= fileList.size() || row < 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
if (role == Qt::DisplayRole) {
|
switch (role) {
|
||||||
return fileList.at(index.row());
|
case Qt::DisplayRole:
|
||||||
} else if (role == Qt::BackgroundRole) {
|
return fileList.at(row).fileName();
|
||||||
int batch = (index.row() / 100) % 2;
|
case Qt::BackgroundRole: {
|
||||||
if (batch == 0)
|
const int batch = row / batchSize;
|
||||||
return qApp->palette().base();
|
const QPalette &palette = QGuiApplication::palette();
|
||||||
else
|
return (batch % 2) != 0 ? palette.alternateBase() : palette.base();
|
||||||
return qApp->palette().alternateBase();
|
|
||||||
}
|
}
|
||||||
return QVariant();
|
case Qt::DecorationRole:
|
||||||
|
return iconProvider.icon(fileList.at(row));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
//![4]
|
//![4]
|
||||||
|
|
||||||
|
QFileInfo FileListModel::fileInfoAt(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
return fileList.at(index.row());
|
||||||
|
}
|
||||||
|
|
||||||
//![1]
|
//![1]
|
||||||
bool FileListModel::canFetchMore(const QModelIndex &parent) const
|
bool FileListModel::canFetchMore(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
@ -99,19 +110,20 @@ void FileListModel::fetchMore(const QModelIndex &parent)
|
|||||||
{
|
{
|
||||||
if (parent.isValid())
|
if (parent.isValid())
|
||||||
return;
|
return;
|
||||||
int remainder = fileList.size() - fileCount;
|
const int start = fileCount;
|
||||||
int itemsToFetch = qMin(100, remainder);
|
const int remainder = int(fileList.size()) - start;
|
||||||
|
const int itemsToFetch = qMin(batchSize, remainder);
|
||||||
|
|
||||||
if (itemsToFetch <= 0)
|
if (itemsToFetch <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
beginInsertRows(QModelIndex(), fileCount, fileCount + itemsToFetch - 1);
|
beginInsertRows(QModelIndex(), start, start + itemsToFetch - 1);
|
||||||
|
|
||||||
fileCount += itemsToFetch;
|
fileCount += itemsToFetch;
|
||||||
|
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
|
||||||
emit numberPopulated(itemsToFetch);
|
emit numberPopulated(path, start, itemsToFetch, int(fileList.size()));
|
||||||
}
|
}
|
||||||
//![2]
|
//![2]
|
||||||
|
|
||||||
@ -121,7 +133,8 @@ void FileListModel::setDirPath(const QString &path)
|
|||||||
QDir dir(path);
|
QDir dir(path);
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
fileList = dir.entryList();
|
this->path = path;
|
||||||
|
fileList = dir.entryInfoList(QDir::NoDot | QDir::AllEntries, QDir::Name);
|
||||||
fileCount = 0;
|
fileCount = 0;
|
||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,8 @@
|
|||||||
#define FILELISTMODEL_H
|
#define FILELISTMODEL_H
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QStringList>
|
#include <QFileInfoList>
|
||||||
|
#include <QFileIconProvider>
|
||||||
|
|
||||||
//![0]
|
//![0]
|
||||||
class FileListModel : public QAbstractListModel
|
class FileListModel : public QAbstractListModel
|
||||||
@ -65,8 +66,10 @@ public:
|
|||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
QFileInfo fileInfoAt(const QModelIndex &) const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void numberPopulated(int number);
|
void numberPopulated(const QString &path, int start, int number, int total);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setDirPath(const QString &path);
|
void setDirPath(const QString &path);
|
||||||
@ -76,8 +79,10 @@ protected:
|
|||||||
void fetchMore(const QModelIndex &parent) override;
|
void fetchMore(const QModelIndex &parent) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList fileList;
|
QFileInfoList fileList;
|
||||||
int fileCount;
|
QString path;
|
||||||
|
QFileIconProvider iconProvider;
|
||||||
|
int fileCount = 0;
|
||||||
};
|
};
|
||||||
//![0]
|
//![0]
|
||||||
|
|
||||||
|
@ -56,37 +56,43 @@
|
|||||||
Window::Window(QWidget *parent)
|
Window::Window(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
FileListModel *model = new FileListModel(this);
|
model = new FileListModel(this);
|
||||||
model->setDirPath(QLibraryInfo::path(QLibraryInfo::PrefixPath));
|
model->setDirPath(QDir::rootPath());
|
||||||
|
|
||||||
QLabel *label = new QLabel(tr("&Directory:"));
|
view = new QListView;
|
||||||
QLineEdit *lineEdit = new QLineEdit;
|
|
||||||
label->setBuddy(lineEdit);
|
|
||||||
|
|
||||||
QListView *view = new QListView;
|
|
||||||
view->setModel(model);
|
view->setModel(model);
|
||||||
|
|
||||||
logViewer = new QTextBrowser(this);
|
logViewer = new QPlainTextEdit(this);
|
||||||
logViewer->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
|
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,
|
connect(model, &FileListModel::numberPopulated,
|
||||||
this, &Window::updateLog);
|
this, &Window::updateLog);
|
||||||
|
connect(view, &QAbstractItemView::activated,
|
||||||
|
this, &Window::activated);
|
||||||
|
|
||||||
QGridLayout *layout = new QGridLayout;
|
auto *layout = new QVBoxLayout(this);
|
||||||
layout->addWidget(label, 0, 0);
|
layout->addWidget(view);
|
||||||
layout->addWidget(lineEdit, 0, 1);
|
layout->addWidget(logViewer);
|
||||||
layout->addWidget(view, 1, 0, 1, 2);
|
|
||||||
layout->addWidget(logViewer, 2, 0, 1, 2);
|
|
||||||
|
|
||||||
setLayout(layout);
|
|
||||||
setWindowTitle(tr("Fetch More Example"));
|
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>
|
#include <QWidget>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QTextBrowser;
|
class QModelIndex;
|
||||||
|
class QListView;
|
||||||
|
class QPlainTextEdit;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class FileListModel;
|
||||||
|
|
||||||
class Window : public QWidget
|
class Window : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -65,10 +69,13 @@ public:
|
|||||||
Window(QWidget *parent = nullptr);
|
Window(QWidget *parent = nullptr);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateLog(int number);
|
void updateLog(const QString &path, int start, int number, int total);
|
||||||
|
void activated(const QModelIndex &);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTextBrowser *logViewer;
|
QPlainTextEdit *logViewer;
|
||||||
|
FileListModel *model;
|
||||||
|
QListView *view;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WINDOW_H
|
#endif // WINDOW_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user