百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Qt Model View 框架

bigegpt 2024-09-24 07:40 4 浏览

Model-View及Qt实现

Model-View-Controller架构最早出现在SmallTalk语言中,至今出现了很多变体。

Model是负责维护数据(如管理数据库),View负责显示与用户交互(如各种界面),Controller将控制业务逻辑。这种分层的做法在大型程序中使得数据、逻辑与界面分离,便于维护更新。

Qt引入了与MVC架构相似的模式Model-View架构,并加入了代理(delegate),用于自定义数据的编辑和渲染。

因为架构中的Model以表格的抽象方式访问数据,事实上并非Model-View的最佳选择。

Qt中Model,View,Delegate均由抽象类定义,并通过信号槽进行交互:

  • Model的信号通知View数据发生了改变
  • View的信号通知用户交互事件
  • Delegate的信号在编辑数据时用于通知Model和View的状态

QAbstractItemModel是所有Model的基类,它定义了View和Delegate访问数据的接口。

模型并不存储数据,而是通过与数据源交互得到数据。数据源包括数据库,文件,内存中的对象以及IO设备。

Qt 内置了许多标准模型:

  • QStringListModel:存储简单的字符串列表。
  • QStandardItemModel:可以用于树结构的存储,提供了层次数据。
  • QFileSystemModel:本地系统的文件和目录信息。
  • QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel:存取数据库数据。

如果这些标准模型不能满足需要,可以继承QAbstractItemModel创建新的Model。

QAbstractListModel或QAbstractTableModel提供了一些基本的实现,继承它们可能是更好的选择。

QAbstractItemView是所有View的基类。Qt 还提供了一系列标准的视图:QListView用于显示列表,QTableView用于显示表格,QTreeView用于显示层次数据,它们与List,Table, Tree这些布局在一定程度上对应。

QAbstractItemDelegate则是所有委托的抽象基类。自 Qt 4.4 之后,默认的委托实现是QStyledItemDelegate。但是,QStyledItemDelegate和QItemDelegate都可以作为视图的编辑器,二者的区别在于,QStyledItemDelegate使用当前样式进行绘制。在实现自定义委托时,推荐使用QStyledItemDelegate作为基类,或者结合 Qt style sheets。

Qt开发必备技术栈学习路线和资料

QListWidget,QtreeWidget,QTableWidget

基于MVC架构,Qt提供了QListWidget,QtreeWidget,QTableWidget三个可视化组件,它们均继承了相应的View类,集成了Model-View的功能,程序员可以方便地使用这些类进行开发标准的List、Tree和Table组件。

QListWidget

QListWidget用于显示列表,QListWidget的创建方法与其它Widget一样需要指定一个父组件QListWidget(QWidget * parent = 0)。

QListWidget的列表项是QListWidgetItem对象,QListWidgetItem可以存储和显示图标及文本。

在建立QListWidgetItem 对象时指定一个QListWidget对象作为父对象即可将列表项添加到列表组件最后,调用void addItem(QListWidgetItem * item)实例方法也可以将列表项添加到列表尾。

void insertItem(int row, QListWidgetItem * item);系列重载函数可以将菜单项添加到指定的位置。

void insertItems(int row, const QStringList & labels) 与void addItems(const QStringList & labels)方法则可以批量添加列表项。

QListWidgetItem可以在创建对象的时候指定图标和文本。

QListWidgetItem(const QIcon & icon, const QString & text, QListWidget * parent = 0, int type = Type),也可以通过setIcon(const QIcon & icon)和setText(const QString & text)设置。

对于Item的显示风格有很多选择,详情可以查阅Qt文档。

QListWidget继承了QListView的setViewMode函数可以设置列表的显示风格。QListWidget定义了一系列信号,它们会在列表项被点击等事件发生时发出。

QTreeWidget

QTreeWidget用于显示树状组件,其用法与QListWidget非常相似,它的项是QTreeWidgetItem对象。

QTreeWidgetItem有非常多的重载构造函数,QTreeWidgetItem可以接受QTreeWidget或QTreeWidget作为父对象,由此可以创建树状结构。

QTreeWidget和QTreeWidgetItem中常使用QList来创建多根树。

QTreeWidget可以用来显示类似Windows资源管理器的界面。

void setColumnCount(int columns)可以设置列数目,而QTreeWidget的使用QStringList存储文本也是为了存储多列数据。

void setHeaderLabels(const QStringList & labels)可以设定列名称。

QTableWidgets

QTableWidget的用法与前两个相似,其项目类为QTableWidgetItem。初始化QTableWidget对象时需要先指定对象的宽和高,使用void setItem(int row, int column, QTableWidgetItem * item)将项目添加到指定单元格

Model

标准Model

QStringListModel

QStringListModel是最简单的模型类,具备向视图提供字符串数据的能力。QStringListModel是一个可编辑的模型,可以为组件提供一系列字符串作为数据,可以将其看作是封装了QStringList的模型。

QStringListModel很多时候都会作为QListView或者QComboBox这种只有一列的视图组件的数据模型。

void setStringList(const QStringList & strings);用于设置QStringListModel所维护的StringList,使用View的void setModel(QAbstractItemModel * model)函数将View与Model关联。

QFileSystemModel

QFileSystemModel的作用是维护一个目录的信息。因此,它不需要保存数据本身,而是保存这些在本地文件系统中的实际数据的一个索引。我们可以利用QFileSystemModel访问文件系统信息、甚至通过模型来修改文件系统。QTreeView是最适合应用QFileSystemModel的视图。

model = new QFileSystemModel;
model->setRootPath(QDir::currentPath());

treeView = new QTreeView(this);
treeView->setModel(model);
treeView->setRootIndex(model->index(QDir::currentPath()));

自定义Model

QAbstractItemModel定义了Model的标准接口。QAbstractItemModel及其派生类均以表格的形式提供访问数据。

自定义Model需要继承QAbstractItemModel并重写下列函数:

  • data()
  • QVariant QAbstractItemModel::data(const QModelIndex & index,
    int role = Qt::DisplayRole) const

访问数据的接口,QModelIndex是存储Model表格的索引,index.row()和index.column()可以得到索引中指向的行或列。

role是一个枚举代表了数据的渲染方式,QVariant是变体型可以被转换为任意Qt兼容的数据类型。

  • setData()
  • bool QAbstractItemModel::setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole)

写入数据的接口。

  • dataChanged信号
  • void QAbstractItemModel::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector & roles = QVector ())

在数据被改变后由setData()方法发送dataChanged()信号,通知视图刷新数据。使用两个QModelIndex通知刷新的范围。

此外还有一些工具函数:

  • rowCount() / columnCount()

返回模型的行数 / 列数。

  • headerData()

返回表头信息。

示例:

显示汇率表的应用,底层的数据使用一个QMap<QString, double>类型的数据,作为key的QString是货币名字,作为value的double是这种货币对美元的汇率

CurrencyModel.h

class CurrencyModel : public QAbstractTableModel 
{ 
	Q_OBJECT
public: 
        CurrencyModel(QObject *parent = 0); 
        void setCurrencyMap(const QMap<QString, double> &map); 
        int rowCount(const QModelIndex &parent) const; 
        int columnCount(const QModelIndex &parent) const; 
        QVariant data(const QModelIndex &index, int role) const; 
		bool setData(const QModelIndex &index, const QVariant &value, int role); 
        QVariant headerData(int section, Qt::Orientation orientation, int role) const; 
private: 
        QString currencyAt(int offset) const; 
        QMap<QString, double> currencyMap; 
};

CurrencyModel.cpp

CurrencyModel::CurrencyModel(QObject *parent) 
    : QAbstractTableModel(parent) 
{ 
} 
 
int CurrencyModel::rowCount(const QModelIndex & parent) const 
{ 
        return currencyMap.count(); 
} 
 
int CurrencyModel::columnCount(const QModelIndex & parent) const 
{ 
        return currencyMap.count(); 
} 
 
QVariant CurrencyModel::data(const QModelIndex &index, int role) const 
{ 
        if (!index.isValid()) 
                return QVariant(); 
 
        if (role == Qt::TextAlignmentRole) { 
                return int(Qt::AlignRight | Qt::AlignVCenter); 
        } 
		else if (role == Qt::DisplayRole) { 
                QString rowCurrency = currencyAt(index.row()); 
                QString columnCurrency = currencyAt(index.column()); 
                if (currencyMap.value(rowCurrency) == 0.0) 
                        return "####"; 
                double amount = currencyMap.value(columnCurrency) / currencyMap.value(rowCurrency);
                return QString("%1").arg(amount, 0, 'f', 4); 
        } 
        return QVariant(); 
}

bool CityModel::setData(const QModelIndex &index, const QVariant &value, int role) 
{ 

	if (!index.isValid() || role != Qt::EditRole) {
		return false;
	}
    if ( currencyAt(index.column()) == "USD") { 
			QString currency = currencyAt(index.row());
			currencyMap[currency] = toInt(value);

            QModelIndex columnIndexBegin = createIndex(index.column(),0);
			QModelIndex columnIndexEnd = createIndex(index.column(),currencyMap.count()- 1);
            emit dataChanged(columnIndexBegin, columnIndexEnd);

			QModelIndex rawIndexBegin = createIndex(0,index.raw());
			QModelIndex rawIndexEnd = createIndex(currencyMap.count()- 1,index.raw());
            emit dataChanged(rawIndexBegin, rawIndexEnd); 
            return true; 
    } 
    return false; 
}  
 
QVariant CurrencyModel::headerData(int section, Qt::Orientation orientation, int role) const 
{ 
        if (role != Qt::DisplayRole) 
                return QVariant(); 
        return currencyAt(section); 
} 
 
void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map) 
{ 
        currencyMap = map; 
        reset(); 
} 
 
QString CurrencyModel::currencyAt(int offset) const 
{ 
        return (currencyMap.begin() + offset).key(); 
}

Qt开发必备技术栈学习路线和资料

Qt学习资料→「链接」

相关推荐

5分钟调色大片的方法(5分钟调色大片的方法有哪些)

哈喽大家好。在大家印象中一定觉得ps非常难学非常难。大家不要着急,小编的教学都是针对ps零基础的同学的,而且非常实用哦。只要大家跟着图文练习一两遍,保证大家立马学会~!好了,废话少说,下面开始我们今天...

闪白特效原来是这么用的(闪白特效怎么使用)

作者|高艳侠订阅|010-86092062闪白特效是影视作品中应用比较多的效果之一,那么具体该在哪些场景使用闪白特效?具体该如何操作?下面就以AdobePremiere(以下简称PR)为例,...

ppt常用小图标去哪里找?3个矢量素材网站推荐!

ppt是一个注重可视化表达的演示载体,除了高清图片,ppt中另一类常用的素材是各种小图标,也叫矢量图标,巧妙运用小图标能提升整体美观度和表现力,那么ppt常用小图标去哪里找呢?为方便各位快速找到合适的...

有什么好用的截图录屏工具?试试这9款

经常有朋友反馈苦于缺乏截屏和录屏的趁手工具,本期我们分享几个相当好用的截屏和录屏工具,希望能帮到大家。ScreenToGifScreenToGif是一款免费且开源的录屏工具。此款工具最大的特点是可以...

配色苦手福音!专业快速色环配色PS插件

今天橘子老师给的大家介绍的是一款快速配色的插件,非常强大配色苦手福音来啦!(获取方式见文末)【插件介绍】配色在后期设计中占有主导地位,好的配色能让作品更加抢眼Coolorus这款专业的配色插件,能够...

如何用PS抠主体?(ps怎么抠主体)

1.主体法抠图-抠花苞和花梗导入一张荷花苞的照片,点击上图中顶部“选择”菜单栏,下拉单击“主体”。可以看到,只有花苞被选中,但是花梗并没有被选中。接下来单击上图中左侧工具栏的“快速选择工具”,上图中顶...

2799元的4K电视,有保障吗?(买4k电视机哪个品牌好)

在上一期《电脑报》的3·15专题报道中,我们揭露了一款不靠谱的42英寸4K智能电视——TCLD42A561U。这款售价2699元的4K智能电视不仅4K画质方面存在严重问题,而且各种功能和应用体验也不理...

苹果电脑的Touch Bar推出一段时间了 这款工具可以帮你开发适用于它的APP

距离苹果推出带有TouchBar的MacBookPro已经有一段时间了,除了那些像Adobe、Google和Microsoft大公司在开发适用于TouchBar的应用之外,其实还有很多独立的开...

如魔法般吸取颜色的桌灯(如魔法般吸取颜色的桌灯叫什么)

色彩为生活带来的感官刺激,逐渐被视为理所当然。一盏桌灯运用它的神奇力量,将隐藏于物件中的颜色逐一释放,成为装点环境的空间魔法师。ColorUp是一款可以改变颜色的吸色台灯,沿用传统灯泡的造型,融入了拾...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

ps拾色器快捷键是什么?(ps2019拾色器快捷键)

ps拾色器快捷键是什么?文章末尾有获取方式,按照以下步骤就能自动获得!学会制作PS特效需要一定程度的耐心和毅力。初学者可以从基本的工具和技术开始学习,逐渐提高他们的技能水平。同时,观看更多优秀的特效作...

免费开源的 Windows 截图录屏工具,支持 OCR 识别和滚动截图等

功能很强大、安装很小巧的免费截图、录屏工具,提供很多使用的工具来帮我么能解决问题,推荐给大家。关于ShareXShareX是一款免费的windows工具,起初是一个小巧的截图工具,经过多年的迭...

入门到精通系列PS教程:第13篇 · 拾色器、颜色问题说明及补充

入门到精通系列PS教程:第13篇·拾色器、颜色问题说明及补充作者|侯潇问题说明我的第12篇教程里,有个小问题没有说清楚。要说是错误,又不算是错误,只是没有说准确。写完那篇教程后,因为已经到了深...

PS冷知识:用吸管工具吸取屏幕上的任意颜色

今天,我们给大家介绍PS中的一个冷知识:用吸管工具可以吸取屏幕上的任意颜色。其实,操作起来是非常简单的。大多数情况下,我们认为,PS的吸管工具只能吸取PS软件作图区域范围内的颜色,最多加上画布四周的...

Windows 11 将提供内置颜色选择器工具

Windows11内置了颜色选择器,可以扫描并识别屏幕上的颜色并生成颜色代码。此外,微软还利用人工智能技术,让屏幕上的文本扫描和选择变得更加便捷。这两项功能均已在SnippingToolv1...