Qt model/view 理解01

news2024/10/6 0:31:05

在 Qt 中对数据处理主要有两种方式:1)直接对包含数据的的数据项 item 进行操作,这种方法简单、易操作,现实方式单一的缺点,特别是对于大数据或在不同位置重复出现的数据必须依次对其进行操作,如果现实方式改变,则在改动程序过程中还需对数据进行重新编码操作,费工费资源。2)采用 model/view 模型,将数据 -- 模型 -- 视图三者串起来,通过约定的接口保证数据的正确显示和显示方式的多样性,当需要重新调整显示时,只需修改视图,保证接口不变,即可以新 view 显示数据。

1/2 两种处理数据方式:

视图与数据绑定在一起:

视图与数据隔离:

在此,我主要介绍第二种模型:model/view模式,在此以QAbstractTableModel/QTableView 为例。

如果是只读模式,model 只要重写以下三个方法:

//a方法:返回模型行数。
int rowCount(const QModelIndex &parent) const; 

//b方法:返回模型列数。
int columnCount(const QModelIndex &parent) const; 

//c方法:返回index项的role角色的数据。其中index项中可以有多个角色,每个角色都可以有一个数据。
QVariant data(const QModelIndex &index, int role) const;

如果用户要能够编辑数据(编辑模式),model 还需要重写以下两个方法:

//d方法:设置模型中项的内容。
bool QAbstractItemModel::setData(const QModelIndex & index, 
                                 const QVariant & value, 
                                 int role= Qt::EditRole);

//e方法:返回项的编辑形式,默认情况下只有ItemIsSelectable和ItemIsEnabled,如果要可编辑,需要
//添加ItemIsEditable属性。
Qt::ItemFlags QAbstractTableModel::flags(const QModelIndex & index) const

其中 a/b/c 方法为纯虚函数(pure virtual method),继承的类必须由 coder 自己实现此方法。d/e 方法为虚函数(virtual),coder 在继承了此方法,实现自定义内容后可直接调用基类方法。

在此我们以《c++ gui programming with Qt4》中的 trackEditor 例子作一讲解。

class MyTableModel : public QAbstractTableModel
{
public:
    explicit MyTableModel(QList<Track>* tracks, QWidget *parent = 0);

    virtual int rowCount(const QModelIndex &parent) const;
    virtual int columnCount(const QModelIndex &parent) const;
    virtual QVariant data(const QModelIndex &index, int role) const;
    virtual QVariant headerData(int section,
                                Qt::Orientation orientation,
                                int role) const;
    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
    virtual bool setData(const QModelIndex &index, const QVariant &value, int role);

private:
    QList<Track>* pTracks;
};

其中 “QList<Track>* tracks” 是用来保存 model 所显示的数据集合,在 model 初始化时被赋值,根据 data 方法的算法调用其中数据显示。

MyTableModel::MyTableModel(QList<Track>* tracks, QWidget *parent)
{
    Q_UNUSED(parent);

    pTracks = tracks;
}

构造函数对 tracks 进行赋值。

int MyTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return pTracks->count();
}

int MyTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return 2;
}

以上 2 个方法返回 model 的行 / 列数,因为 tracks 中的数据量不确定,所以直接返回其 count 方法,保证每次都是最新值;

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if ( !index.isValid()) {
        return QVariant();
    }

    if (Qt::DisplayRole == role || Qt::EditRole == role) {
        if (0 == index.column()) {
            return pTracks->at(index.row()).getTitle();
        } else if (1 == index.column()) {
            return pTracks->at(index.row()).getDuration();
        }
    }

    return QVariant();
}

根据数据类型和所在列,返回不同的数据信息,当 index 都不属于以上两种情况时,返回 QVariant 对象。EditRole 保证了当用户编辑数据时,数据显示的是被选中模式而不是直接消失。

bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if ( !index.isValid()) {
        return false;
    }

    if (Qt::EditRole == role) {
        (*pTracks)[index.row()].setTitle(value.toString());
        emit dataChanged(index, index);

        return true;
    } else {
        return QAbstractTableModel::setData(index, value, role);
    }
}

根据 coder 处理和传入角色,设置 index 处项的值及 tracks 中对应处的数据并更新 index 的数据显示。当传入数据 coder 不处理时,则直接调用基类方法处理,再辞没有特别指明第几列进行编辑,因为是后面通过 flags 方法来设定了可编辑的列,故此处不用再特别指明。在此请注意,setData 方法是判断的是 Qt::EditRole 角色,data 方法是 Qt::DisplayRole,但是保存、读取的都是 tracks,这正是 coder 要注意的,在不同的过程时,程序所处于的角色不同,但是都操作同样的数据库(tracks),这点要注意。

Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{
    if (0 == index.column()) {
        return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
    } else {
        return QAbstractTableModel::flags(index);
    }
}

model 中每个项的处理标志位默认为(ItemIsEnabled | ItemIsSelectable),coder 可根据要求对不同属性的项进行设置。在此设定第 0 列可编辑,其余列不可编辑。

程序运行结果,分别用 TableView 和 ListView 显示相同的数据:

具体代码如下:共有 maindialg,mytablemodel,tack 三个类,一个 main 运行类。具体界面文件是由 Qt 自己生成的 ui。

track.h

#ifndef TRACK_H
#define TRACK_H

#include <QString>

class Track
{
public:
    explicit Track(const QString& title = "", int duration = 0);

    QString getTitle() const;
    int getDuration() const;

    void setDuration(int duration);
    void setTitle(QString title);

private:
    QString mTitle;
    int mDuration;
};

#endif // TRACK_H

track.cpp

#include "track.h"

Track::Track(const QString &title, int duration) :
    mTitle(title),
    mDuration(duration)
{

}

QString Track::getTitle() const
{
    return mTitle;
}

int Track::getDuration() const
{
    return mDuration;
}

void Track::setDuration(int duration)
{
    mDuration = duration;
}

void Track::setTitle(QString title)
{
    mTitle = title;
}

mytablemodel.h

#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H

#include <QWidget>
#include <QAbstractTableModel>
#include "track.h"

class MyTableModel : public QAbstractTableModel
{
public:
    explicit MyTableModel(QList<Track>* tracks, QWidget *parent = 0);

    virtual int rowCount(const QModelIndex &parent) const;
    virtual int columnCount(const QModelIndex &parent) const;
    virtual QVariant data(const QModelIndex &index, int role) const;
    virtual QVariant headerData(int section,
                                Qt::Orientation orientation,
                                int role) const;
    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
    virtual bool setData(const QModelIndex &index, const QVariant &value, int role);

private:
    QList<Track>* pTracks;
};

#endif // MYTABLEMODEL_H

mytablemodel.cpp

#include "mytablemodel.h"

MyTableModel::MyTableModel(QList<Track>* tracks, QWidget *parent)
{
    Q_UNUSED(parent);

    pTracks = tracks;
}

int MyTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return pTracks->count();
}

int MyTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);

    return 2;
}

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if ( !index.isValid()) {
        return QVariant();
    }

    if (Qt::DisplayRole == role) {
        if (0 == index.column()) {
            return pTracks->at(index.row()).getTitle();
        } else if (1 == index.column()) {
            return pTracks->at(index.row()).getDuration();
        }
    }

    return QVariant();
}

QVariant MyTableModel::headerData(int section,
                                  Qt::Orientation orientation,
                                  int role) const
{
    /*if (Qt::Vertical == orientation) {
        return QVariant();
    }*/

    if (Qt::DisplayRole == role && Qt::Horizontal == orientation) {
        switch (section) {
        case 0:
            return "first";

        case 1:
            return "second";
        }
    }

    return QVariant();
}

Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{
    if (0 == index.column()) {
        return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
    } else {
        return QAbstractTableModel::flags(index);
    }
}

bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if ( !index.isValid()) {
        return false;
    }

    if (Qt::EditRole == role) {
        (*pTracks)[index.row()].setTitle(value.toString());
        emit dataChanged(index, index);

        return true;
    } else {
        return QAbstractTableModel::setData(index, value, role);
    }
}

maindialog.h

#ifndef MAINDIALOG_H
#define MAINDIALOG_H

#include <QDialog>
#include <QTableView>
#include <QListView>
#include "mytablemodel.h"

namespace Ui {
class MainDialog;
}

class MainDialog : public QDialog
{
    Q_OBJECT

public:
    explicit MainDialog(QWidget *parent = 0);
    ~MainDialog();

    void setTableModel(MyTableModel* model);

    void setListModel(MyTableModel* model);

private:
    Ui::MainDialog *ui;

    QTableView* pTableView;
    QListView* pListView;
};

#endif // MAINDIALOG_H

maindialog.cpp

#include<QGridLayout>
#include "maindialog.h"
#include "ui_maindialog.h"

MainDialog::MainDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::MainDialog),
    pTableView(new QTableView(this)),
    pListView(new QListView(this))
{
    ui->setupUi(this);

    QVBoxLayout* layout(new QVBoxLayout(this));
    layout->addWidget(pTableView);
    layout->addWidget(pListView);
    setLayout(layout);

    setAttribute(Qt::WA_DeleteOnClose);
}

MainDialog::~MainDialog()
{
    delete ui;
}

void MainDialog::setTableModel(MyTableModel *model)
{
    pTableView->setModel(model);
}

void MainDialog::setListModel(MyTableModel* model)
{
    pListView->setModel(model);
}

main.cpp

#include <QApplication>
#include "maindialog.h"
#include "track.h"
#include "mytablemodel.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QList<Track> tracks;
        tracks << Track("The Flying Dutchman: Overture", 630)
               << Track("The Flying Dutchman: Wie aus der Fern laengst "
                        "vergangner Zeiten", 374)
               << Track("The Flying Dutchman: Steuermann, lass die Wacht",
                        152)
               << Track("Die Walkuere: Ride of the Valkyries", 286)
               << Track("Tannhaeuser: Freudig begruessen wir die edle "
                        "Halle", 384)
               << Track("Tannhaeuser: Wie Todesahnung - O du mein holder "
                        "Abendstern", 257)
               << Track("Lohengrin: Treulich gefuert ziehet dahnin", 294)
               << Track("Lohengrin: In fernem Land", 383)
               << Track("Die Meistersinger von Nuernberg: Overture", 543)
               << Track("Die Meistersinger von Nuernberg: Verachtet mir "
                        "die Meister nicht", 200)
               << Track("Die Meistersinger von Nuernberg: Ehrt eure "
                        "deutschen Meister", 112)
               << Track("Goetterdaemmerung: Funeral Music", 469)
               << Track("Tristan und Isolde: Mild und leise, wie er "
                        "laechelt", 375);

    MyTableModel model(&tracks);

    MainDialog* w(new MainDialog(0));
    w->setTableModel(&model);
    w->setListModel(&model);
    w->show();

    return a.exec();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1062681.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

了解基于Elasticsearch 的站内搜索,及其替代方案

对于一家公司而言&#xff0c;数据量越来越多&#xff0c;如果快速去查找这些信息是一个很难的问题&#xff0c;在计算机领域有一个专门的领域IR&#xff08;Information Retrival&#xff09;研究如何获取信息&#xff0c;做信息检索。在国内的如百度这样的搜索引擎也属于这个…

Linux系统编程系列之线程池

Linux系统编程系列&#xff08;16篇管饱&#xff0c;吃货都投降了&#xff01;&#xff09; 1、Linux系统编程系列之进程基础 2、Linux系统编程系列之进程间通信(IPC)-信号 3、Linux系统编程系列之进程间通信(IPC)-管道 4、Linux系统编程系列之进程间通信-IPC对象 5、Linux系统…

Linux文件查找、别名、用户组

1、文件查看: 查看/etc/passwd文件的第5行 2、文件查找 (1)在当前目录及子目录中&#xff0c;查找大写字母开头的txt文件 (2)在/etc及其子目录中&#xff0c;查找以数字开头的文件 (3)在$HOME目录及其子目录中&#xff0c;查找所有文本文件 (4)忽略文件名大小写查找a.txt 3、查…

博途1200/1500 ALT指令

SMART PLC的ALT指令实现代码,请查看下面文章博客 SMART PLC如何构造ALT指令_smart200类似alt指令-CSDN博客单按钮启停这些老生常谈的问题,很多人感兴趣。这篇博文讨论下不同的实现方法,希望对大家有所帮助。指令虽然简单,但是在编程的时候合理使用对我们高效率编程帮助还是…

来聊一聊独热码检测

国庆假期不小心扭伤了脚踝&#xff0c;在家没事看到一篇文章挺有意思&#xff0c;于是写出来分享给大家。 这是一道数字电路面试题&#xff0c;也是很多面试官很喜欢考察面试者的一道题目&#xff0c;题干很简单&#xff1a;给定一个4bit的信号A&#xff0c;设计逻辑来判断A是…

博客之站项目测试报告

项目背景项目功能测试计划Bug总结升级自动化测试正常登录流程 项目背景 1&#xff1a;博客之站系统是采用前后端分离的方式来实现&#xff1b;使用MySQL、Redis数据库储存相关数据&#xff1b;同时部署到云服务器上。 2&#xff1a;包含注册页、登录页、博客列表页、个人列表页…

计算机考研 | 2020年 | 计算机组成原理真题

文章目录 【计算机组成原理2020年真题43题-13分】【第一步&#xff1a;信息提取】【第二步&#xff1a;具体解答】 【计算机组成原理2020年真题44题-10分】【第一步&#xff1a;信息提取】【第二步&#xff1a;具体解答】 【计算机组成原理2020年真题43题-13分】 【第一步&…

vertx的学习总结6之动态代理类和测试

Beyond the event bus 一、章节覆盖&#xff1a; 如何在事件总线之上公开服务 verticles和事件总线服务的异步测试 动态代理&#xff1a; MyService 接口 package porxy.test;import io.vertx.codegen.annotations.ProxyGen;ProxyGen public interface MyService {void he…

基于ssm的电商管理平台/基于javaweb的网上购物系统/电子商城网站

摘 要 本文论述了电商管理平台的设计和实现&#xff0c;该网站从实际运用的角度出发&#xff0c;运用了计算机网站设计、数据库等相关知识&#xff0c;基于SSM框架、JSP技术和Mysql数据库设计来实现的&#xff0c;网站主要包括用户注册、用户登录、查看商品信息、系统公告等…

优化方法的应用(optimtool.example)

import optimtool as oo from optimtool.base import np, sp, pltpip install optimtool>2.4.2优化方法的应用&#xff08;optimtool.example&#xff09; import optimtool.example as oeLasso问题&#xff08;Lasso&#xff09; oe.Lasso.[函数名]([矩阵A], [矩阵b], [因…

Linux删除空目录/非空目录和文件

一、删除目录 删除名为mydir的空目录: rmdir mydir 删除名为mydir的非空目录(非空目录是指该目录包含了其他文件或子目录&#xff0c;而不是空的或没有任何内容的目录) rm -r mydir 删除mydir1下的空目录mydir2 rmdir mydir1/mydir2 删除当前目录下所有以dir一个数字结尾的目录…

打开MySQL数据库

在命令行里输入mysql --version就可以查看&#xff1a; mysql -uroot -p之前设置的密码&#xff08;不用输入&#xff09;就可登录成功&#xff1a;

什么是邮件签名证书?

邮件签名证书是一种数字证书&#xff0c;用于保护电子邮件的安全性和可信度。邮件签名证书可以确保电子邮件本身在发送过程中不会被篡改或伪造&#xff0c;同时也可以验证发件人的身份。 邮件签名证书的工作原理是使用S/MIME协议。S/MIME协议是一种用于加密和签名电子邮件的标准…

tio-websocket-spring-boot-starter的最简单实例,看完你一定有所收获

前言 我最近一个月一直在寻找能够快速开发实时通讯的简单好用的模块,所以我就去寻找了一下相关的内容.在此之前我使用的是Spring原生的webSocket,她有个弊端就是设置组不容易设置,而且配置上也稍微复杂一点,需要配置拦截器和处理器,还需要把它放入到Springboot的启动容器里面,也…

在word文档里面插入漂亮的伪代码

推荐用texsword.0.8 安装与界面 下载链接&#xff1a;https://sourceforge.net/projects/texsword/ 极为轻便&#xff0c;是Word的一个宏 安装过程也是极为简单&#xff0c;复制解压后的 texsword.dotm 文件到 C:\Users\{YOUR_USER_NAME}\AppData\Roaming\Microsoft\Word\ST…

gitgitHub

在git中复制CtrlInsert、粘贴CtrlShif 一、用户名和邮箱的配置 查看用户名 &#xff1a;git config user.name 查看密码&#xff1a; git config user.password 查看邮箱&#xff1a;git config user.email 查看配置信息&#xff1a; $ git config --list 修改用户名 git co…

【树】树的直径和重心

目录 一.树的直径 &#xff08;1&#xff09;定义 &#xff08;2&#xff09;思路 &#xff08;3&#xff09;例题 &#xff08;4&#xff09;std(第一小问) 二.树的重心 &#xff08;1&#xff09;介绍 &#xff08;2&#xff09;求重心 &#xff08;3&#xff09;例…

全排列[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个不含重复数字的数组nums&#xff0c;返回其所有可能的全排列。你可以按任意顺序返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 示例…

【机器学习-黑马程序员】人工智能、机器学习概述

文章目录 前言一、人工智能概述二、什么是机器学习二、机器学习算法分类三、机器学习开发流程 前言 本专栏文章为观看黑马程序员《python机器学习》所做笔记&#xff0c;课程地址在这。如有侵权&#xff0c;立即删除。 一、人工智能概述 机器学习和人工智能、深度学习的关系 机…

Harbor+Trivy实现镜像漏洞扫描

文章目录 安装HarborTrivyoras下载压缩包解压并安装 离线漏洞库oras方式trivy方式配置离线库 扫描镜像harbor配置扫描镜像 使用命令扫描 安装 Harbor 安装Harbor时&#xff0c;指定--with-trivy参数同时安装trivy组件。 ./install.sh --with-trivyTrivy 下载最新版本的安装…