1. QListView 基础介绍
QListView 是 Qt 框架中用于显示项目列表的控件,属于模型/视图架构的一部分。它提供了一种灵活的方式来显示和操作项目列表。
主要特点:
-
基于模型/视图架构
-
支持多种视图模式(列表、图标)
-
内置选择、编辑功能
-
可自定义项目显示方式
2. 基本使用
2.1 简单示例
#include <QApplication>
#include <QListView>
#include <QStringListModel>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建数据模型
QStringList strings;
strings << "苹果" << "香蕉" << "橙子" << "西瓜";
QStringListModel model(strings);
// 创建并设置ListView
QListView listView;
listView.setModel(&model);
listView.setWindowTitle("水果列表");
listView.resize(300, 200);
listView.show();
return app.exec();
}
2.2 常用方法
// 设置选择模式
listView.setSelectionMode(QAbstractItemView::SingleSelection); // 单选
listView.setSelectionMode(QAbstractItemView::MultiSelection); // 多选
// 设置视图模式
listView.setViewMode(QListView::ListMode); // 列表模式(默认)
listView.setViewMode(QListView::IconMode); // 图标模式
// 设置是否可编辑
listView.setEditTriggers(QAbstractItemView::NoEditTriggers); // 不可编辑
listView.setEditTriggers(QAbstractItemView::DoubleClicked); // 双击编辑
// 设置网格线
listView.setGridSize(QSize(100, 30)); // 设置项目大小
listView.setSpacing(5); // 设置项目间距
3. 数据模型使用
3.1 使用 QStringListModel
QStringListModel *model = new QStringListModel(this);
QStringList list;
list << "项目1" << "项目2" << "项目3";
model->setStringList(list);
ui->listView->setModel(model);
3.2 使用 QStandardItemModel
QStandardItemModel *model = new QStandardItemModel(this);
// 添加文本项目
QStandardItem *item1 = new QStandardItem("文本项目");
model->appendRow(item1);
// 添加带图标的项目
QStandardItem *item2 = new QStandardItem(QIcon(":/icon.png"), "带图标项目");
model->appendRow(item2);
// 添加可勾选项目
QStandardItem *item3 = new QStandardItem("可勾选项目");
item3->setCheckable(true);
item3->setCheckState(Qt::Checked);
model->appendRow(item3);
ui->listView->setModel(model);
4. 项目选择与操作
4.1 获取选中项目
// 获取当前选中项的索引
QModelIndex currentIndex = ui->listView->currentIndex();
// 获取所有选中项的索引列表
QModelIndexList selectedIndexes = ui->listView->selectionModel()->selectedIndexes();
// 通过模型获取数据
QVariant data = model->data(currentIndex, Qt::DisplayRole);
4.2 添加和删除项目
// 添加项目
void addItem(const QString &text) {
QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->listView->model());
if(model) {
model->appendRow(new QStandardItem(text));
}
}
// 删除选中项目
void removeSelectedItems() {
QStandardItemModel *model = qobject_cast<QStandardItemModel*>(ui->listView->model());
if(!model) return;
QModelIndexList selected = ui->listView->selectionModel()->selectedIndexes();
foreach(QModelIndex index, selected) {
model->removeRow(index.row());
}
}
5. 自定义显示
5.1 使用委托(Delegate)自定义项目显示
class CustomDelegate : public QStyledItemDelegate {
public:
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
if (option.state & QStyle::State_Selected) {
painter->fillRect(option.rect, QColor("#4CAF50")); // 选中项背景色
}
QStyledItemDelegate::paint(painter, option, index);
}
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override {
// 设置项目高度
QSize size = QStyledItemDelegate::sizeHint(option, index);
size.setHeight(40);
return size;
}
};
// 使用自定义委托
ui->listView->setItemDelegate(new CustomDelegate(this));
5.2 设置交替行颜色
ui->listView->setAlternatingRowColors(true);
ui->listView->setStyleSheet("alternate-background-color: #f0f0f0;");
6. 自定义模型
在 Qt 中创建自定义模型需要继承自 QAbstractItemModel 或其子类(如 QAbstractListModel)。对于列表视图,通常继承 QAbstractListModel 更为简单。
1).基本模型结构
#include <QAbstractListModel>
#include <QStringList>
class CustomListModel : public QAbstractListModel {
Q_OBJECT
public:
explicit CustomListModel(QObject *parent = nullptr);
// 必须重写的基类方法
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
// 可选重写的方法
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
// 自定义数据操作方法
void addItem(const QString &item);
void removeItem(int row);
private:
QStringList m_data; // 实际存储数据的容器
};
2). 实现自定义模型
2.1 基本实现
CustomListModel::CustomListModel(QObject *parent)
: QAbstractListModel(parent) {}
int CustomListModel::rowCount(const QModelIndex &parent) const {
// 对于列表模型,parent无效时应返回项目数
if (parent.isValid())
return 0;
return m_data.size();
}
QVariant CustomListModel::data(const QModelIndex &index, int role) const {
if (!index.isValid() || index.row() >= m_data.size())
return QVariant();
switch (role) {
case Qt::DisplayRole:
case Qt::EditRole:
return m_data.at(index.row());
case Qt::ToolTipRole:
return QString("项目: %1").arg(m_data.at(index.row()));
case Qt::TextAlignmentRole:
return Qt::AlignVCenter | Qt::AlignLeft;
default:
return QVariant();
}
}
Qt::ItemFlags CustomListModel::flags(const QModelIndex &index) const {
if (!index.isValid())
return Qt::NoItemFlags;
return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsSelectable;
}
2.2 数据操作方法
void CustomListModel::addItem(const QString &item) {
beginInsertRows(QModelIndex(), m_data.size(), m_data.size());
m_data.append(item);
endInsertRows();
}
void CustomListModel::removeItem(int row) {
if (row < 0 || row >= m_data.size())
return;
beginRemoveRows(QModelIndex(), row, row);
m_data.removeAt(row);
endRemoveRows();
}
bool CustomListModel::setData(const QModelIndex &index, const QVariant &value, int role) {
if (!index.isValid() || role != Qt::EditRole)
return false;
m_data.replace(index.row(), value.toString());
emit dataChanged(index, index, {role});
return true;
}
3). 高级自定义功能
3.1 支持拖放操作
// 在构造函数中添加
setSupportedDragActions(Qt::MoveAction);
setSupportedDropActions(Qt::MoveAction);
Qt::DropActions CustomListModel::supportedDropActions() const {
return Qt::MoveAction;
}
QStringList CustomListModel::mimeTypes() const {
return {"application/vnd.text.list"};
}
QMimeData *CustomListModel::mimeData(const QModelIndexList &indexes) const {
auto *mimeData = new QMimeData;
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
for (const QModelIndex &index : indexes) {
if (index.isValid())
stream << m_data.at(index.row());
}
mimeData->setData("application/vnd.text.list", encodedData);
return mimeData;
}
bool CustomListModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent) {
if (!data->hasFormat("application/vnd.text.list"))
return false;
QByteArray encodedData = data->data("application/vnd.text.list");
QDataStream stream(&encodedData, QIODevice::ReadOnly);
QStringList newItems;
while (!stream.atEnd()) {
QString text;
stream >> text;
newItems << text;
}
// 插入新项目
int beginRow = row != -1 ? row : rowCount(parent);
for (const QString &text : qAsConst(newItems)) {
insertRow(beginRow);
setData(index(beginRow, 0, parent), text);
beginRow++;
}
return true;
}
3.2 自定义角色
// 在头文件中定义自定义角色
enum CustomRoles {
BackgroundColorRole = Qt::UserRole + 1,
TextColorRole,
IconRole
};
// 在data()方法中添加处理
QVariant CustomListModel::data(const QModelIndex &index, int role) const {
// ... 其他代码
switch (role) {
case BackgroundColorRole:
return index.row() % 2 == 0 ? QColor("#f0f0f0") : QColor("#ffffff");
case TextColorRole:
return QColor("#333333");
case IconRole:
return QIcon(":/icons/item.png");
// ... 其他角色
}
}
4). 使用自定义模型
4.1 基本使用
CustomListModel *model = new CustomListModel(this);
model->addItem("项目1");
model->addItem("项目2");
model->addItem("项目3");
QListView *listView = new QListView;
listView->setModel(model);
// 启用拖放
listView->setDragEnabled(true);
listView->setAcceptDrops(true);
listView->setDropIndicatorShown(true);
listView->setDragDropMode(QAbstractItemView::InternalMove);
4.2 使用自定义角色
// 使用委托显示自定义角色
class CustomDelegate : public QStyledItemDelegate {
public:
using QStyledItemDelegate::QStyledItemDelegate;
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
// 获取自定义角色数据
QColor bgColor = index.data(BackgroundColorRole).value<QColor>();
QColor textColor = index.data(TextColorRole).value<QColor>();
QIcon icon = index.data(IconRole).value<QIcon>();
// 自定义绘制
painter->fillRect(opt.rect, bgColor);
QRect iconRect = opt.rect.adjusted(5, 5, -5, -5);
iconRect.setWidth(32);
icon.paint(painter, iconRect);
QRect textRect = opt.rect.adjusted(42, 0, -5, 0);
painter->setPen(textColor);
painter->drawText(textRect, Qt::AlignVCenter | Qt::AlignLeft, opt.text);
}
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override {
return QSize(200, 40);
}
};
// 设置自定义委托
listView->setItemDelegate(new CustomDelegate);
5). 性能优化技巧
1)实现 canFetchMore/fetchMore 用于大数据集的懒加载:
bool canFetchMore(const QModelIndex &parent) const override {
return !m_allDataLoaded && m_data.size() < m_totalItems;
}
void fetchMore(const QModelIndex &parent) override {
int remaining = m_totalItems - m_data.size();
int itemsToFetch = qMin(100, remaining);
if (itemsToFetch <= 0) {
m_allDataLoaded = true;
return;
}
beginInsertRows(QModelIndex(), m_data.size(), m_data.size() + itemsToFetch - 1);
// 加载更多数据...
endInsertRows();
}
2)优化 data() 方法:避免在 data() 中进行复杂计算
3)批量更新:使用 beginResetModel()/endResetModel() 进行大批量数据更新
4)使用模型测试:实现 QAbstractItemModelTester 检查模型一致性
7. 信号与槽
// 当前项变化信号
connect(ui->listView, &QListView::clicked, [](const QModelIndex &index){
qDebug() << "点击了:" << index.data().toString();
});
// 双击项目信号
connect(ui->listView, &QListView::doubleClicked, [](const QModelIndex &index){
qDebug() << "双击了:" << index.data().toString();
});
// 选择变化信号
connect(ui->listView->selectionModel(), &QItemSelectionModel::selectionChanged,
[](const QItemSelection &selected, const QItemSelection &deselected){
qDebug() << "选择已改变";
});
8. 高级功能
7.1 拖放支持
// 启用拖放
ui->listView->setDragEnabled(true); // 允许拖动
ui->listView->setAcceptDrops(true); // 接受放置
ui->listView->setDropIndicatorShown(true); // 显示放置指示器
ui->listView->setDragDropMode(QAbstractItemView::InternalMove); // 内部移动
// 自定义拖放行为需要重写模型的 mimeData() 和 dropMimeData() 方法
7.2 排序和过滤
// 启用排序
ui->listView->setSortingEnabled(true);
// 使用代理模型进行过滤
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(sourceModel);
proxyModel->setFilterRegExp(QRegExp("pattern", Qt::CaseInsensitive));
ui->listView->setModel(proxyModel);
9. 性能优化
-
大数据集处理:
// 对于大数据集,禁用不必要的功能 ui->listView->setUniformItemSizes(true); // 所有项目大小相同可提高性能 ui->listView->setViewMode(QListView::ListMode); // 列表模式比图标模式性能更好
-
自定义模型:对于复杂数据,考虑实现自定义模型,只加载可见项数据
-
避免频繁更新:批量更新数据而不是逐项更新