QMLコンポーネントの基本

Basics of QML components
Qt QuickのUIレイアウトに用いられるQMLは、Itemから派生したコンポーネントから成り立っています。初めにデザイナーを表示したときは、使用できるコンポーネントはImageやTextなどシンプルなものしかありませんが、これはライブラリーを追加することで拡張することができます。

「インポート」タブにある「<インポートを追加>」と表示されているコンボボックスから「QtQuick.Controls」を選択すると、コントロールライブラリーが追加され、カラムコンテナやボタンなど、GUIで幅広く使用されるコントロールが利用できるようになります。対象のQMLファイルを開くと行頭に「import QtQuick.Controls (バージョン)」の一文が追加されているのが確認できます。
まずはデザイナに「Qt Quick - Positioner / Column」を追加し、その中に「Qt Quick - Controls 2 / Label」と「Qt Quick - Controls 2 / Button」を追加してみましょう。Columnパネルにそれぞれのコントロールを入れ子にすることで、自動で垂直に並べられます。
QMLコンポーネントは「プロパティ」と「メソッド」という概念によって、プログラムから制御することができます。たとえば、デザイナーでラベルを選択した状態で「Text Color」で赤色を選ぶか、QMLのlabelに「color:"red"」を直接記述するなどすると、テキストが赤色に変わります。対象のコンポーネントに用意されているプロパティはQtのドキュメントでも確認することができます。
Qtではイベントのことを「シグナル」と呼んでおり、特定の条件を満たすとこのシグナルが呼び出されます。QMLでは「on+頭を大文字にしたシグナル名」のプロパティを追加することで、イベントを把握することができます。

main.qmlのButtonを以下のように書き換えてみましょう。
button.qml
Button {
    id: button
    text: qsTr("Button")
    focusPolicy: Qt.ClickFocus
    anchors.horizontalCenter: parent.horizontalCenter
    onPressed:{
        label.text = "Pressed";
    }
    onReleased: {
        label.text = "Released";
    }
}
ボタンが押されると「pressed」シグナルが発生し、「onPressed」関数が呼び出されます。ここでJavaScriptで「idがlabelのコンポーネント」の「text」プロパティを「Pressed」にする命令があるため、ボタンを押すとラベルが「Pressed」に置き換わります。同様に、ボタンを離すとonReleaseが呼び出されて、ラベルに「Released」と表示されます。

コントロールにどのようなシグナルがあるかは、Qtドキュメント(例:ボタンシグナル一覧)で全て確認できます。

QMLに記入したコンポーネントには独自のプロパティも追加できます。定義は「property [型] [名称]:[初期値]」のように記述し、主な型として以下のものが挙げられます。Variable値はJavaScriptでのvarにあたり、文字列や数値など様々な値を代入できますが、C++との連携がしづらく、また、処理速度低下の原因にもなるので、あまり使わないほうがよいでしょう。

型名内容
int整数値
real浮動小数(C言語のfloatに相当)
double浮動小数
string文字列
boolBoolean値(true/false)
color
sizeサイズ(width/height)
rect矩形位置(x/y/width/height)
varVariable値

これは独自プロパティを使ったサンプルです。ボタンを押すたびにlabelにあるcountプロパティの値が1ずつ増えて、その値がラベルに表示されます。
count.qml
Label {
    id: label
    text: qsTr("Label")
    property int count:0
}

Button {
    id: button
    text: qsTr("Button")
    onPressed:{
        label.count++;
        label.text = label.count;
    }
}
プロパティ同士を直接紐づける方法はプロパティバインディングと呼ばれ、QMLコードをより簡潔にさせることができるだけでなく、「width: label.width / 2」のような、特定のコントロールのサイズを連動させるといった使い方が可能です。
binding.qml
Label {
    id: label
    // countの値が変わるとtextも連動して変化する
    property int count:0
    text: count
}

Button {
    id: button
    text: qsTr("Button")
    // 1行に収まるのなら、{}は省略できる。
    onPressed: label.count++
}
プロパティ自体の値が変化したときにシグナルを発生させることができます。QMLでは「on+頭を大文字にしたプロパティ名+Changed」で定義でき、値が変化するたびにこの関数が呼び出されます。
propchange.qml
Label {
    id: label
    text: qsTr("Label")
    color: "red"
    property int count:0
    onCountChanged: {
        // count値が変わるたびに呼び出される
        // なお、「this」はこのLabelを指している
        this.text = count;
    }
}

Button {
    id: button
    text: qsTr("Button")
    onPressed:{
        label.count++;
    }
}
例えば、Itemコンポーネントには「resize」のようなシグナルがないので、「onWidthChanged」「onYChanged」などを定義することで、ウィンドウやコントロールのサイズ変更を検出することになります。
2018/10/26