How to make a QML Component a Singleton?

来源:互联网 发布:网络宣传方法 编辑:程序博客网 时间:2024/05/17 03:37

In this tutorial I’ll walk you through how to define a custom QML Component as a singleton.

UPDATE: I uploaded a new sample code which better outlines the difference between using an instance of MyStyleObject and using the singleton MySingletonStyleObject.You can download it here.

Currently I’m working on a rather large Qt Quick application which will be deployed on an embedded device. I’m starting to notice performance issues as we add more and more screens to the application. I decided to run the QML Profiler that is part of Qt Creator and one of the things I noticed was that one of our QML Components is being created 1500+ times. This component is an Item which holds a number of properties defining different styling options like what the colour Blue is for our purposes; its our style sheet. The issue being that its loading non-standard fonts which is expensive so as it turns out we’re loading the fonts 1500+ times.

Each screen/page in the application is instantiating its own copy of the style object as we weren’t really keen on defining one globally and simply referring to it. I mean really there is nothing wrong with that approach per-say but it does relay on a dependency; that someone instantiated the object somewhere in the application and that the objects id never changes.

So how can I reduce the number of instantiated objects without depending on a locked in stone id name?

Enter the Singleton

So as it turns out Qt Quick does have a mechanism to let you define a QML component as a singleton. I didn’t even think to see if that was even an option, a college mentioned it to me in passing and they only knew about it as a one line statement on a blog post.

Ok so its a thing but how do you do it?

There are three steps you need to do; first you need to use the pragma Singleton keyword in your QML script, then you need to register the component as a singleton, and lastly you need to import it into your other QML scripts which are going to use it.

Step 1: Declaring the QML Component as a Singleton

Lets say this is your style sheet QML object that you want to make a singleton.

view plaincopy to clipboardprint?
  1. //MyStyleObject.qml  
  2. import QtQuick 2.0  
  3.   
  4. Item {  
  5.     readonly property string colourBlue: "blue"  
  6.     readonly property string colourRed: "red"  
  7.     readonly property int fontPointSize: 16  
  8. }  

To declare it as a singleton you need to add the keywords pragma Singleton to the top of the script file.

view plaincopy to clipboardprint?
  1. //MyStyleObject.qml  
  2. pragma Singleton  
  3. import QtQuick 2.0  
  4.   
  5. Item {  
  6.     readonly property string colourBlue: "blue"  
  7.     readonly property string colourRed: "red"  
  8.     readonly property int fontPointSize: 16  
  9. }  

Step 2: Registering the Component

Now you have two options you can either register the Component in C++ or by using a qmldir file.

To register the singleton via C++ somewhere in your C++ code you need to call qmlRegisterSingletonType().

view plaincopy to clipboardprint?
  1. #include <QtQml>  
  2. ...  
  3. qmlRegisterSingletonType( QUrl("file:///absolute/path/MyStyleObject.qml"), "ca.imaginativethinking.tutorial.style", 1, 0, "MyStyle" );  
  4. ...  

If adding the call to qmlRegisterSingletonType() won’t work for you, maybe this is a Qt Quick UI project (i.e. no C++ ) then you can add a file called qmldir to the directory where your MyStyleObject.qml file exists. When importing a directory the QML Engine first looks for the qmldir file and uses it to import the scripts found in that directory; if the file does not exist it will import the scripts found with default values (i.e. non-singletons and uses the file name as the component name). The qmldir file can define different names to be used instead of the file name and can also tell the import to register the script as a singleton.

Here is what the directory structure should look like:

/root  + absolute  |  + path  |  |  + qmldir  |  |  + MyStyleObject.qml  |  |  + AnotherObject.qml  |  |  + MyButton.qml  |  |  + MySwitch.qml  |  + main.qml

Here is how to define the qmldir file:

view plaincopy to clipboardprint?
  1. singleton MyStyle 1.0 MyStyleObject.qml  
  2. MyOtherObject 1.0 AnotherObject.qml  
  3. MyButton 1.0 MyButton.qml  

Notice that if a script is found in the directory but is not declared in the qmldir file it still gets import but uses the default settings. MySwich.qml will be imported and registered using the name MySwitch as a non-singleton. You can see here that we can also use qmldir to define a different name other then the file name for the component, MyButton was registered to use the file name per the default but AnotherObject.qml was registered to use the name MyOtherObject.

Step 3: Importing and Using the Singleton

If you use the C++ option above then in order to import and use the singleton in your QML script you need to import the module you defined via the second parameter of qmlRegisterSingletonType() then access the object using the registered name (parameter three of qmlRegisterSingletonType()).

view plaincopy to clipboardprint?
  1. //main.qml  
  2. import QtQuick 2.0  
  3. import ca.imaginativethinking.tutorial.style 1.0  
  4.   
  5. Rectangle {  
  6.     anchors.fill: parent  
  7.     color: MyStyle.colourBlue // <-- Notice that to access the singleton I use the object name not id (i.e. Capital M)  
  8. }  

If you used the qmldir approach then you simply need to import the directory which will register all the scripts under that directory.

view plaincopy to clipboardprint?
  1. //main.qml  
  2. import QtQuick 2.0  
  3. import "path"  
  4.   
  5. Rectangle {  
  6.     anchors.fill: parent  
  7.     color: MyStyle.colourBlue // <-- Notice that to access the singleton I use the object name not id (i.e. Capital M)  
  8. }  

Note here however that if main.qml was within the path directory you would still have to import the path as it does not appear that the qmldir file gets used when you relay on the auto look up path.

So what does this buy us?

Example time: lets say we create an app that shows 100 blue boxes with red boarders on the screen. We'll use the MyStyleObject component to hold what shade of blue Blue is and the thickness of the boarder.

QMLSingletonSample_1

How we'll achieve this is by using a GridView with a integer model of 100 and the MyStyleObject will be created within the delegate.

view plaincopy to clipboardprint?
  1. GridView {  
  2.     anchors.fill: parent  
  3.     model: 100  
  4.     delegate: gridDelegate  
  5.     cellHeight: 50  
  6.     cellWidth: cellHeight  
  7. }  
  8. Component {  
  9.     id: gridDelegate  
  10.   
  11.     Rectangle {  
  12.         width: 50  
  13.         height: width  
  14.         color: myStyle.colourBlue  
  15.         border.color: myStyle.colourRed  
  16.         border.width: myStyle.borderSize  
  17.   
  18.         Text {  
  19.             anchors.centerIn: parent  
  20.             text: index  
  21.             font.pointSize: myStyle.fontPointSize  
  22.             color: myStyle.colourWhite  
  23.         }  
  24.         MyStyleObject {  
  25.             id: myStyle  
  26.         }  
  27.     }  
  28. }  

We can run the QML Profiler in Qt Creator (Analyze -> QML Profiler) it will switch Qt Creator over to the Analyze view and launch our application.

QMLProfiler_1

Once our application has launched we can press the stop button on the Analyze view to terminate the application and stop the profiler. It will then load the data into the view.

QMLProfiler_2

By instantiating an instance of the MyStyleObject within the delegate you can see it gets created 100 times which takes 12.084ms; binded to 99 times which takes 1.130ms and that the compile phase for the object (which only happens once) takes 708.820µs.

If we change this into a singleton and run the same profiler we'll find that now the object is only created once (474.917µs); although the compile phase does take longer (1.917ms) your still saving about 10ms. This might not seem like a lot over all but when your trying to keep the presentation of your application at 60FPS every little bit helps.

view plaincopy to clipboardprint?
  1. GridView {  
  2.     anchors.fill: parent  
  3.     model: 100  
  4.     delegate: gridDelegate  
  5.     cellHeight: 50  
  6.     cellWidth: cellHeight  
  7. }  
  8. Component {  
  9.     id: gridDelegate  
  10.   
  11.     Rectangle {  
  12.         width: 50  
  13.         height: width  
  14.         color: MyStyle.colourBlue // <-- Capital M MyStyle means I'm now access the one and only instance of the MySingletonStyle object  
  15.         border.color: MyStyle.colourRed  
  16.         border.width: MyStyle.borderSize  
  17.   
  18.         Text {  
  19.             anchors.centerIn: parent  
  20.             text: index  
  21.             font.pointSize: MyStyle.fontPointSize  
  22.             color: MyStyle.colourWhite  
  23.         }  
  24.     }  
  25. }  

So there you go that is all you have to do to define a QML Component as a singleton so that it only gets created once.

You can download a sample application which illustrate the above here:

QML Singleton Sample 1.1 - Updated to be more clear.


转载:http://imaginativethinking.ca/make-qml-component-singleton/

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 指环扣松了怎么办图解 塑料放久了发粘怎么办 橡胶时间久了粘怎么办 胶的手机套变黄怎么办 手机壳硅胶变黄怎么办 硅胶手机壳大了怎么办 硅胶手机壳变大了怎么办 硅胶手机壳有点大怎么办 硅胶手机壳粘手怎么办 透明手机壳变黄怎么办? 耳机胶套经常掉怎么办 硅胶手机壳粘毛怎么办 耳机海绵套坏了怎么办 沙发垫海绵坏了怎么办 汽车坐海绵坏了怎么办 苹果手机边框有缝隙怎么办 孕期牙套子掉了怎么办 平果充电线不匹配怎么办 苹果六外壳掉漆怎么办 苹果平板充电没反应怎么办 苹果平板黑屏没反应怎么办 苹果平板卡机了怎么办 苹果7plus掉漆怎么办 皮的手机壳脏了怎么办 小米5x边边裂开怎么办 荣耀8的后盖摔了怎么办 hp打印机卡了纸怎么办 华为荣耀9进水了怎么办 小米5x屏幕脱胶怎么办 小米5x后盖松动怎么办 苹果手机没电了怎么办 荣耀9的后盖裂了怎么办 手机一直在开机画面怎么办华为 华为手机一直显示开机画面怎么办 华为p7手机开不了机怎么办 华为荣耀8弯了怎么办 手机壳掉漆了怎么办 华为5a手机音量小怎么办 华为5a手机声音小怎么办 苹果屏幕磨花了怎么办 白色磨砂手机壳脏了怎么办