QListView开发入门
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);// 创建并设置ListViewQListView 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_OBJECTpublic: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); // 列表模式比图标模式性能更好
-
自定义模型:对于复杂数据,考虑实现自定义模型,只加载可见项数据
-
避免频繁更新:批量更新数据而不是逐项更新