QML基礎


BASIC

QWidget 和 QML

QWidgets were designed for a different type of user interface than QML, so it is not always a good idea to port a QWidget-based application to QML.

QWidgets are a better choice if your UI is comprised of a small number of complex and static elements.

QML is a better choice if your UI is comprised of a large number of simple and dynamic elements.

QtQuick提供了一套動態的QML元素來定制UI的Framework, 幫助程序員和設計師合作為便攜式設備建立流暢的UI; 

QML是對JavaScript的一種擴展, 使用QML元素來構建對象樹, 對QObject base類型系統進行改善, 支持自動屬性綁定;

Dependency

QtDeclarative: QtCore, QtGui, QtNetwork, QtOpenGL, QtScript, QtSql, QtSvg, QtXmlPatterns

http://qt-project.org/wiki/Qt_Library_Cross_Dependencies

 

QML語言格式

對象是指定的類型, 首字母大寫, 使用大括號;

Image {       
    source: "pics/logo.png"
    anchors.centerIn: parent       
}

屬性指定, property: value

屬性一般以單行指定, 也可以指定多個屬性, 使用分號作為語句的結束;

Rectangle { width: 100; height: 100 }

Import語句: import Qt 4.8 OR import QtQuick 1.1, 表示將QML元素或QtQuick庫包含進來;

JS表達式

屬性可以和表達式綁定, 還可以通過id引用其他對象的屬性;

Text {       
    id: text1       
    text: "Hello World"
}       
Text {       
    id: text2       
    text: text1.text       
}

QML注釋 單行 //...     多行 /*...*/

屬性

通常首字母小寫; property int textId;

屬性類型: 整型int, 實數real, 布爾bool, 字符串string, 顏色color, 列表等;

QML屬性會進行類型安全檢測;

x: "hello" // illegal!

id 每個對象有一個唯一的屬性-id, 同一個QML文件不能出現同名的id; id可以被對象以及腳本使用;

Note id首字符必須是小寫字符或下划線, 不能包含除字母,數字和下划線以外的字符;

列表屬性

Item {       
    children: [       
        Image {},       
        Text {}       
    ]       
}

對於單一項目列表, 可以省略方括號

Image {       
    children: Rectangle {}       
}

默認屬性: 屬性標記可省略

State {       
changes: [//可省略       
    PropertyChanges {},       
    PropertyChanges {}       
]//可省略       
}

分組屬性: 使用點操作符 '.' 或分組符號

Text {       
    font.pixelSize: 12       
    font.bold: true
}       
Text {       
    font { pixelSize: 12; bold: true }       
}

對象屬性: Type.property;

信號處理

MouseArea {       
    acceptedButtons: Qt.LeftButton | Qt.RightButton       
    onPressed: if (mouse.button == Qt.RightButton)     console.log("Right mouse button pressed")       
}

設置別名

property alias someName: element.property

QML定義signal

signal signalName(type Property)

使用時定義slot: 'onSignalName'

 

QtQuick針對C++開發者入門

Qt Framework運行性能高, 占內存小, 適合開發移動, 嵌入式與上網本的App;

QML是描述性語言, 適合設計師編寫; QML整合了JavaScript與Qt現存的QObject類型系統;

QtQuick包含QML, QDeclarative模塊, 以及QtCreator等工具;

QML文檔可以是本地文件, 網絡資源或者直接構建的文本數據; QML也是一個版本化的語言: import Lib version;

默認屬性 children: [Text {},Rectangle {}]; resources: [Timer {}]

錨屬性: anchors, 目前有17個;

可視化透明度 opacity: real; 在動畫中應該謹慎使用, 多個圖層進行渲染將導致性能下降; 最好在最終部署前對盡可能多的場景做預渲染;

子對象對於某些屬性可以繼承自父級對象;

互動元素

MouseArea - Flickable, Flipable, FocusScope; 可以使用JavaScript表達式;

狀態聲明 state

動畫 Transitions, Animation 

QML視圖模式 ListView GridView ListModel ListElement PathView C++QAbstractItemModel

QML文檔是UTF-8編碼格式的;

---End---

 

QML與Qt程序

Qt Declarative UI運行環境

QML文檔通過QML運行環境載入並運行. 包含Declarative UI引擎和內置的QML元素, 插件模塊, 還提供了訪問第三方的QML元素與模塊.

QML與Qt

單純使用QML可以不了解Qt, 但是如果想設計一個數據邏輯和UI分開的結構, 則需要用到Qt;

QML可直接訪問的Qt類:

QAction, signal and slot(can be used as function in JavaScript),

QWidget--QDeclarativeView(Qt5使用QQuickView代替, 屬於QWindow, 不用QWidget),

Qt Model--QAbstractItemModel

QML Tools

查看和調試QML的工具: qmlviewer

command: qmlviewer.exe filename.qml

 

將C++類注冊成為QML類型

#include <QtQml>       
qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider");

使用:

import com.mycompany.qmlcomponents 1.0       
Slider {       
    // ...       
}

以C++類創建QML屬性

1)inherited from QObject

2)declarate the Marco: Q_OBJECT(meta system), Q_PROPERTY(QML property)

Declarative UI

QDeclarativeView加載QML文件

QDeclarativeView是一個QWidget(QAbstractScrollArea), 可以加載QML文件;

QDeclarativeView view;       
view.setSource(QUrl::fromLocalFile("app.qml"));       
view.show();

PRO工程文件

QT += gui declarative

QDeclarativeEngine

可以直接加載QML, 創建QObject來進行操作;
每個程序至少需要一個Engine, 可以配置全局設置應用到所有的QML組件中;

QDeclarativeEngine: 提供了一個實例化QML Component的環境;
QDeclarativeComponent: 封裝QML Component的一個類;
QDeclarativeContext: 定義了一個通過QML engine工作的context, 可以將數據暴露給QML component;

QDeclarativeEngine engine;
QDeclarativeContext *windowContext = new QDeclarativeContext(engine.rootContext());
QDeclarativeComponent component(&engine, "application.qml");
QObject *window = component.create(windowContext);

Note 對於shadow build, qml文件需要放到build路徑中;

加上數據

>背景顏色

QDeclarativeContext *context = view.rootContext();
context->setContextProperty("backgroundColor",QColor(Qt::yellow));
view.setSource(QUrl::fromLocalFile("main.qml"));

當不需要QDeclarativeView顯示組件時, 可以使用QDeclarativeEngine::rootContext()代替

QDeclarativeContext *windowContext = new QDeclarativeContext(engine.rootContext());

QDeclarativeContexts是樹形結構, 除了root context每個QDeclarativeContexts都有一個父級, 子級QDeclarativeContexts繼承父級的context屬性.
這樣應用程序分隔不同數據導出到不同的QML對象實例有更多自由性.

結構化數據

除了QVariant支持內置數據類型外, QObject的派生類型也可以分配給context;

class CustomPalette : public QObject{
    Q_OBJECT
    Q_PROPERTY(QColor background READ background WRITE setBackground NOTIFY backgroundChanged)
    Q_PROPERTY(QColor text READ text WRITE setText NOTIFY textChanged)
...}
//...
view.rootContext()->setContextProperty("palette", new CustomPalette);

在QML中;

Rectangle {
color: palette.background }

在屬性改變時, Notify信號會被發出;(需要實現Notify, 在發出信號時注意判斷值是否改變)

QML調用C++

public slots或者Q_INVOKEABLE模式下的函數可以被QObject調用;

QML支持的返回值類型: bool; unsigned int, int; float, double, qreal; QString; QUrl; QColor; QDate,QTime,QDateTime; QPoint,QPointF; QSize,QSizeF; QRect,QRectF; QVariant;

Q_INVOKABLE bool isRunning() const;
public slots:
    void start();
    void stop();

作為context導入QML;

view.rootContext()->setContextProperty("stopwatch",new Stopwatch);

QML中使用;

onClicked: {
if (stopwatch.isRunning())
    stopwatch.stop()
else
    stopwatch.start();
}

更有效率的寫法:

onClicked: stopwatch.running = !stopwatch.running

網絡組件

如果QML或圖片等是網絡資源, QDeclarativeComponent要先獲取網絡數據, 才可以創建對象.

QDeclarativeComponent::statusChanged()和continueLoading(), 還需要防止組件是緩存中保存的;

MyApplication::MyApplication()
{
// ...
    component = new QDeclarativeComponent(engine, QUrl("http://www.example.com/main.qml"));
if (component->isLoading())
    QObject::connect(component, SIGNAL(statusChanged(QDeclarativeComponent::Status)), this, SLOT(continueLoading()));
else
    continueLoading();
}
void MyApplication::continueLoading()
{
if (component->isError()) {
    qWarning() << component->errors();
} 
else {
    QObject *myObject = component->create();
}
}

Qt資源

qrc是XML格式的文件, 會被rcc工具編譯成object文件, 鏈接到動態庫(shared library)中;

格式

<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/mainPage">
<file>main.qml</file>
<file alias = "images_bkg.png" >images/background.png</file>
</qresource>
</RCC>

prefix是內置前綴, 不是實際目錄名; alias可以幫助程序員將代碼改動限制在qrc內;

view.setSource(QUrl("qrc:/mainPage/main.qml"));

QML使用:

Image {
    source: "images_bkg.png"//"images/background.png" 
}

Note prefix會被帶入到qml內的資源搜索路徑中, 定義時需注意;
系統資源不能從QML直接訪問, 當QML文件被加載作為資源, 所有的文件指定在QML作為相對路徑從系統資源載入.
這種情況下在QML層訪問系統資源是完全透明的. 但是當QML文件沒有被加載作為資源, QML就無法訪問系統資源;

---End---

 

QML與Qt整合

基於QWidget用戶界面(把基於QWidget的程序導向QML不是個好主意)

QDeclaractiveView是QWidget的子類;

QDeclarativeView *qmlView = new QDeclarativeView;
qmlView->setSource(QUrl::fromLocalFile("myqml.qml"));
QWidget *widget = myExistingWidget();
QVBoxLayout *layout = new QVBoxLayout(widget);
widget->addWidget(qmlView);

>缺點 QdeclarativeView初始化慢, 比QWidget占用更大內存, 如果創建大量QDeclarativeView對象會導致性能下降;
這種情況下需要用QML重寫QWidget, 從主QML部件載入qml來代替QDeclarativeView;

QWidget UI是復雜的並且由少數靜態頁面組成的情況;
QML UI是簡單的並且由大量動態元素組成的情況;

基於QGraphicsView的UI

添加QML部件到一個QGraphicsScene; Graphics View Framework;

QGraphicsScene* scene = myExistingGraphicsScene();
QDeclarativeEngine *engine = new QDeclarativeEngine;
QDeclarativeComponent component(engine, QUrl::fromLocalFile("myqml.qml"));
QGraphicsObject *object = qobject_cast<QGraphicsObject *>(component.create());
scene->addItem(object);

>使用QDeclarativeComponent創建QGraphicsObject, QGraphicsScene::addItem()放置圖形;

Performance選項

QGraphicsView::setOptimizationFlags(QGraphicsView::DontSavePainterState)

QGraphicsView::setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate)

QGraphicsScene::setItemIndexMethod(QGraphicsScene::NoIndex)

QML載入QGraphicsWidget對象

使用qmlRegisterType();

C++寫QML擴展

QtDeclarative模塊提供API以便C++擴展QML; 添加QML類型, 擴展現有Qt, QML類型, 調用C++函數;

Tips

內置類型的轉換: QColor - 字符串"red", QSize - 字符串 800*600

繼承自QDeclarativeItem, 覆蓋paint()方法; 使用setParentItem()方法指定父級;

qmlRegisterType()注冊新的QML類型;

Q_INVOKABLE 聲明的方法可以被Qt metaObject系統和QML使用, slot函數也擁有相似的特性;

Qt::transparent可以將顏色變為透明; 

使用update()方法引發repaint;

Q_ENUMS導出枚舉類型;

列表屬性類型

Q_PROPERTY(QDeclarativeListProperty<PieSlice> slices READ slices)
QDeclarativeListProperty<PieSlice> slices();
static void append_slice(QDeclarativeListProperty<PieSlice> *list, PieSlice *slice);
//...
QDeclarativeListProperty<PieSlice> PieChart::slices()
{
    return QDeclarativeListProperty<PieSlice>(this, 0, &PieChart::append_slice);
}
void PieChart::append_slice(QDeclarativeListProperty<PieSlice> *list, PieSlice *slice)
{
    PieChart *chart = qobject_cast<PieChart *>(list->object);
    if (chart) {
        slice->setParentItem(chart);
        chart->m_slices.append(slice);
    }
}

QML

slices: [
PieSlice {
    anchors.fill: parent
    color: "red"
    fromAngle: 0; angleSpan: 110
},
PieSlice {
    anchors.fill: parent
    color: "black"
    fromAngle: 110; angleSpan: 50}
]

插件Plugin 

作為QDeclarativeExtensionPlugin子類; Q_EXPORT_PLUGIN2宏定義;
工程文件: 

CONFIG += qt plugin;

qmldir文件會被自動解析, 通知插件引擎載入; 

plugin project-plugins lib

---End---

 

refer to <QtQuick 中文手冊>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM