QML用Instantiator动态创建顶级窗口
关键点
- 使用Model驱动Instantiator
- QML里面的hashmap: QQmlPropertyMap
上一次说到用 QQmlApplicationEngine 多次load的方式创建多个一级窗口 详见这里{:target="_blank"},
但是窗口数据需要自己设置, 不如Model设置方式方便, 窗口如果比较复杂, 数据设置起来比较麻烦,而且管理窗口也会比较麻烦.
这里就说说用 Instantiator 这个QML里面的组件, 这个组件是根据模版用来动态创建多个QML组件的
(A Instantiator can be used to control the dynamic creation of objects, or to dynamically create multiple objects from a template.).
只是没想到的是竟然可以来创建多个一级窗口.
先看一下简单的:
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Window 2.3
Instantiator {
id: windowInstantiator
model: ListModel {
id: windowModel
ListElement { title: "Initial Window"; x: -200 }
ListElement { title: "Second Window"; x:300 }
}
delegate: Window {
id: window
visible: true
width: 640
height: 480
x: Screen.width/2 - window.width/2 + model.x
y: Screen.height / 2 - window.height/2
title: model.title
Rectangle {
width: 150
height: 50
Button {
text: qsTr("Duplicate Window")
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
onClicked: windowModel.append({ "title": "Window #" + (windowModel.count +1)})
}
}
}
}
- 里面直接用了ListModel来简化代码,
- delegate里面用model来读取数据, 然后还用了model的count属性来看一共有多少个窗口.
- 其中用了Screen类来判断窗口的位置.
- 一开始仅有2个窗口, 点击按钮则可以动态增加窗口(也就是修改Model数据)
那接下来我们看看如何直接通过Model来控制创建多个窗口, 为了与真实情况接轨, 里面放一个ListView, 视图QML如下:
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Window 2.3
import QtQuick.Layouts 1.3
Instantiator {
id: windowInstantiator
model: rootModel
delegate: Window {
id: window
visible: true
width: 640
height: 480
x: Screen.width/2 - window.width/2 + modelData.x
y: Screen.height / 2 - window.height/2
title: modelData.title + " (Window Count: " + count + " )"
ListView{
width: 100; height: 100
id: listView
objectName: "listView"
Layout.fillWidth: true
Layout.fillHeight: true
model: modelData.listModel
delegate: Rectangle {
height: 25
width: 100
Text { text: "hello " + model.name }
}
}
}
}
其中Instantiator的model是 rootModel, 而ListView的Model用的是 listModel数据.
接下来我们看看如何设置数据, 有两种方法:
- 实现一个 QAbstractListModel, 这个直接用QT新建一个QT Model就可以.
- 直接用QList来包装一个列表, 可以自己创建一个类, 或者直接用HashMap?
实现一个简单的类
class WindowModel : public QObject
{
Q_OBJECT
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(int x READ getX WRITE setX NOTIFY xChanged)
Q_PROPERTY(MyListModel* listModel READ getListModel WRITE setListModel NOTIFY listModelChanged)
public:
explicit WindowModel(QObject *parent = nullptr);
QString title() const;
void setTitle(const QString &title);
MyListModel *getListModel() const;
void setListModel(MyListModel *value);
int getX() const;
void setX(int x);
Q_SIGNALS:
void titleChanged();
void xChanged();
void listModelChanged();
private:
QString _title = "";
int m_x = 0;
MyListModel* m_listModel;
};
然后直接放到QList里面:
//用自己定义Model
WindowModel *win1 = new WindowModel();
win1->setTitle( "First");
win1->setX(-100);
win1->setListModel(model1);
WindowModel *win2 = new WindowModel();
win2->setTitle( "Second");
win2->setX(300);
win2->setListModel(model2);
//QVariantList list;
QList<WindowModel *> winlist;
winlist << win1 << win2;
或者用HashMap形式
看了看QHash, 并不能直接在QML里面使用, 可以用QQmlPropertyMap, 则可以在QML里面用modelData.xxx的方式直接调用数据.
//用类似Map结构的QQmlPropertyMap
QQmlPropertyMap hash1;
hash1.insert("title", "First");
hash1.insert("x", QVariant::fromValue(-100));
hash1.insert("listModel", QVariant::fromValue(model1));
QQmlPropertyMap hash2;
hash2.insert("title", "Second");
hash2.insert("x", QVariant::fromValue(300));
hash2.insert("listModel", QVariant::fromValue(model2));
//QVariantList list;
QList<QQmlPropertyMap*> list;
list << &hash1 << &hash2;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("rootModel", QVariant::fromValue(list));
注意modelData与model的区别
- 用QList做Model, 在QML里面调用modelData.xxx
- 用QAbstractListModel的子类做Model, 在QML里面调用model.xxx
官方说明详见 https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html{:target="_blank"}
更详细的请查看项目源码
https://github.com/cnscud/learn/tree/master/qt/windowByInstantiator{:target="_blank"}
QML用Instantiator动态创建顶级窗口的更多相关文章
- Tkinter 之TopLevel顶级窗口
一.参数说明 width 设置宽度 height 设置高度 background(bg) 设置背景颜色默认值由系统指定为了防止更新,可以将颜色值设置为空字符串 borderwidth(bd) 设置 ...
- QML用同一模版多开主窗口
如何动态地创建多个长的一样的主窗口哪(数据当然不一样), 用QML也是可以实现的. 简单的地说, 就是调用多次load即可. QCoreApplication::setAttribute(Qt::AA ...
- tp根据数据库动态创建微信菜单
喻可伟的博客 tp根据数据库动态创建微信菜单 $button = array();$class = M('ucenter_menu')->limit(3)->select();//取出 ...
- Winfrom动态创建控件
FlowLayoutPanel flowLayoutPanel1 = new FlowLayoutPanel();for (int i = 0; i < 9; i++){ Button b ...
- JavaScript DOM动态创建(声明)Object元素
http://www.cnblogs.com/GuominQiu/archive/2011/04/01/2002783.html 一文提及“等整个页面加载完毕后,根据用户所选的阅读机类型,再用Java ...
- Delphi动态创建组件,并释放内存
开发所用delphi版本是xe2,效果图如下: 代码如下: ---------------------------------------------------------------------- ...
- Qt Quick 组件和动态创建的对象具体的解释
在<Qt Quick 事件处理之信号与槽>一文中介绍自己定义信号时,举了一个简单的样例.定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Co ...
- Extjs2.0 desktop 动态创建桌面图标和开始菜单
这几天一直纠结Extjs desktop怎么动态读取数据,用Ext.net已经实现但是不灵活.Ext.net做出来的桌面在窗口关闭后只是隐藏该窗口,并没有释放,对于我这种js菜鸟来说,改那一坨代码要人 ...
- JavaScript异步加载的三种方式——async和defer、动态创建script
一.script标签的位置 传统的做法是:所有script元素都放在head元素中,必须等到全部js代码都被下载.解析.执行完毕后,才能开始呈现网页的内容(浏览器在遇到<body>标签时才 ...
随机推荐
- Linux安装界面简介
1.安装欢迎界面:install or upgrade an exsiting system:安装或升级现有系统 install system with basic video driver:安装过程 ...
- rabbitmqctl 命令整理
虽然还有http 接口.web admin组件可以进行管理,但是rabbitmqctl 基本包含了 rabbitmq 的全部管理功能,更为全面. 所以将其使用方法总结于此. 一,命令格式 rabbit ...
- Docker笔记--镜像&基于GO项目创建Docker镜像
Docker笔记--镜像&基于GO项目创建Docker镜像 核心概念 Doker镜像--包含一个基本的操作系统运行环境和应用程序,镜像是创建Docker容器的基础. Docker容器--如果把 ...
- css中的毛玻璃(不是透明度) 简单文档
其实毛玻璃很简单 只需要在css中加入 backdrop-filter:blur(8px); 8px是模糊力度 注意:使用该方法前需要设置背景不能是透明(如果是显示这个元素下面的图像记得半透明,例子就 ...
- 单片机项目中使用新IC芯片的调试方法
前两天,一位小伙伴咨询我一款新IC芯片怎么使用,借此机会我顺便把我日常工作中经常用到的一种调试方法介绍给小伙伴们,希望对对大家有所帮助.准备仓促,文中难免有技术性错误,欢迎大家给予指正,并给出好的建议 ...
- C# 小知识点记录
1.当计算数据有小数点时不要使用float和double类型的数据,使用这两个会计算不准确.使用decimal 2.如果使用decimal计算数据,遇到除不进的数据有很多小数点的时候,在计算结果后面接 ...
- http连接复用进化论
HTTP协议是应用层协议,它定义万维网客户端如何与服务器进行通信.它在传输层的TCP协议的基础上进行数据传输 HTTP 1.0 在HTTP 1.0时代,默认一个http请求对应一个TCP连接,没有任何 ...
- 从S3中拷贝或同步文件
p.p1 { margin: 0; font: 16px "Helvetica Neue"; color: rgba(53, 53, 53, 1) } p.p2 { margin: ...
- MySQL存储引擎——InnoDB和MyISAM的区别
MySQL5.5后,默认存储引擎是InnoDB,5.5之前默认是MyISAM. InnoDB(事务性数据库引擎)和MyISAM的区别补充: InnoDB是聚集索引,数据结构是B+树,叶子节点存K-V, ...
- python使用笔记002
一.字符串常用方法 1 s = ' ha.hahaha.' 2 print(s.count('a'))#找某一个元素在字符串里出现的次数 3 print(s.index('a'))#找某一个元素的下标 ...