关键点

  • 使用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动态创建顶级窗口的更多相关文章

  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. VisualCom软件仿真平台V1.0发布(附安装包下载链接)

    自我们借助VisualCom(暂定名称,后续可能会变更)软件平台撰写技术文章以来,有不少粉丝发私信询问该软件哪里来的,以及哪里有安装包,这里回复一下:VisualCom软件平台是由本微信公众号组织开发 ...

  2. Vue(9)购物车练习

    购物车案例 经过一系列的学习,我们这里来练习一个购物车的案例   需求:使用vue写一个表单页面,页面上有购买的数量,点击按钮+或者-,可以增加或减少购物车的数量,数量最少不得少于0,点击移除按钮,会 ...

  3. 一次鞭辟入里的 Log4j2 异步日志输出阻塞问题的定位

    一次鞭辟入里的 Log4j2 日志输出阻塞问题的定位 问题现象 线上某个应用的某个实例突然出现某些次请求服务响应极慢的情况,有几次请求超过 60s 才返回,并且通过日志发现,服务线程并没有做什么很重的 ...

  4. VSCode 使用 Code Runner 插件无法编译运行文件名带空格的文件

    本文同时在我的博客发布:VSCode 使用 Code Runner 插件无法编译运行文件名带空格的文件 - Skykguj 's Blog (sky390.cn) 使用 Visual Studio C ...

  5. yoyogo v1.7.4 发布,支持 grpc v1.3.8 & etcd 3.5.0

    YoyoGo (Go语言框架)一个简单.轻量.快速.基于依赖注入的微服务框架( web .grpc ),支持Nacos/Consoul/Etcd/Eureka/k8s /Apollo等 . https ...

  6. Python管道进行数据的吞吐处理

    import multiprocessing import random import time import datetime import struct import os import getF ...

  7. logback学习与配置使用

    Logback介绍 Logback 分为三个模块:Core.Classic 和 Access.Core模块是其他两个模块的基础. Classic模块扩展了core模块. Classic模块相当于log ...

  8. <clinit>() 和 <init>()

    原文:https://www.cnblogs.com/aspirant/p/7200523.html <clinit>() 类构造器方法 在 类初始化阶段 被执行 由编译器自动收集类中的所 ...

  9. 使用过redis做异步队列么,你是怎么用的?有什么缺点?

    Redis设计主要是用来做缓存的,但是由于它自身的某种特性使得它可以用来做消息队列. 它有几个阻塞式的API可以使用,正是这些阻塞式的API让其有能力做消息队列: 另外,做消息队列的其他特性例如FIF ...

  10. 6 shell内置命令

    知识点1:什么是shell内建命令? Shell 内建命令,就是由 Bash 自身提供的命令,而不是文件系统中的某个可执行文件. 内建命令与普通命令的性质是不一样的,内建命令并不是某个外部文件,只要在 ...