关键点

  • 使用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.).

只是没想到的是竟然可以来创建多个一级窗口.

先看一下简单的:

  1. import QtQuick 2.12
  2. import QtQuick.Controls 2.5
  3. import QtQuick.Window 2.3
  4. Instantiator {
  5. id: windowInstantiator
  6. model: ListModel {
  7. id: windowModel
  8. ListElement { title: "Initial Window"; x: -200 }
  9. ListElement { title: "Second Window"; x:300 }
  10. }
  11. delegate: Window {
  12. id: window
  13. visible: true
  14. width: 640
  15. height: 480
  16. x: Screen.width/2 - window.width/2 + model.x
  17. y: Screen.height / 2 - window.height/2
  18. title: model.title
  19. Rectangle {
  20. width: 150
  21. height: 50
  22. Button {
  23. text: qsTr("Duplicate Window")
  24. anchors.horizontalCenter: parent.horizontalCenter
  25. anchors.bottom: parent.bottom
  26. onClicked: windowModel.append({ "title": "Window #" + (windowModel.count +1)})
  27. }
  28. }
  29. }
  30. }
  • 里面直接用了ListModel来简化代码,
  • delegate里面用model来读取数据, 然后还用了model的count属性来看一共有多少个窗口.
  • 其中用了Screen类来判断窗口的位置.
  • 一开始仅有2个窗口, 点击按钮则可以动态增加窗口(也就是修改Model数据)

那接下来我们看看如何直接通过Model来控制创建多个窗口, 为了与真实情况接轨, 里面放一个ListView, 视图QML如下:

  1. import QtQuick 2.12
  2. import QtQuick.Controls 2.5
  3. import QtQuick.Window 2.3
  4. import QtQuick.Layouts 1.3
  5. Instantiator {
  6. id: windowInstantiator
  7. model: rootModel
  8. delegate: Window {
  9. id: window
  10. visible: true
  11. width: 640
  12. height: 480
  13. x: Screen.width/2 - window.width/2 + modelData.x
  14. y: Screen.height / 2 - window.height/2
  15. title: modelData.title + " (Window Count: " + count + " )"
  16. ListView{
  17. width: 100; height: 100
  18. id: listView
  19. objectName: "listView"
  20. Layout.fillWidth: true
  21. Layout.fillHeight: true
  22. model: modelData.listModel
  23. delegate: Rectangle {
  24. height: 25
  25. width: 100
  26. Text { text: "hello " + model.name }
  27. }
  28. }
  29. }
  30. }

其中Instantiator的model是 rootModel, 而ListView的Model用的是 listModel数据.

接下来我们看看如何设置数据, 有两种方法:

  • 实现一个 QAbstractListModel, 这个直接用QT新建一个QT Model就可以.
  • 直接用QList来包装一个列表, 可以自己创建一个类, 或者直接用HashMap?

实现一个简单的类


  1. class WindowModel : public QObject
  2. {
  3. Q_OBJECT
  4. Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
  5. Q_PROPERTY(int x READ getX WRITE setX NOTIFY xChanged)
  6. Q_PROPERTY(MyListModel* listModel READ getListModel WRITE setListModel NOTIFY listModelChanged)
  7. public:
  8. explicit WindowModel(QObject *parent = nullptr);
  9. QString title() const;
  10. void setTitle(const QString &title);
  11. MyListModel *getListModel() const;
  12. void setListModel(MyListModel *value);
  13. int getX() const;
  14. void setX(int x);
  15. Q_SIGNALS:
  16. void titleChanged();
  17. void xChanged();
  18. void listModelChanged();
  19. private:
  20. QString _title = "";
  21. int m_x = 0;
  22. MyListModel* m_listModel;
  23. };

然后直接放到QList里面:

  1. //用自己定义Model
  2. WindowModel *win1 = new WindowModel();
  3. win1->setTitle( "First");
  4. win1->setX(-100);
  5. win1->setListModel(model1);
  6. WindowModel *win2 = new WindowModel();
  7. win2->setTitle( "Second");
  8. win2->setX(300);
  9. win2->setListModel(model2);
  10. //QVariantList list;
  11. QList<WindowModel *> winlist;
  12. winlist << win1 << win2;

或者用HashMap形式

看了看QHash, 并不能直接在QML里面使用, 可以用QQmlPropertyMap, 则可以在QML里面用modelData.xxx的方式直接调用数据.

  1. //用类似Map结构的QQmlPropertyMap
  2. QQmlPropertyMap hash1;
  3. hash1.insert("title", "First");
  4. hash1.insert("x", QVariant::fromValue(-100));
  5. hash1.insert("listModel", QVariant::fromValue(model1));
  6. QQmlPropertyMap hash2;
  7. hash2.insert("title", "Second");
  8. hash2.insert("x", QVariant::fromValue(300));
  9. hash2.insert("listModel", QVariant::fromValue(model2));
  10. //QVariantList list;
  11. QList<QQmlPropertyMap*> list;
  12. list << &hash1 << &hash2;
  13. QQmlApplicationEngine engine;
  14. 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动态创建顶级窗口的更多相关文章

  1. Tkinter 之TopLevel顶级窗口

    一.参数说明 width  设置宽度 height  设置高度 background(bg) 设置背景颜色默认值由系统指定为了防止更新,可以将颜色值设置为空字符串 borderwidth(bd) 设置 ...

  2. QML用同一模版多开主窗口

    如何动态地创建多个长的一样的主窗口哪(数据当然不一样), 用QML也是可以实现的. 简单的地说, 就是调用多次load即可. QCoreApplication::setAttribute(Qt::AA ...

  3. tp根据数据库动态创建微信菜单

    喻可伟的博客   tp根据数据库动态创建微信菜单 $button = array();$class = M('ucenter_menu')->limit(3)->select();//取出 ...

  4. Winfrom动态创建控件

    FlowLayoutPanel flowLayoutPanel1 = new FlowLayoutPanel();for (int i = 0; i < 9; i++){    Button b ...

  5. JavaScript DOM动态创建(声明)Object元素

    http://www.cnblogs.com/GuominQiu/archive/2011/04/01/2002783.html 一文提及“等整个页面加载完毕后,根据用户所选的阅读机类型,再用Java ...

  6. Delphi动态创建组件,并释放内存

    开发所用delphi版本是xe2,效果图如下: 代码如下: ---------------------------------------------------------------------- ...

  7. Qt Quick 组件和动态创建的对象具体的解释

    在<Qt Quick 事件处理之信号与槽>一文中介绍自己定义信号时,举了一个简单的样例.定义了一个颜色选择组件,当用户在组建内点击鼠标时,该组件会发出一个携带颜色值的信号,当时我使用 Co ...

  8. Extjs2.0 desktop 动态创建桌面图标和开始菜单

    这几天一直纠结Extjs desktop怎么动态读取数据,用Ext.net已经实现但是不灵活.Ext.net做出来的桌面在窗口关闭后只是隐藏该窗口,并没有释放,对于我这种js菜鸟来说,改那一坨代码要人 ...

  9. JavaScript异步加载的三种方式——async和defer、动态创建script

    一.script标签的位置 传统的做法是:所有script元素都放在head元素中,必须等到全部js代码都被下载.解析.执行完毕后,才能开始呈现网页的内容(浏览器在遇到<body>标签时才 ...

随机推荐

  1. mturoute 最大传输单元路由检测Host

    mturoute检测mtu字符 下载地址:https://www.elifulkerson.com/projects/mturoute.php mturoute.exe                ...

  2. sleep、wait方法之间区别

    sleep.wait方法之间区别 1.所属的类不同 sleep是Thread类的静态方法,而wait是Object类的成员方法 2.锁机制不一样 sleep方法:会让出资源调度器为当前线程分配的时间片 ...

  3. 如何优雅的实现Mysql 增删改查,看完你就会了

    接着上期说,上期没写一条sql就把数据查询出来了,那如果要保存或者更新数据怎么办呢?能不能自己写sql呢? 保存数据 @GetMapping("save")//保存数据 publi ...

  4. java 写webservice接口解析xml报文

    1 <!--解析xml报文--> 2 <dependency> 3 <groupId>dom4j</groupId> 4 <artifactId& ...

  5. OSPF多区域原理与配置

    OSPF多区域原理与配置 目录 一.OSPF多区域生成 1.1.生成OSPF多区域的原因 二.OSPF的三种通信量 2.1.域内通信量 2.2.域间通信量 2.3.外部通信量 三.OSPF的路由器类型 ...

  6. Unity获取系统时间

    示例如下: Debug.Log(System.DateTime.Now); // 当前本地时间 (年月日时分秒) -- 10/4/2018 9:38:19 PM Debug.Log(System.Da ...

  7. Linux-ELK日志收集

    1.ELK简介 ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是开源软件.新增了一个FileBeat,它是一个轻量级的日志收集处理工 ...

  8. 5、基本数据类型(str)

    5.1.字符串: 1.n1 = "lc" n2 = 'root' n3 = """chang""" n4='''tom' ...

  9. 解决git同步每次都需要输入用户名、密码

    打开 git bash 执行命令: git config --global credential.helper store

  10. SpringBoot Cache 入门

    首先搭载开发环境,不会的可以参考笔者之前的文章SpringBoot入门 添加依赖 <dependency> <groupId>org.springframework.boot& ...