Model/View(模型/视图)结构
文章目录
- Model/View(模型/视图)结构
- 简介
- 视图组件
- Model/View结构的一些概念
- 项目控件组(item Widgets)
- 模型/视图 如何使用
- 项目视图组
- 设置行的颜色交替变换
- 拖拽
- 设置编辑操作
- 其他操作
- 选择模型
- 自定义选择多行
- 全选
- 代理 Delegate
- 现有代理
- 自定义代理
- 通过QWidget设置代理
- 通过QPainter设置代理
简介
模型视图结构是Qt中用界面组件显示与编辑数据的一种结构,视图是显示和编辑数据的界面组件,模型是视图与原始数据之间的接口
视图组件
- QListView 用于显示单列的列表数据,使用于一维数据的操作
void Widget::initListModel()
{
listMod = new QStandardItemModel; // 创建模型
ui->listView->setModel(listMod); // 视图设置模型
// 增加
listMod->appendRow(new QStandardItem("item1")); // 往模型里插入数据
for (int i = 2; i < 10; i++)
listMod->appendRow(new QStandardItem(QString("item%1").arg(i)));
listMod->insertRow(2, new QStandardItem("insert item")); // 在第二行插入新的数据
// 删除
listMod->removeRows(2, 1); // 从第二行开始删除1个,不包括第二行
listMod->removeRow(8); // 删除第九行
listMod->takeRow(0); // 移除第一行,内存还在,没被释放
// 查找
QList<QStandardItem*> findItem = listMod->findItems("item5"); // 查找叫做item5的行,返回所有找到的行list
if (findItem.isEmpty())
qDebug() << "没找到";
else
for (auto& find : findItem)
qDebug() << find->text();
QStandardItem* findItem2 = listMod->item(3, 0); // 查找第三行,第0列的元素
if (findItem2)
qDebug() << findItem2->text();
findItem2->setEditable(false); // 设置不可编辑,双击没反应
findItem2->setEnabled(false); // 设置不启用,变成灰色
findItem2->setData(QString("display item"), Qt::DisplayRole);
// 在第五行插入一个元素
QMap<int, QVariant> map;
map.insert(Qt::DisplayRole, QString("display"));
map.insert(Qt::DecorationRole, QColor(0, 0, 255));
map.insert(Qt::ToolTipRole, QString("tool tip"));
auto it = listMod->item(5);
qDebug() << map;
listMod->setItemData(it->index(), map);
// 自定义数据或角色
findItem2->setData(QString("这是自定义角色"), Qt::UserRole + 1);
qDebug() << findItem2->data(Qt::UserRole + 1);
// 清除角色
findItem2->clearData();
}
- QTreeView 用于显示树状结构的数据
void Widget::initTreeModel()
{
treeMod = new QStandardItemModel;
ui->treeView->setModel(treeMod);
treeMod->appendRow(new QStandardItem("item1"));
treeMod->insertRow(1); // 在第一行插入一个空白行
QStandardItem* root1 = new QStandardItem("root1");
QStandardItem* root2 = new QStandardItem("root2");
root1->appendRow(new QStandardItem("sub item"));
QList<QStandardItem*> subItem1s;
for (int i = 0; i < 5; i++)
subItem1s.append(new QStandardItem(QString("su1b%1").arg(i)));
QList<QStandardItem*> subItem2s;
for (int i = 0; i < 5; i++)
subItem2s.append(new QStandardItem(QString("su2b%1").arg(i)));
root1->appendRow(subItem1s); // 只添加了su1b0
root2->appendRows(subItem2s); // 添加多行
treeMod->appendRow(root1);
treeMod->appendRow(root2);
}
- QTableView 显示表格状数据
void Widget::initTableModel()
{
tableMod = new QStandardItemModel;
ui->tableView->setModel(tableMod);
QList<QStandardItem*> items, items1;
for (int i = 0; i < 10; i++) {
items.append(new QStandardItem(QString("item%1").arg(i)));
items1.append(new QStandardItem(QString("abc%1").arg(i)));
}
tableMod->appendColumn(items1);
tableMod->appendRow(items);
tableMod->setHorizontalHeaderLabels(QStringList() << "h1"
<< "h2"
<< "h3"); // 添加水平方向表头
}
- QColumnView 用多个QListView显示树状层次结构
- QHeaderView 提供行表头或列表头的视图组件,如QTableView的行表头列表头
Model/View结构的一些概念
项目控件组(item Widgets)
模型/视图 如何使用
项目视图组
设置行的颜色交替变换
QPalette palet;
palet.setBrush(QPalette::Base, Qt::yellow);
palet.setBrush(QPalette::AlternateBase, Qt::green);
ui->listView->setPalette(palet);
ui->listView->setAlternatingRowColors(true); // 开启颜色交替
拖拽
ui->tableView->setDragEnabled(true); // 设置可以拖
ui->tableView->setDragDropMode(QAbstractItemView::DragDrop); // 支持拖和放
移动内容需要重写事件
设置编辑操作
ui->listView->setEditTriggers(QListView::AnyKeyPressed); // 设置按下任意键编辑
其他操作
ui->tableView->setSelectionBehavior(QTableView::SelectRows); // 设置选择方式,默认选择一行
ui->tableView->setSortingEnabled(true); // 设置自动排序,默认升序
ui->listView->setViewMode(QListView::IconMode); // 设置视图模式为图标视图
ui->listView->setFlow(QListView::TopToBottom); // 设置排列丛上到下
ui->listView->setResizeMode(QListView::Adjust); // 设置随窗口改变适应布局
ui->tableView->hideColumn(8); // 把第八列隐藏
ui->tableView->showColumn(8); // 显示
ui->tableView->setCornerButtonEnabled(false); // 设置左上角是否允许双击全选,默认是允许的
选择模型
Widget::Widget(QWidget* parent)
: QWidget(parent)
, ui(new Ui::Widget)
, model(new QStandardItemModel)
{
ui->setupUi(this);
ui->tableView->setModel(model);
QList<QStandardItem*> items[5];
for (int i = 0; i < 5; i++)
for (int j = 0; j < 10; j++)
items[i].append(new QStandardItem(QString("item%1").arg(j)));
for (int i = 0; i < 5; i++)
model->appendColumn(items[i]);
// 设置自定义选择区域
QItemSelectionModel* selectModel = ui->tableView->selectionModel(); // 获取当前的选择模型
QModelIndex leftTop = model->index(0, 0);
QModelIndex rightBottom = model->index(4, 2);
QItemSelection selection(leftTop, rightBottom);
selectModel->select(selection, QItemSelectionModel::Select);
// 获取当前选择区域,并且修改它
QModelIndexList indexs = selectModel->selectedIndexes();
for (auto& i : indexs) {
qDebug() << i.data();
QStandardItemModel* item = (QStandardItemModel*)i.model();
item->setData(i, "123", Qt::DisplayRole);
item->setData(i, QIcon("C:/Users/PVer/Pictures/Resource/派蒙.jpeg"), Qt::DecorationRole);
}
}
自定义选择多行
QModelIndex idx1 = model->index(0, 0); // 第0行第0列
QModelIndex idx2 = model->index(0, 1); // 第0行第1列
QModelIndex idx3 = model->index(1, 0); // 第1行第0列
QModelIndex idx4 = model->index(0, 2); // 第0行第2列
QItemSelection sel(idx1, idx3);
QItemSelection sel1(idx2, idx4);
selectModel->select(sel, QItemSelectionModel::SelectionFlag(0x0002 | 0x0020)); // 选中0,2行
selectModel->select(sel1, QItemSelectionModel::SelectionFlag(0x0002 | 0x0040)); // 选中1,2列
全选
QModelIndex topLeft = model->index(0, 0); // 获取左上角
QModelIndex bottomRight = model->index(model->rowCount() - 1, model->columnCount() - 1); // 获取右下角
QItemSelection selAll(topLeft, bottomRight);
selectModel->select(selAll, QItemSelectionModel::Select);
代理 Delegate
代理就是在视图组件上为编辑数据提供编辑器,如在表格组件中编辑一个单元格的数据时,缺省是使用一个QLineEdit编辑框。代理负责从数据模型获取相应的数据,然后显示在编辑器里,修改数据后,又将其保存到数据模型中。
现有代理
视图本身有一个代理,可以编辑
自定义代理
通过QWidget设置代理
- 给列表视图加入你创建的代理类
ui->tableView->setItemDelegate(new CustomDelegate); // 设置代理
- 创建一个代理的类CustomDelegate继承自QStyledItemDelegate
头文件
#ifndef CUSTOMDELEGATE_H
#define CUSTOMDELEGATE_H
#include <QStyledItemDelegate>
#include <QWidget>
class CustomDelegate : public QStyledItemDelegate {
Q_OBJECT
public:
CustomDelegate(QObject* parent = nullptr);
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override;
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
};
#endif // CUSTOMDELEGATE_H
源文件
#include "CustomDelegate.h"
#include <QSpinBox>
CustomDelegate::CustomDelegate(QObject* parent)
: QStyledItemDelegate(parent)
{
}
QWidget* CustomDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QSpinBox* box = new QSpinBox(parent);
box->setMaximum(100);
box->setMinimum(0);
box->setFrame(false); // 设置微调框不显示边框
return box;
}
void CustomDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
int v = index.data().toInt();
QSpinBox* box = dynamic_cast<QSpinBox*>(editor);
box->setValue(v); // 设置微调框里的初始数值
}
void CustomDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
QSpinBox* box = dynamic_cast<QSpinBox*>(editor);
box->interpretText();
int v = box->value();
model->setData(index, v, Qt::DisplayRole);
}
void CustomDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
editor->setGeometry(option.rect); // 设置微调框大小和位置和模型窗口重叠
}
- 此处是用微调框做的代理类,效果如图
通过QPainter设置代理
QQ聊天的例子
新建头文件
#ifndef CUSTOMDELEGAT2_H
#define CUSTOMDELEGAT2_H
#include <QStyledItemDelegate>
#include <QWidget>
class CustomDelegat2 : public QStyledItemDelegate {
Q_OBJECT
public:
explicit CustomDelegat2(QObject* parent = nullptr);
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
virtual void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override;
};
#endif // CUSTOMDELEGAT2_H
源文件
#include "CustomDelegat2.h"
#include <QPainter>
CustomDelegat2::CustomDelegat2(QObject* parent)
: QStyledItemDelegate { parent }
{
}
void CustomDelegat2::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
QRect area = option.rect; // 获取绘制区域
// 获取图标并绘制
QRect r1 = QRect(area.topLeft(), QSize(area.width() / 3, area.height()));
painter->drawPixmap(r1, QPixmap("C:/Users/PVer/Pictures/Resource/BinQQqq.bmp"));
// 绘制名称
QRect r2 = QRect(r1.topRight(), QSize(r1.width(), r1.height() / 2));
painter->drawText(r2, "梦想盛开的地方");
// 绘制消息
QRect r3 = QRect(r2.bottomLeft(), r2.size());
painter->drawText(r3, "是要做什么的");
// 绘制日期
QRect r4 = QRect(r2.topRight(), r2.size());
painter->drawText(r4, "7-23");
}
QSize CustomDelegat2::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
return QSize(option.widget->width(), 50);
}
QWidget* CustomDelegat2::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
return new QWidget(parent);
}
void CustomDelegat2::setEditorData(QWidget* editor, const QModelIndex& index) const
{
}
void CustomDelegat2::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
}
代码里加入树视图,并且设置自定义模型
listModel = new QStandardItemModel;
ui->listView->setModel(listModel);
ui->listView->setItemDelegate(new CustomDelegat2);
listModel->appendRow(new QStandardItem);
listModel->appendRow(new QStandardItem);
listModel->appendRow(new QStandardItem);