目錄
(放個目錄方便大家預覽。破乎不支持目錄,這個目錄是從博客複製過來的,點擊跳轉到博客)
本文是《Qml組件化編程》系列文章的第十篇,濤哥將教大家,Qml自定義模塊的知識。
特別是最近的研究結果:如何讓Qml模塊在Designer中拖拽使用。濤哥希望有更多的人學會這個技能。
註:文章主要發布在濤哥的博客 和 濤哥的知乎專欄-Qt進階之路
(先播點新聞)
2019年5月20的時候,Qt官方放出了Qt Design Studio的1.2 beta版, 免費使用/暫不開源。
下載地址在這:
http://download.qt.io/development_releases/qtdesignstudio/1.2/1.2.0-beta1-community/
Qt Design Studio是主要給美工使用的一款UI工具。
Qt在Photo Shop/Sketch這兩款工具中,提供了QtBridge插件,可以將設計好的資源直接導出成Qml工程。
導出的工程可以用Qt Design Studio/QtCreator打開,用拖拖拽拽的方式,實現各種功能、動畫等等。
QtDesignStudio目前還不成熟,但未來是一片光明。等Designer做好了,就不再需要手寫Qml代碼,拖拖拽拽就能搞定界面部分。
只剩下邏輯處理和後端功能才需要寫代碼/寫js腳本。
Qt Design Studio目前與QtCreator的差異是,前者內置了一些特殊的模塊:包括 Shapes圖元、Effects等,
Qt Design Studio還使用了qmlproject文件作為工程管理。
除此之外,功能都是一樣的。幀動畫編輯器在QtCreator中也是可以使用的。
最新的TaoQuick (tag: 0.1.6), 已經支持在QtCreator中拖拽使用了
代碼倉庫在這:TaoQuick
(下面進入正題)
(有必要先說一下資源管理,這部分內容幫助文檔都有,搜索關鍵詞為」rcc」 或 「Qt Resource」)
Qt提供了一個資源管理工具rcc,可以將各種資源文件壓縮、打包進二進位程序。
通常用來打包各種圖片、Qml文件、配置文件或數據文件等等,只要將資源文件添加到qrc文件中即可。
qrc文件是xml格式的文本文件,裡面記錄著添加的各種資源。
示例 TaoResource.qrc:
<!DOCTYPE RCC><RCC version="1.0"> <qresource> <file>images/copy.png</file> <file>images/cut.png</file> <file>images/new.png</file> <file>images/open.png</file> <file>images/paste.png</file> <file>images/save.png</file> </qresource> </RCC>
只要在pro文件中寫上 RESOURCES = TaoResource.qrc就可以了。qmake會自動將資源壓縮、打包進exe/dll程序
也可以使用命令行手動編譯:
rcc -binary TaoResource.qrc -o TaoResource.rcc
或者
rcc -binary TaoResource.qrc -o TaoResource.dll
這種方式編譯出來的,是一個純粹的資源插件,擴展名寫什麼都無所謂的。
可以在代碼中動態載入資源、卸載資源
QResource::registerResource("/path/to/TaoResource.rcc"); QResource::unRegisterResource("/path/to/TaoResource.rcc");
使用」:/「 或者 「qrc:/「開頭的路徑即可,這兩者的區別濤哥未作總結,大家自己實踐吧。
cutAct = new QAction(QIcon(":/images/cut.png")
在Qt插件中,添加了資源的情況下,需要用宏Q_INIT_RESOURCE來註冊資源
(Qt插件和前面的rcc編譯出來的不一樣,不是一個純粹的資源插件,不能直接被QResource::registerResource識別)
TaoClass::TaoClass() : BaseClass() { Q_INIT_RESOURCE(TaoResource);
QFile file(":/images/save.png"); ... }
(這部分內容幫助文檔也有,搜索關鍵詞」QML Modules」)
設計Qml模塊的大致步驟如下:
如果要支持designer,還要加上一步:
這一步暫時沒有任何文檔和工具,濤哥照貓畫虎做出來的。以後文檔肯定會出來的,現在有些功能不完善。
(參考Qt的支持Designer的Qml模塊。更深入的瞭解,在QtCreator源碼)
(幫助文檔搜索關鍵詞 「qmldir」 或 「Module Definition qmldir…」)
這裡以TaoQuick中的為例,我順手加了點注釋:
TaoQuick/TaoQuick/qmldir:
#模塊名稱 import使用的地方,就用這個名稱 module TaoQuick
#插件dll文件名稱,即 TaoQuick.dll plugin TaoQuick
#依賴的模塊
depends QtQuick 2.12 depends QtQuick.Controls 2.12
# 這裡一堆的組件 TGradientBtn 1.0 BasicComponent/Button/TGradientBtn.qml TImageBtn 1.0 BasicComponent/Button/TImageBtn.qml TImgTextBtn 1.0 BasicComponent/Button/TImgTextBtn.qml TTextBtn 1.0 BasicComponent/Button/TTextBtn.qml
TMoveArea 1.0 BasicComponent/Mouse/TMoveArea.qml TTransArea 1.0 BasicComponent/Mouse/TTransArea.qml
TNormalProgress 1.0 BasicComponent/Progress/TNormalProgress.qml TCircleProgress 1.0 BasicComponent/Progress/TCircleProgress.qml
TBusyIndicator 1.0 BasicComponent/Others/TBusyIndicator.qml TDragItem 1.0 BasicComponent/Others/TDragItem.qml TResizeBorder 1.0 BasicComponent/Others/TResizeBorder.qml TToolTip 1.0 BasicComponent/Others/TToolTip.qml TDialog 1.0 BasicComponent/Others/TDialog.qml TPopup 1.0 BasicComponent/Others/TPopup.qml TFPS 1.0 BasicComponent/Others/TFPS.qml
# 支持designer designersupported
還有單例singleton、內部類型internal、C++類型描述typeinfo, 這些用法TaoQuick沒有用到,就不多說了。
plugin TaoQuick這一句,表示對應的dll文件名稱。dll是要寫一個C++類,繼承自QQmlExtensionPlugin
看一下TaoQuick中的實現
//taoquick_plugin.h #pragma once
#include <QQmlExtensionPlugin>
class TaoQuickPlugin : public QQmlExtensionPlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public: void registerTypes(const char *uri) override; };
//taoquick_plugin.cpp #include "taoquick_plugin.h" void TaoQuickPlugin::registerTypes(const char *uri) { Q_UNUSED(uri); Q_INIT_RESOURCE(Qml); //註冊Qml.qrc }
運行時候的bin路徑文件結構是這樣的:
TaoQuick文件夾的名字就是模塊名字
這裡說一下,TaoQuick項目中還有一個qmldir文件:
TaoQuick/TaoQuick/Qml/qmldir:
TGradientBtn 1.0 BasicComponent/Button/TGradientBtn.qml TImageBtn 1.0 BasicComponent/Button/TImageBtn.qml TImgTextBtn 1.0 BasicComponent/Button/TImgTextBtn.qml TTextBtn 1.0 BasicComponent/Button/TTextBtn.qml
這裡面module、plugin這些東西都沒有,只有組件。而且這個文件是加入了qrc的,即編譯進dll裡面了。
前面那個qmldir,需要和dll放在同級目錄,dll模塊才能被Qml引擎導入。
後面這個qmldir的作用是,導出dll插件時,不用帶上qml源碼,直接import 這個qmldir的資源路徑,就能夠用裡面的組件了。
也就是說,使用的地方,要寫兩句import
import TaoQuick 1.0 import "qrc:/Tao/Qml/"
這種用法不能在QtCreator高亮,運行沒問題。(商業版似乎有更高級的資源內建功能,或許可以支持高亮,後續再研究)
具體的實現和用法,可以參考TaoQuick 或者文末的最簡Demo。
TaoQuick中的qmake語法,可以參考另一篇文章 <Qt實用技能2-用好qmake>
再看一下效果:
要支持Designer,需要以下步驟:
首先要在Qml路徑下,創建一個designer文件夾。必須叫這個名字
其次要放一個擴展名為.metainfo的文件,裡面按格式寫上組件信息。名字似乎沒有要求。
最後,將整個Qml文件夾拷貝到[QTDIR]/qml/路徑下,並把文件夾名字改成模塊名字。
TaoQuick項目的路徑是這樣的:
metainfo文件,目前沒有文檔、沒有自動生成工具,只能手動寫,語法和qml語法類似。(可以參考QtCreator源碼,裡面有完整的解析器)
MetaInfo { Type { name: "TaoQuick.BasicComponent.Button.TGradientBtn" icon: "images/TGradientBtn.png"
ItemLibraryEntry { name: "TGradientBtn" category: "TaoQuick - Buttons" libraryIcon: "images/TGradientBtn.png" version: "1.0" requiredImport: "TaoQuick" Property { name: "width"; type: "int"; value: 120 } Property { name: "height"; type: "int"; value: 80 } } } }
頂層MetaInfo為固定寫法
接下來一個Type就對應Designer中的一個可拖拽的組件:
* name應該算作Qml組件文件的路徑,路徑分隔符用"點", 路徑默認從[QTDIR]/qml開始,如果有自定義qml 導入路徑,應該可以從相應的路徑開始查找(未嘗試)。
* icon 就是小圖標了,用來在Designer界面上預覽。這裡的images路徑,默認從designer文件夾開始
ItemLibraryEntry 是對這個組件更詳細的描述:
* name 顯示在Designer上面的名字 * category 分組的名字 * libraryIcon 小圖標,和前面那個一樣(不懂有什麼區別,先照抄) * version 版本 (TaoQuick都是1.0) * requiredImport 必要的導入的模塊 * Property 屬性。就是可以在Designer中調整、做幀動畫的。
Property支持的關鍵字有 name type value三個。 type 的值,暫時沒有完整的支持列表,源碼裡面能翻到Qml的基礎類型[「boolean」, 「int」, 「real」, 「string」, 「url」, 「color」], Qt發行的Qml中,還能看到」binding」。
(qtcreator-4.9.0qt-creator-opensource-src-4.9.0srcpluginsqmldesignerdesignercoremetainfometainfo.cpp)
屬性這裡,應該是QtCreator還沒有開發完整。Qml組件,metainfo裏什麼屬性都不寫,Designer裡面一個屬性都看不到。就寫一個width屬性,其它的屬性也自動給列出來了。
但是Color這種,即使寫了color,還是按照binding字元串處理的,不能用顏色選擇器改顏色。只能等QtCreator後續版本了。
Qt自帶的Rectangle一類,是從C++裡面寫的,Color屬性是可以用顏色選擇器的。Qt自帶的Qml組件Color屬性也是按binding處理的。
前面示例那個FPS組件,用到了一張圖片。圖片資源要麼和Qml文件放一起,用」file:///./「的方式訪問,要麼放進資源裏,用C++註冊。
所以在前面的TaoQuick安裝路徑中,有一個dll文件。C:Qt5.12.3msvc2017_64qmlTaoQuickTaoQuick.dll
然後封裝這個組件的時候,還要再import一下TaoQuick.dll, 即import TaoQuick 1.0
圖片路徑就用資源路徑
//TFPS.qml import QtQuick 2.12 import QtQuick.Controls 2.12 import TaoQuick 1.0 Item { property int fps: 60
property int frameCount: 0 property color textColor: "#f7e08c" Image { id: spinner source: "qrc:/Core/Image/Others/spinner.png" width: 32 height: 32 anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left RotationAnimation on rotation { from: 0 to: 360 running: true loops: Animation.Infinite duration: 1000 } onRotationChanged: frameCount++ } Text { anchors.left: spinner.right anchors.verticalCenter: parent.verticalCenter text: "FPS" + fps font.pixelSize: 20 renderType: Text.NativeRendering color: textColor } Timer { interval: 1000 repeat: true running: true onTriggered: { fps = frameCount frameCount = 0 } } }
可以手動拷貝文件夾,也可以參考TaoQuick的自動化安裝。
<Qt實用技能2-用好qmake>一文中已經說過了
只要增加一個pri文件,再執行make install即可
//TaoQuickDesigner.pri taoquick_designer.files = $$PWD/designer/TaoQuick.metainfo taoquick_designer.path = $$[QT_INSTALL_QML]/$${uri}/designer
toaquick_qmldir.files = $$PWD/qmldir toaquick_qmldir.path = $$[QT_INSTALL_QML]/$${uri}
taoquick_qml_buttons.files = $$PWD/BasicComponent/Button/*.qml taoquick_qml_buttons.path = $$[QT_INSTALL_QML]/$${uri}/BasicComponent/Button
taoquick_qml_mouse.files = $$PWD/BasicComponent/Mouse/*.qml taoquick_qml_mouse.path = $$[QT_INSTALL_QML]/$${uri}/BasicComponent/Mouse
taoquick_qml_others.files = $$PWD/BasicComponent/Others/*.qml taoquick_qml_others.path = $$[QT_INSTALL_QML]/$${uri}/BasicComponent/Others
taoquick_qml_progress.files = $$PWD/BasicComponent/Progress/*.qml taoquick_qml_progress.path = $$[QT_INSTALL_QML]/$${uri}/BasicComponent/Progress
taoquick_degisner_images.files = $$PWD/designer/images/*.png taoquick_degisner_images.path = $$[QT_INSTALL_QML]/$${uri}/designer/images
INSTALLS += taoquick_designer toaquick_qmldir taoquick_qml_buttons taoquick_qml_mouse taoquick_qml_others taoquick_qml_progress taoquick_degisner_images
最簡Demo
有讀者反饋說,上面的太複雜了,不容易抓住重點。濤哥特意寫了一個最簡單的Demo,給大家參考,github鏈接:
https://github.com/jaredtao/taomodule