Qt第十四章 模型视图

Model/View(模型/视图)结构

文章目录

简介

模型视图结构是Qt中用界面组件显示与编辑数据的一种结构,视图是显示和编辑数据的界面组件,模型是视图与原始数据之间的接口

视图组件

  • QListView 用于显示单列的列表数据,使用于一维数据的操作
c 复制代码
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 用于显示树状结构的数据
c 复制代码
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 显示表格状数据
c 复制代码
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)

模型/视图 如何使用

项目视图组

设置行的颜色交替变换

c 复制代码
    QPalette palet;
    palet.setBrush(QPalette::Base, Qt::yellow);
    palet.setBrush(QPalette::AlternateBase, Qt::green);
    ui->listView->setPalette(palet);
    ui->listView->setAlternatingRowColors(true); // 开启颜色交替

拖拽

c 复制代码
    ui->tableView->setDragEnabled(true); // 设置可以拖
    ui->tableView->setDragDropMode(QAbstractItemView::DragDrop); // 支持拖和放

移动内容需要重写事件

设置编辑操作

c 复制代码
 ui->listView->setEditTriggers(QListView::AnyKeyPressed); // 设置按下任意键编辑

其他操作

c 复制代码
	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); // 设置左上角是否允许双击全选,默认是允许的

选择模型

c 复制代码
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);
    }
}

自定义选择多行

c 复制代码
 	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列

全选

c 复制代码
    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设置代理
  1. 给列表视图加入你创建的代理类
c 复制代码
ui->tableView->setItemDelegate(new CustomDelegate); // 设置代理
  1. 创建一个代理的类CustomDelegate继承自QStyledItemDelegate
    头文件
c 复制代码
#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

源文件

c 复制代码
#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); // 设置微调框大小和位置和模型窗口重叠
}
  1. 此处是用微调框做的代理类,效果如图
通过QPainter设置代理

QQ聊天的例子

新建头文件

c 复制代码
#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

源文件

c 复制代码
#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
{
}

代码里加入树视图,并且设置自定义模型

c 复制代码
    listModel = new QStandardItemModel;
    ui->listView->setModel(listModel);
    ui->listView->setItemDelegate(new CustomDelegat2);
    listModel->appendRow(new QStandardItem);
    listModel->appendRow(new QStandardItem);
    listModel->appendRow(new QStandardItem);
相关推荐
转世成为计算机大神28 分钟前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
宅小海1 小时前
scala String
大数据·开发语言·scala
qq_327342731 小时前
Java实现离线身份证号码OCR识别
java·开发语言
锅包肉的九珍1 小时前
Scala的Array数组
开发语言·后端·scala
心仪悦悦1 小时前
Scala的Array(2)
开发语言·后端·scala
yqcoder1 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
baivfhpwxf20231 小时前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
许嵩662 小时前
IC脚本之perl
开发语言·perl
长亭外的少年2 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
直裾2 小时前
Scala全文单词统计
开发语言·c#·scala