一.简介
QListView
是 Qt 中用于显示列表数据的控件。
它是 MVC(模型-视图-控制器)架构的一部分,通常与 QAbstractListModel
或其子类结合使用;
使用QListView 可以使用设计界面拖拽或者使用代码编写;
二.数据填充
1.简单数据填充
比如字符串列表QStringList
QStringList dataList = {"Item 1", "Item 2", "Item 3"};
QStringListModel *model = new QStringListModel(dataList);
ui->listView->setModel(model);
创建了一个字符串列表,并使用 QStringListModel
将其设置为 QListView
的模型。这样,列表视图就会展示出这些字符串。
2.自定义模型
a.使用字符串列表
#include <QAbstractListModel>
#include <QListView>
#include <QStringList>
class MyModel : public QAbstractListModel
{
Q_OBJECT
public:
MyModel(QObject *parent = nullptr)
: QAbstractListModel(parent)
{
m_data << "item1" << "item2" << "item3";
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
Q_UNUSED(parent);
return m_data.count();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
{
if (!index.isValid())
return QVariant();
if (index.row() >= m_data.size())
return QVariant();
if (role == Qt::DisplayRole)
return m_data.at(index.row());
else
return QVariant();
}
private:
QStringList m_data;
};
这是一个最基本的自定义数据模型,rowCount
方法返回项的总数,而 data
方法根据索引返回相应的数据。自定义模型实际并非如此简单.里面还涉及到数据修改.角色项等.这个后面单独写一篇吧.
3.数据库数据绑定
当数据存储在数据库中时,您可以使用 QSqlTableModel
来将数据绑定到 QListView
。这个模型提供了一个接口来读取和写入数据库表。
#include <QSqlTableModel>
#include <QListView>
//执行以下代码前提是数据库已经打开;
以下代码只是演示如何使用数据库数据绑定到view
QSqlTableModel *tableModel = new QSqlTableModel;
tableModel->setTable("your_table_name");
tableModel->select();
ui->listView->setModel(tableModel);
在这段代码中,我们指定了要操作的数据库表,并通过调用 select
方法加载了数据。然后,我们将模型设置到 QListView
,数据库中的数据就会显示在列表视图中。
三.自定义委托以及外观
1.自定义委托
a.使用Qt现有控件,比如按钮
//继承QItemDelegate该类也是可以的,只是目前新的基本都继承QStyledItemDelegate 更加灵活
class ButtonDelegate : public QStyledItemDelegate {
public:
ButtonDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
QPushButton *editor = new QPushButton(parent);
// 这里可以设置按钮的属性,例如文本、图标等
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const override {
QPushButton *button = static_cast<QPushButton*>(editor);
// 根据模型数据设置按钮的显示
QString value = index.model()->data(index, Qt::DisplayRole).toString();
button->setText(value);
}
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const
QModelIndex &index) const override {
editor->setGeometry(option.rect);
}
};
b.使用自绘
#include <QStyledItemDelegate>
#include <QPainter>
class ButtonDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
ButtonDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
QStyleOptionButton button;
button.rect = option.rect.adjusted(4, 4, -4, -4);
button.text = index.model()->data(index, Qt::DisplayRole).toString();
button.state = QStyle::State_Enabled;
QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter);
}
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override {
if (event->type() == QEvent::MouseButtonRelease) {
// 在这里处理按钮点击事件
emit buttonClicked(index);
return true;
}
return false;
}
signals:
void buttonClicked(const QModelIndex &index);
};
四.复杂数据处理
要在 QListView
中展示复杂的数据结构,并利用角色(Roles)和自定义数据模型,需要以下几个步骤:
-
定义复杂数据结构: 首先,定义一个复杂的数据结构。例如,一个包含多个字段的类或结构体。
-
创建自定义数据模型: 创建一个继承自
QAbstractListModel
或QAbstractItemModel
的自定义模型类。在这个模型类中,实现必要的方法,如data()
、rowCount()
和roleNames()
。 -
实现角色(Roles): 在自定义模型中,定义额外的角色来代表数据结构中的不同元素。这通常是通过在
roleNames()
方法中返回一个角色名与角色值的映射来完成的。 -
填充模型数据: 填充自定义模型的数据。这涉及到将复杂数据结构的实例添加到模型中。
-
在
QListView
中使用模型: 创建QListView
的实例,并将自定义模型设置给它。
自定义委托(可选): 如果需要,可以创建一个自定义委托来自定义数据项的呈现方式。
class MyData {
public:
QString name;
int age;
};
class MyModel : public QAbstractListModel {
Q_OBJECT
public:
enum DataRoles {
NameRole = Qt::UserRole + 1,
AgeRole
};
MyModel(QObject *parent = nullptr) : QAbstractListModel(parent) {
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override {
return dataList.size();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
if (!index.isValid() || index.row() >= dataList.size())
return QVariant();
const MyData &item = dataList.at(index.row());
switch (role) {
case NameRole:
return item.name;
case AgeRole:
return item.age;
default:
return QVariant();
}
}
QHash<int, QByteArray> roleNames() const override {
QHash<int, QByteArray> roles;
roles[NameRole] = "name";
roles[AgeRole] = "age";
return roles;
}
private:
QList<MyData> dataList;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MyModel model;
// 填充模型数据
// ...
QListView listView;
listView.setModel(&model);
listView.show();
return app.exec();
}
使用如自定义模型.只是将其代理数据从字符串列表更换为了类列表.当然,使用结构体等其他数据类型也是可以的.某些时候.若是在信号里面传输自定义数据结构.需要注册到Qt的元对象系统;
五.高级定制
要高级定制 QListView
,涉及到视觉效果的定制、性能优化以及交互功能的增强。下面是具体的实现步骤和代码示例:
1. 视觉效果定制
a. 自定义外观
可以通过重写 paint
方法或使用 Qt 样式表(QSS)来自定义 QListView
的外观。
使用样式表示例
一般来说.做项目的时候会单独写一个qss文件.作为整个程序的外观文件,并全局加载.
listView->setStyleSheet("QListView {"
" background-color: #f0f0f0;"
" color: #333;"
" border: 1px solid #ddd;"
"}"
"QListView::item {"
" padding: 5px;"
"}"
"QListView::item:selected {"
" background-color: #3399ff;"
" color: white;"
"}");
2. 性能优化
a. 面对大量数据的性能考虑
对于大量数据,应考虑使用合适的数据结构和高效的模型更新方法。使用 beginInsertRows
和 endInsertRows
来批量添加或删除项目。
b. 延迟加载和视图的虚拟化
延迟加载(Lazy Loading)是指仅在需要显示数据时才加载它们。可以通过在模型的 data
方法中实现按需加载来达到这个目的。
3. 交互增强
交互增强对于 QListView
而言,主要包括实现拖放、排序和过滤等功能。这些功能可以显著提高用户体验,尤其是在处理大量数据项的时候。以下是每个功能的具体实现方法:
1. 拖放功能
为了在 QListView
中启用拖放功能,您需要设置相应的属性,并实现所需的事件处理。
a. 启用拖放: 首先,开启 QListView
的拖放功能,并设置拖放模式。
listView->setDragEnabled(true); // 启用拖拽
listView->viewport()->setAcceptDrops(true); // 接受拖放
listView->setDropIndicatorShown(true); // 显示拖放指示器
listView->setDragDropMode(QAbstractItemView::InternalMove); // 设置拖放模式
b. 实现拖放事件: 您可能需要重写以下方法来自定义拖放行为:
dragEnterEvent(QDragEnterEvent *event)
:处理拖动进入视图的事件。dragMoveEvent(QDragMoveEvent *event)
:处理拖动时的事件。dropEvent(QDropEvent *event)
:处理放置操作的事件。
2. 排序功能
要实现排序功能,通常需要使用 QSortFilterProxyModel
作为模型的代理。
a. 设置代理模型: 创建一个 QSortFilterProxyModel
实例,并将其设置为模型的代理。
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(listView);
proxyModel->setSourceModel(yourModel); // yourModel 是原始数据模型
listView->setModel(proxyModel);
b. 启用和实现排序: 通过点击列头或使用代码来触发排序。
proxyModel->setSortRole(Qt::UserRole); // 设置排序所依据的角色
proxyModel->sort(0, Qt::AscendingOrder); // 根据第一列进行升序排序
3. 过滤功能
过滤功能也可以通过 QSortFilterProxyModel
实现。
a. 设置过滤条件: 设置过滤角色和过滤规则。
proxyModel->setFilterRole(Qt::DisplayRole); // 设置过滤所依据的角色
proxyModel->setFilterRegExp(QRegExp("过滤条件", Qt::CaseInsensitive, QRegExp::FixedString));
b. 动态过滤: 您可以根据用户输入或其他条件动态更改过滤规则。
void updateFilter(const QString &text) {
proxyModel->setFilterRegExp(QRegExp(text, Qt::CaseInsensitive, QRegExp::FixedString));
}
通过以上步骤,您可以为 QListView
实现丰富的交互功能,使其更加动态和易用。
结论
QListview相较于QListWidget更加灵活多变.拥有更多的可塑性.