1. 概述
QAbstractItemModel是Qt框架中的一个核心抽象基类,在Qt的模型/视图架构中扮演着至关重要的角色。这个类提供了一个接口,用于表示和管理数据,但不直接处理数据的存储。它的主要功能是为视图组件(如QListView、QTableView和QTreeView等)提供一个标准化的接口,使其能够访问和操作数据。通过这种方式,QAbstractItemModel实现了数据处理(模型)与数据展示(视图)的分离,从而简化了复杂数据的管理和展示。
2. 重要方法
QAbstractItemModel类中有多个重要的方法,这些方法使得开发者能够自定义数据的访问和操作方式。以下是一些关键的方法:
- index(int row, int column, const QModelIndex &parent = QModelIndex()) const:返回给定行、列和父节点的模型索引。
- parent(const QModelIndex &index) const:返回给定模型索引的父节点的模型索引。
- rowCount(const QModelIndex &parent = QModelIndex()) const:返回给定父节点下的行数。
- columnCount(const QModelIndex &parent = QModelIndex()) const:返回给定父节点下的列数。
- data(const QModelIndex &index, int role = Qt::DisplayRole) const:返回给定模型索引和角色的数据。
- setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole):将给定模型索引设置为指定的值。
- moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild):将源模型索引的特定行移动到目标模型索引的特定行位置,并返回移动是否成功的布尔值。
这些方法共同构成了QAbstractItemModel类提供的数据访问和操作接口。
3. 重要信号
QAbstractItemModel类还定义了一些重要的信号,用于通知视图组件数据的更新。以下是一些关键的信号:
- dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>()):当模型中的数据发生变化时,发出此信号以通知视图组件更新显示。
- layoutChanged():当模型的布局发生变化时(例如,行或列的插入、删除或移动),发出此信号以通知视图组件重新布局。
- rowsInserted(const QModelIndex &parent, int start, int end):当在给定父节点下插入新行时,发出此信号。
- rowsRemoved(const QModelIndex &parent, int start, int end):当从给定父节点下删除行时,发出此信号。
这些信号使得视图组件能够响应模型数据的变化,从而保持数据的一致性和准确性。
4、重要角色和标志
以下是QAbstractltemModel类中一些常见的角色和标志及其简要介绍:
角色(Role)
- Qt::DisplayRole:用于显示的数据。
- Qt::EditRole:用于编辑的数据。
- Qt::ToolTipRole:用于显示工具提示的数据。
- Qt::DecorationRole:用于显示装饰图标的数据。
- Qt::CheckstateRole:用于显示复选框状态的数据。
标志(Flags)
- Qt::ItemIsSelectable:项是可选中的。
- Qt::ItemIsEditable:项是可编辑的。
- Qt::ItemIsEnabled:项是启用的。
- Qt::ItemIsUserCheckable:项是用户可复选的。
- Qt::ItemIsDragEnabled:项可拖拽。
- Qt::ItemIsDropEnabled:项可放下。
二维表格模型
#include <QApplication>
#include <QMainWindow>
#include <QTableView>
#include <QVariant>
#include <QVector>
class TableModel : public QAbstractItemModel
{
Q_OBJECT
public:
TableModel(QObject *parent = nullptr) : QAbstractItemModel(parent)
{
// 初始化数据
dataList = {
{"Alice", "30", "Engineer"},
{"Bob", "25", "Designer"},
{"Charlie", "35", "Manager"}
};
}
// 获取行数
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
if (parent.isValid()) return 0;
return dataList.size();
}
// 获取列数
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
if (parent.isValid()) return 0;
return dataList.isEmpty() ? 0 : dataList[0].size();
}
// 获取数据项的值
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
{
if (!index.isValid() || role != Qt::DisplayRole)
return QVariant();
return dataList[index.row()][index.column()];
}
// 标题
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal) {
switch (section) {
case 0: return "Name";
case 1: return "Age";
case 2: return "Occupation";
}
}
return QVariant();
}
// 返回指定位置的索引
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
{
if (parent.isValid() || !hasIndex(row, column, parent))
return QModelIndex();
return createIndex(row, column);
}
// 返回父索引
QModelIndex parent(const QModelIndex &index) const override
{
return QModelIndex();
}
// 获取数据项的标志属性
Qt::ItemFlags flags(const QModelIndex &index) const override
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
}
private:
QVector<QVector<QString>> dataList;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 创建主窗口
QMainWindow mainWindow;
mainWindow.setWindowTitle("QAbstractItemModel Example");
mainWindow.resize(400, 300);
// 创建自定义表模型
TableModel *model = new TableModel;
// 创建表视图
QTableView *tableView = new QTableView;
tableView->setModel(model);
tableView->horizontalHeader()->setStretchLastSection(true);
tableView->setEditTriggers(QAbstractItemView::DoubleClicked);
// 布局管理
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(tableView);
QWidget *centralWidget = new QWidget;
centralWidget->setLayout(layout);
mainWindow.setCentralWidget(centralWidget);
// 显示主窗口
mainWindow.show();
return app.exec();
}
树状模型
#include <QApplication>
#include <QMainWindow>
#include <QTreeView>
#include <QVariant>
#include <QVector>
class TreeItem
{
public:
explicit TreeItem(const QVector<QVariant> &data, TreeItem *parentItem = nullptr)
: itemData(data), parentItem(parentItem) {}
~TreeItem() { qDeleteAll(childItems); }
void appendChild(TreeItem *child) { childItems.append(child); }
TreeItem *child(int row) { return childItems.value(row); }
int childCount() const { return childItems.count(); }
int columnCount() const { return itemData.count(); }
QVariant data(int column) const { return itemData.value(column); }
int row() const { return parentItem ? parentItem->childItems.indexOf(const_cast<TreeItem*>(this)) : 0; }
TreeItem *parent() { return parentItem;}
private:
QVector<TreeItem*> childItems;
QVector<QVariant> itemData;
TreeItem *parentItem;
};
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
TreeModel(QObject *parent = nullptr)
: QAbstractItemModel(parent)
{
QVector<QVariant> rootData {"Title 1", "Title 2"};
rootItem = new TreeItem(rootData);
QVector<QVariant> childData1 {"Child 1", "Child Data 1"};
TreeItem *childItem1 = new TreeItem(childData1, rootItem);
rootItem->appendChild(childItem1);
QVector<QVariant> childData2 {"Child 2", "Child Data 2"};
TreeItem *childItem2 = new TreeItem(childData2, childItem1);
childItem1->appendChild(childItem2);
}
~TreeModel() { delete rootItem; }
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
TreeItem *parentItem = parent.isValid() ? static_cast<TreeItem*>(parent.internalPointer()) : rootItem;
return parentItem->childCount();
}
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
TreeItem *parentItem = parent.isValid() ? static_cast<TreeItem*>(parent.internalPointer()) : rootItem;
return parentItem->columnCount();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
{
if (!index.isValid() || role != Qt::DisplayRole)
return QVariant();
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
return item->data(index.column());
}
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
{
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeItem *parentItem = parent.isValid() ? static_cast<TreeItem*>(parent.internalPointer()) : rootItem;
TreeItem *childItem = parentItem->child(row);
return childItem ? createIndex(row, column, childItem) : QModelIndex();
}
QModelIndex parent(const QModelIndex &index) const override
{
if (!index.isValid())
return QModelIndex();
TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
TreeItem *parentItem = childItem->parent();
if (parentItem == rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
Qt::ItemFlags flags(const QModelIndex &index) const override
{
if (!index.isValid())
return Qt::NoItemFlags;
return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
}
private:
TreeItem *rootItem;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 创建主窗口
QMainWindow mainWindow;
mainWindow.setWindowTitle("QAbstractItemModel Example - Tree");
mainWindow.resize(400, 300);
// 创建自定义树模型
TreeModel *model = new TreeModel;
// 创建树视图
QTreeView *treeView = new QTreeView;
treeView->setModel(model);
// 布局管理
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(treeView);
QWidget *centralWidget = new QWidget;
centralWidget->setLayout(layout);
mainWindow.setCentralWidget(centralWidget);
// 显示主窗口
mainWindow.show();
return app.exec();
}
#include "main.moc"
觉得有帮助的话,打赏一下呗。。