使用C++实现QML的TreeView Model (一)_PHP教程
使用C++实现QML的TreeView Model (一)
QML中的数据访问组件如ListView、TableView、GridView通常使用ListModel做为数据提供者,这种应用有相当大局限性,如无法访问本地文件系统、无法连接到传统的SQL数据库,所以通常在使用中都是通过C++实现数据访问,通过QML进行数据展示和编辑,常用的数据模型组件有QAbstractItemModel、QAbstractTableModel、QSQLTableModel等。所有的高级Model组件都继承自QAbstractItemModel,只要了解QAbstractItemModel的接口函数和运作机理,就可以了解QT的Model/View机制实现方式。QAbstractItemModel是一个抽象类,要实例化QAbstractItemModel必须继承并至少实现以下5个方法:
int rowCount(const QModelIndex &parent=QModelIndex()) const;
int columnCount(const QModelIndex &parent=QModelIndex()) const;
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const;
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
QModelIndex parent(const QModelIndex &child) const;
与 QWidget组件不同的是,在QML的数据模型中,并不通过列(Column)进行数据访问,而是通过Role进行数据访问,例如:
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>TableView{<br /> </li><li>id:tableView1<br /></li><li>anchors.fill: parent<br /></li><li>TableViewColumn{<br /></li><li>width:50<br /></li><li>title:""<br /></li><li>role:"tagging" </li><li>}<br /></li><li><br /></li><li>TableViewColumn{<br /></li><li>width:80<br /></li><li>title:"操作"<br /></li><li>role:"name" </li><li>} </li><li>} </li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>QHash<int,QByteArray> roleNames() const; </li></ol>
以下是一个完整的Model类定义:
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>classSqlMenuEntry:public QAbstractItemModel,public QQmlParserStatus<br /> </li><li>{<br /></li><li>Q_OBJECT<br /></li><li>public:<br /></li><li>explicit SqlMenuEntry(QObject *parent=0);<br /></li><li>~SqlMenuEntry();<br /></li><li>enum MenuEntryRoles{idRole=Qt::UserRole+1,nameRole,defaultEntryRole,customEntryRole,iconRole,iconHoverRole};<br /></li><li>int rowCount(const QModelIndex &parent=QModelIndex()) const;<br /></li><li>int columnCount(const QModelIndex &parent=QModelIndex()) const;<br /></li><li>QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const;<br /></li><li>QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;<br /></li><li>QModelIndex parent(const QModelIndex &child) const;<br /></li><li>QHash<int,QByteArray>roleNames() const;<br /></li><li>private:<br /></li><li>QHash<int,QByteArray> mRoleNames;<br /></li><li> QList<QHash<int,QVariant>> mRecords; //真正的数据保存在这里,QList只能保存二维数据没办法保存树状节点,这里仅仅是例子<br /></li><li>};<br /></li><li><br /></li><li></li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>QHash<int, QByteArray> SqlMenuEntry::roleNames() const<br /> </li><li>{<br /></li><li>return mRoleNames;<br /></li><li>} </li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>SqlMenuEntry::SqlMenuEntry(QObject *parent)<br /> </li><li>:QAbstractItemModel(parent)<br /></li><li>{<br /></li><li>mRoleNames[nameRole] = "name";<br /></li><li>mRoleNames[idRole] = "menuid";<br /></li><li>mRoleNames[iconRole] = "icon";<br /></li><li>mRoleNames[defaultEntryRole] = "default";<br /></li><li>mRoleNames[iconHoverRole] = "iconHover";<br /></li><li>} </li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>ListView{<br /> </li><li>model:MenuEntryModel{ }<br /></li><li>delegate:Item{<br /></li><li>Column{<br /></li><li>Text{text:name}<br /></li><li> Text{text:icon}<br /></li><li>}<br /></li><li>}<br /></li><li>} </li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>int SqlMenuEntry::rowCount(const QModelIndex &parent) const<br /> </li><li>{<br /></li><li> return mRecords.size();</li><li><br /></li><li>} </li><li>int SqlMenuEntry::columnCount(const QModelIndex &parent) const </li><li>{ </li><li> return 1; //QML不使用列获取数据,默认返回一列,不返回1例的话,View控件会认为表是空表,不获取数据 </li><li>} </li><li>QModelIndex SqlMenuEntry::index(int row, int column, const QModelIndex &parent) const </li><li>{ </li><li> if((row >= 0)&&(row < mRecords.size())) </li><li> { </li><li> return createIndex(row,column); </li><li> } </li><li> return QModelIndex(); //返回一个无效的空索引 </li><li>} </li><li>QModelIndex SqlMenuEntry::parent(const QModelIndex &child) const </li><li>{ </li><li> return QModelIndex(); //二维表中的行没有parent节点 </li><li>} </li><li>QVariant SqlMenuEntry::data(const QModelIndex &index, int role) const </li><li>{ </li><li> if(index.isValid) </li><li> { </li><li> return mRecords[index.row()][role]; </li><li> } </li><li>} </li></ol>
mRecords中的数据可以按需求生成,如通过QSqlQuery组件从数据库服务器获取,获取添加数据:
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li> QHash<int,QVariant> row;<br /> </li><li>row[nameRole] = "name1";<br /></li><li>row[iconRole] = "icon1";<br /></li><li>mRecords.append(row); </li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li>qmlRegisterType<SqlMenuEntry>("com.limutech.tv",1,0,"MenuEntryModel");</li></ol>
<ol style="margin:0 1px 0 0px;padding-left:40px;" start="1" class="dp-css"><li> import com.limutech.tv 1.0<br /> </li><li>MenuEntryModel{<br /></li><li>id:menuEntryModel<br /></li><li>}<br /></li><li>ListView{<br /></li><li>model:menuEntryModel<br /></li><li>...<br /></li><li>} </li></ol>
1、View调用rowCount(constQModelIndex &parent)并传递一个空的parent获取根节点的行数;
2、View调用columnCount(const QModelIndex &parent)并传递一个空的parent获取根节点的列数;
3、View对各行列枚举调用index(int row, int column, const QModelIndex &parent)交传行号、列号和空的parent获取根节点QModelIndex;
4、继续以返回的modelIndex为parent获取每行的rowCount和columnCount,如果大于0则该节点还有子节点;
5、调用roleNames返回可用的role列表
6、以返回的modelIndex和role为参数,调用data获取数据并使用相应的delegate进行显示
所以要显示一个树状列表,需要对二维表模型进行完善,处理parent不为空的情况,同时,模型应该可以存储树状数据,在下一节我将继续分享层次模型的实现方式和涉及数据修改的一些实现。

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

OnLeaks 现在与 Android Headlines 合作,首次展示了 Galaxy S25 Ultra,几天前,他试图从他的 X(以前的 Twitter)粉丝那里筹集到 4,000 美元以上的资金,但失败了。对于上下文,嵌入在 h 下面的渲染图像

除了发布两款新智能手机外,TCL 还发布了一款名为 NXTPAPER 14 的新 Android 平板电脑,其大屏幕尺寸是其卖点之一。 NXTPAPER 14 采用 TCL 标志性品牌哑光液晶面板 3.0 版本

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

Vivo Y300 Pro刚刚全面亮相,它是最薄的中端Android手机之一,配备大电池。准确来说,这款智能手机的厚度仅为 7.69 毫米,但配备了 6,500 mAh 的电池。这与最近推出的容量相同

三星尚未就何时更新其 Fan Edition (FE) 智能手机系列提供任何提示。目前来看,Galaxy S23 FE 仍然是该公司的最新版本,于 2023 年 10 月年初推出。

Redmi Note 14 Pro Plus 现已正式成为去年 Redmi Note 13 Pro Plus 的直接后继产品(亚马逊售价 375 美元)。正如预期的那样,Redmi Note 14 Pro Plus与Redmi Note 14和Redmi Note 14 Pro一起成为Redmi Note 14系列的主角。李

摩托罗拉今年发布了无数设备,尽管其中只有两款是可折叠的。就上下文而言,虽然世界上大多数地区都收到了 Razr 50 和 Razr 50 Ultra,但摩托罗拉在北美提供了 Razr 2024 和 Razr 2
