Qt 6 QML 和訳文書 P74~P101
Core Elements
要素は目に見えるもの(可視要素)と見えないもの(不可視要素)に分けることができます。目に見える要素(矩形のような)はジオメトリ(幾何領域)を持ち、普通はスクリーン上に領域を表現します。不可視要素(タイマーのようなもの)は、一般的な機能を提供し、普通は可視要素を操作するために使われます。現在、我々は基本的な可視要素に焦点を当てます。例えばItem, Rectangle, Text, ImageそしてMouseAreaです。しかしながら、Qt Quick Controls 2モジュールを使うことによって、ボタンや、ラベル、スライダーのような標準的なプラットフォームコンポーネントから作られるユーザーインターフェースを作ることが可能です。
Item Element
アイテムは全ての可視要素の基本要素であり、他の全ての可視要素はアイテムを継承しています。アイテムは自分自身を塗ることは無いのですが、全ての可視要素に共通しているプロパティを定義します。
ジオメトリ(幾何領域)-トップレフト位置を定義するxとy、要素の展開のためのwidthとheight,自然順序で要素をリフトアップ、またはリフトダウンするスタッキングオーダーのためのz
レイアウト処理 - anchors(left, right, top, bottom, vertical and horizontal center)任意の境界とともに他の要素と相対的に要素を位置づけるもの。
キー処理 - キー処理を制御するための Key プロパティと KeyNavigation プロパティ、および最初にキー処理を有効にするためのフォーカス プロパティが添付されています。
変換 - スケーリングと回転の変換、x、y、z 変換の一般的な変換プロパティ リスト、および transformOrigin ポイント。
ビジュアル - 透明度を制御する不透明度、要素の表示/非表示を表示するために表示、要素の境界にペイント操作を制限するためのクリップ、レンダリング品質を向上させるためのスムーズ。
状態定義 - サポートされている状態のリストを持つ状態リストプロパティ、現在の状態プロパティ、および状態の変化をアニメーション化するための遷移リストプロパティ。さまざまなプロパティをよりよく理解するために、提示された要素のコンテキストでこの章全体でそれらを紹介しようとします。これらの基本的なプロパティは、すべてのビジュアル要素で使用でき、これらの要素で同じように機能することを忘れないでください。
TIP
アイテム要素はしばしば他の要素のためのコンテナとして使用され、HTML内のdiv要素と似通っています。
Rectangle Element
矩形はアイテムを拡張し、塗りつぶしの色をそれに加えます。加えてborder.colorとborder.widthによって定義される境界をサポートします。丸い角の矩形を作るにはradiusプロパティを使うことができます。
Rectangle {
id: rect1
x: 12; y: 12
width: 76; height: 96
color: "lightsteelblue"
}
Rectangle {
id: rect2
x: 112; y: 12
width: 76; height: 96
border.color: "lightsteelblue"
border.width: 4
radius: 8
}
TIP
有効なカラーバリューは、SVGのカラーネーム(see http://www.w3.org/TR/css3-color/#svg-color (http://www.w3.org/TR/css3-color/#svg-color) )からの色です。QMLでは異なるやり方で色を提供することができますが、最も一般的な方法はRGBストリング型("#FF4444")あるいは、カラーネーム('white')です。ランダムな色はいくつかのJavaScriptを使って作ることができます。
color: Qt.rgba( Math.random(), Math.random(), Math.rando
塗りつぶしの色や境界以外にも、矩形もカスタムグラディエントをサポートします。
Rectangle {
id: rect1
x: 12; y: 12
width: 176; height: 96
gradient: Gradient {
GradientStop { position: 0.0; color: "lightsteelblue" }
GradientStop { position: 1.0; color: "slategray" }
}
border.color: "slategray"
}
グラデーションは、一連のグラデーション分岐点によって定義されます。各ストップには位置と色があります。位置は、Y 軸上の位置を示します (0 = 上、1 = 下)。グラデーションストップの色は、その位置の色をマークします。
TIP
幅が0で、高さが0の矩形は表示されません。これはあなたがいくつかの矩形の幅や高さを、それぞれお互いに依存させて決定しているときによく起きます。そして構成のための論理に何らかの間違いがあった時です。気を付けてください。
TIP
角度の付いたグラディエントを作ることはできません。(斜めのグラデ―ションのようなもの)このため、事前に定義されたイメージを使うのがよいです。一つの可能性は、グラディエントのある矩形を回転させるということですが、①回転した矩形のジオメトリ(幾何領域)は変化しませんし、そのために要素の矩形範囲として可視領域と同じではないので混乱する結果になります。著者の観点から申し上げれば、その場合は定義されたグラディエント画像を使うほうがよいです。(自分で角度のあるグラデーションを付けようとするよりは、そのようにした画像をそのまま持ってきた方がいいということです。)
①例えば、ある横幅の方が長い矩形を90度回転させると、全体の矩形範囲が変化します。
Text Element
テキストを表示するために、Text要素を使うことができます。もっとも注意するプロパティはストリング型のテキストプロパティです。要素は初期の幅と高さを、指定されたテキストと使用されるフォントを元にして計算します。フォントはフォントプロパティグループを使って影響を受けます。(例えば、font.family, font.pixelSize, …).テキストの色を変化させることはcolorプロパティを使うだけです。
Text {
text: "The quick brown fox"
color: "#303030"
font.family: "Ubuntu"
font.pixelSize: 28
}
「テキストはhorizontalAlignmentとverticalAlignmentプロパティを使って中心とそれぞれのサイドにテキストを整序することができます。テキスト表示をよりよくするには、スタイルとスタイルカラ―プロパティを使うことができ、テキストをアウトラインで表示することができ、アウトラインにはraisedとsunkenモードがあります。A very …のように長いテキストのためには中断箇所を示したい場合には、elideプロパティを使って達成できます。elideプロパティは左、右、中央にelide位置を設定することができます。
あなたが…elideモードが出現するのを求めないのであれば、wrapModeプロパティを使ってテキストを行送りすることもできます。(widthが明示的に設定されている場合のみ作動します。)
Text {
width: 40; height: 120
text: 'A very long text'
// '...' shall appear in the middle
elide: Text.ElideMiddle
// red sunken text styling
style: Text.Sunken
styleColor: '#FF4444'
// align text to the top
verticalAlignment: Text.AlignTop
// only sensible when no elide mode
// wrapMode: Text.WordWrap
}
「テキスト要素は指定されたテキストを表示するだけで、それを占める残りのスペースは透明です。これは全く背景装飾を表示しないという意味で、もしお望みであれば、背景色を提供するのはあなた次第です。」
TIP
「テキストアイテムの初期の幅は設定されたフォントとテキストストリングに依存していることを意識してください。幅が全くないテキスト要素とテキストが全くないテキスト要素は、不可視であり、初期の幅は0になります。
TIP
あなたがText要素にレイアウトを設定したい時は、整列しているText要素境界ボックス内テキストと、整列している境界ボックスそれ自体の間を区別する必要があります。前者はhorizontalAlignmentとverticalAlignmentプロパティを使い、後者は、要素の幾何領域を操作し、あるいはanchorsを使います。
Image Element
イメージ要素はいろいろなフォーマットでイメージを表示することができます。(例えば、PNG, JPG, GIF, BMP, WEBP)サポートされたイメージフォーマットの完全なリストは、Qt documentation(https://doc.qt.io/qt6/qimagereader.html#supportedImageFormats) .を見てください。image URLを提供するsource propertyに加えて、サイズ変更のふるまいを管理するfillModeを持ちます。
Image {
x: 12; y: 12
// width: 72
// height: 72
source: "assets/triangle_red.png"
}
Image {
x: 12+64+12; y: 12
// width: 72
height: 72/2
source: "assets/triangle_red.png"
fillMode: Image.PreserveAspectCrop
clip: true
}
TIP
URLはスラッシュでローカルパスでもいいですし、ウェブリンクでもOKです。
TIP
PreserveAspectCropを使っているイメージ要素はイメージの境界の外で表示されているイメージデータを避けるためのクリッピングも可能であるべきです。初期値ではクリッピングは無効です。(clip: false).クリッピングを有効にする必要があります( clip:true)ペイントを要素の外接する長方形に制限します。これは可視要素で使うことができますが、節約して使われるべきです。(https://doc.qt.io/qt6/qtquick-performance.html#clipping) .
TIP
「C++を使ってあなたはQQuickImageProviderを使いあなた自身のイメージプロバイダを作ることができます。これはあなたがその場でイメージを作り、スレッド化されたイメージの読込を利用するようにできます。」
MouseArea Element
「MouseAreaを使ってこれらの要素と相互連絡をします。マウスイベントをとらえることができる矩形の不可視アイテムです。ユーザーが可視部分と相互連絡を取るときに、マウスエリアはコマンドを実行するための可視要素と共に利用されることがよくあります。」
Rectangle {
id: rect1
x: 12; y: 12
width: 76; height: 96
color: "lightsteelblue"
MouseArea {
id: area
width: parent.width
height: parent.height
onClicked: rect2.visible = !rect2.visible
}
}
Rectangle {
id: rect2
x: 112; y: 12
width: 76; height: 96
border.color: "lightsteelblue"
border.width: 4
radius: 8
}
TIP
これはQt Quickの重要な側面です。入力操作は可視表現と分離されています。これは実際の相互作用領域がより大きくなることができるインターフェース要素をユーザーに見せることができます。(これは、実際の作業領域が見た目よりも大きい領域にすることができます。)
TIP
より複合的な相互領域のためには、Qt Quick入力ハンドラを見てください。(https://doc.qt.io/qt-6/qtquickhandlers-index.html)
それらは例えばMouseAreaとFlickableのような要素の代わりに利用される意図があり、より大きなコントロールと柔軟性を提供します。以前のように特定のソースからのすべてのイベントの処理を単一の要素に集中させるのではなく、各ハンドラーインスタンスで1つの相互作用の側面を処理するという考えです。
Components
コンポーネントは再利用可能な要素です。QMLはコンポーネントを作るための異なる方法を提供します。現在、私たちは最も簡単な形式だけを見ます。ファイルを基本としたコンポーネントです。ファイルを基本としたコンポーネントはファイル内のQML要素を置くこと、ファイルに要素名を与えることによって造られるものです。(例えば、Button.qml).あなたはQt Quickモジュールから全ての他の要素のようにコンポーネントを使うことができます。私たちの場合、子コードの中ではButton{…}としてこれを使います。例えば、テキストコンポーネントとマウスエリアをもつ矩形を作りましょう。これは単純なボタンに似せており、目的をはずれる余計に複雑なものになる必要はありません。
Rectangle { // our inlined button ui
id: button
x: 12; y: 12
width: 116; height: 26
color: "lightsteelblue"
border.color: "slategrey"
Text {
anchors.centerIn: parent
text: "Start"
}
MouseArea {
anchors.fill: parent
onClicked: {
status.text = "Button clicked!"
}
}
Text { // text changes when button was clicked
id: status
x: 12; y: 76
width: 116; height: 26
text: "waiting ..."
horizontalAlignment: Text.AlignHCenter
}
}
UIはこれと似通っています。最初のイメージでは、UIは初期状態にあり、2番目のイメージでは、ボタンが押されました。
今や私たちの仕事は再利用可能なボタンUIを抽出することです。このために、私たちはボタンのための可能なAPIについて考えるべきです。あなたは他の誰かがどうやってあなたのボタンを使うべきかを想像することによってこれを行います。こちらが私が考え付いたものです。
// minimal API for a button
Button {
text: "Click Me"
onClicked: { /* do something */ }
}
私はテキストプロパティを使ってテキストを設定したいし、私自身のクリックハンドラを実装したい。また、私はボタンが目的にかなっている初期サイズをもつことを期待していて、そのサイズは上書きできます。(例えば、width: 240)これを達成するために私たちはButton.qmlというファイルを作り、私たちのボタンUIを内側にコピーします。(コピーして貼り付けます。)加えて、ユーザーがルート段階で変化させたいプロパティをエクスポートする必要があります。
// Button.qml
import QtQuick
Rectangle {
id: root
// export button properties
property alias text: label.text
signal clicked
width: 116; height: 26
color: "lightsteelblue"
border.color: "slategrey"
Text {
id: label
anchors.centerIn: parent
text: "Start"
}
MouseArea {
anchors.fill: parent
onClicked: {
root.clicked()
}
}
}
「私たちはテキストプロパティとclickedシグナルをルート段階でエキスポートします。普通、参照をより簡単にするために、rootという名前をroot要素に付けます。私たちはネストされたQML要素の中にあるプロパティをルート段階へエクスポートする手段であり、これを外部の世界で利用可能にするQMLのエイリアス機能を使います。ルート段階のプロパティだけが、他のコンポーネントによって、このファイルの外からアクセス可能であるということを知っておくのは重要なことです。新しいButton要素を使うために、私たちはファイル内でそれを簡潔に宣言することができます。だから前に見せたエグザンプルは、ちょっと単純化されます。」
Button { // our Button component
id: button
x: 12; y: 12
text: "Start"
onClicked: {
status.text = "Button clicked!"
}
}
Text { // text changes when button was clicked
id: status
x: 12; y: 76
width: 116; height: 26
text: "waiting ..."
horizontalAlignment: Text.AlignHCenter
}
今Button{ …}を使うだけであなたのUI内は好きなように多くのボタンとして利用することができます。本当のボタンはもっと複雑になる可能性があります。例えば、クリックされるとき、あるいはよりいい装飾を表示するときにフィードバックを提供します。
TIP
Item {
id: root
width: 116; height: 26
property alias text: label.text
signal clicked
Rectangle {
anchors.fill parent
color: "lightsteelblue"
border.color: "slategrey"
}
...
}
With this technique, it is easy to create a whole series of reusable components.
もしあなたが望むのであれば、さらなるステップを踏み、そしてItemをルート要素として利用できます。これはユーザーが私たちがデザインしたボタンの色を変更させないようにし、そして、エキスポートされたAPIを越えたコントロールを私たちに提供するものです。目的は最小限のAPIをエクスポートすることであるべきです。実践では、これは私たちがルートのRectangleを、Itemに置き換える必要があり、ルートアイテム内の矩形をネストされた要素にします。
この技術で、全体の再利用可能なコンポーネントを作ることができます。
Simple Transformations
変換はオブジェクトの幾何領域を操作します。QMLアイテムは、一般的に、移動、回転、そしてスケーリングが可能です。これらの実行の単純な形があり、より進んだ方法があります。単純な変換でスタートしてみましょう。こちらはスタート地点としてのシーンです。単純な移動はx, yの位置を変化させることによって行われます。回転はrotationプロパティを使って行われます。値は(0…360)度で提供されます。スケーリングはscaleプロパティを使って行われ、value < 1は要素が縮小し、>1は要素が拡大することを意味します。回転とスケーリングはアイテムの幾何領域を変化させません。x, yそしてwidth/heightは変化しません。唯一ペイント指示は変換されます。私たちが例を見せる前に、ちょっとした便利な道具をご紹介します。ClickableImage要素です。ClickableImageは丁度マウスエリア付きのイメージです。これは便利な経験則をもたらします - コードのチャンクを3回コピーした場合は、それをコンポーネントに抽出します。
// ClickableImage.qml
// Simple image which can be clicked
import QtQuick
Image {
id: root
signal clicked
MouseArea {
anchors.fill: parent
onClicked: root.clicked()
}
}
// TransformationExample.qml
import QtQuick
Item {
// set width based on given background
width: bg.width
height: bg.height
Image { // nice background image
id: bg
source: "assets/background.png"
}
MouseArea {
id: backgroundClicker
// needs to be before the images as order matters
// otherwise this mousearea would be before the other e
// and consume the mouse events
anchors.fill: parent
onClicked: {
// reset our little scene
circle.x = 84
box.rotation = 0
triangle.rotation = 0
triangle.scale = 1.0
}
}
ClickableImage {
id: circle
x: 84; y: 68
source: "assets/circle_blue.png"
antialiasing: true
onClicked: {
// increase the x-position on click
x += 20
}
}
ClickableImage {
id: box
x: 164; y: 68
source: "assets/box_green.png"
antialiasing: true
onClicked: {
// increase the rotation on click
rotation += 15
}
}
ClickableImage {
id: triangle
x: 248; y: 68
source: "assets/triangle_red.png"
antialiasing: true
onClicked: {
// several transformations
rotation += 15
scale += 0.05
}
}
// ...
円はx位置をそれぞれのクリックで増加させ、四角はそれぞれのクリックで回転します。三角はそれぞれのクリックで回転とスケールアップをし、組み合わせの変換を実証します。スケーリングと回転のために、antialiasing: trueを設定し、アンチエイリアスを可能にしますが、パフォーマンスの理由で、スイッチが切られています。あなたが自分でする時には、グラフィックス内でラスタライズされているということがわかるようなときには、おそらくはスイッチをオンにするべきです。
TIP
イメージをスケーリングするときに視覚の質をより高めるためには、upの代わりにdownをお勧めします。イメージをより大きくするスケールファクターで拡大することは、スケール化している人工遺物(ぼやけた画像)という結果になります。smooth: trueを使うことを考慮に入れて行えば、パフォーマンスのコストで、より高度な質のフィルターの使用を可能にします。
背景のMouseAreaは全体の背景をカバーしており、オブジェクトの値をリセットします。
TIP
コード内で早い段階で現れる要素は、(zオーダーと呼ばれる)より下位のスタッキングオーダーを持ちます。もし円の上で十分長くクリックをすれば、それは四角の下へ移動します。z-orderもまたアイテムのzプロパティによって操作されることもできます。
これは四角がコード順でいえば、後から現れるからです。同じことはmouse areaにも当てはまります。コードの後ろにあるmouse areaはコードでより前にあるmouse areaに重なり合います。(そしてそれゆえマウスイベントを掴みます。)思い出してください。ドキュメント内の要素の順番は重要です。
Positioning Elements
アイテムを位置づける多くのQML要素があります。これらはいわゆるポジショナー Qt Quickモジュールが次の通りのものを提供しているものです:Row, Column, Grid and Flow. 下記のイラスト内で同じ内容を表示ししてみることができます。
TIP
詳細に入る前に、いくつかの役に立つものを紹介させてください。red, blue, green, lighter そして darker正方形です。これらのコンポーネントのうちそれぞれは、48×48のピクセルでカラーされた矩形を持ちます。参照として、こちらはRedSquareのためのソースコードです。
// RedSquare.qml
import QtQuick
Rectangle {
width: 48
height: 48
color: "#ea7025"
border.color: Qt.lighter(color)
}
fill colorを基本としてより軽い色のborder色を生産するためQt.lighter(color)の使用を覚えてください。私たちは次の例でソースコードをよりコンパクトに、そして読みやすくするため、次の例でこれらの役に立つものを使います。それぞれの矩形は最初48×48のピクセルであることを、思い出して下さい。
Column 要素は、子項目を積み重ねて列に配置します。spacing プロパティを使用すると、各子要素を互いに離すことができます。
// ColumnExample.qml
import QtQuick
DarkSquare {
id: root
width: 120
height: 240
Column {
id: column
anchors.centerIn: parent
spacing: 8
RedSquare { }
GreenSquare { width: 96 }
BlueSquare { }
}
}
// RowExample.qml
import QtQuick
BrightSquare {
id: root
width: 400; height: 120
Row {
id: row
anchors.centerIn: parent
spacing: 20
BlueSquare { }
GreenSquare { }
RedSquare { }
}
}
Grid 要素はグリッド内で子を整理します。rowsとcolumnsプロパティを設定することによって、rowsあるいはcolumnsの数が制限されます。それらのいくつかを設定しないことによって、一方は子アイテムの数から計算されます。例えば、行を3へセットして、6つのアイテムは結局2列になります。プロパティのflowとlayoutDirectionはアイテムがグリッドへ追加される順番を管理するために使われます、一方spacingは子アイテムを分離するスペースの量を管理します。
// GridExample.qml
import QtQuick
BrightSquare {
id: root
width: 160
height: 160
Grid {
id: grid
rows: 2
columns: 2
anchors.centerIn: parent
spacing: 8
RedSquare { }
RedSquare { }
RedSquare { }
RedSquare { }
}
}
最後のポジショナーがFlowです。その子アイテムをflowで加えます。flowの方向はflowとlayoutDirectionを使って管理されます。上から下へかけて、斜めに実行できます。左から右へ、あるいは反対に右から左へ実行することもできます。アイテムがflow内に加えられると、必要に応じて行送りになり、新しい行やカラムを形成します。flowを働かせるためには、widthあるいはheightを持たせなければなりません。これは直接設定するか、あるいはanchorレイアウトを通して設定できます。
// FlowExample.qml
import QtQuick
BrightSquare {
id: root
width: 160
height: 160
Flow {
anchors.fill: parent
anchors.margins: 20
spacing: 20
RedSquare { }
BlueSquare { }
GreenSquare { }
}
}
ポジショナでよく使われる要素はRepeaterです。これはforループのように動き、モデルを配列処理します。最も単純なケースでは、モデルはループの数を提供する単なる値です。
// RepeaterExample.qml
import QtQuick
DarkSquare {
id: root
width: 252
height: 252
property variant colorArray: ["#00bde3", "#67c111", "#ea702
Grid{
anchors.fill: parent
anchors.margins: 8
spacing: 4
Repeater {
model: 16
delegate: Rectangle {
required property int index
property int colorIndex: Math.floor(Math.random
width: 56; height: 56
color: root.colorArray[colorIndex]
border.color: Qt.lighter(color)
Text {
anchors.centerIn: parent
color: "#f0f0f0"
text: "Cell " + parent.index
}
}
}
}
}
このリピーターエグザンプルでは、新しい魔法を幾つか使います。カラーの配列である、自己定義のcolorArrayプロパティを定義します。リピーターは一連の矩形を作ります。(16, モデルとして定義されているので)
それぞれのループごとに、リピーターの子によって定義されている矩形を作ります。矩形内では、JavaScriptのmath funtions: Math.floor(Math.random()*3)関数を使って色を選択します。
これは私たちに0..2からの範囲でランダムの数を与え、カラーの配列から色を選択するのに使います。早い段階で重要となるのは、JavaScriptはQt Quickの中核となる部分であり、例えば、標準ライブラリが私たちにとって利用可能であるということです。repeaterはrepeater内のindexプロパティへ介入します。それは現在のループインデックス(0, 1,..15)を持ちます。
私たちはこれをインデックスを基本とした自己定義をするために使い、あるいはText要素で現在のindexを可視化するためにこれを使います。
TIP
インデックスプロパティは動的にRectangleに介入される一方、読込みを容易にし、ツールを助けるために必要なプロパティとして宣言をするのはいい習慣です。これはint indexの行で必要なプロパティによって達成されます。
TIP
より大きなモデルのより進んだ処理、そして動的なデリゲートによる物理運動のビューは、それ自体モデルビューの章でカバーされます。Repeaterは表現される少量の静的なデータを持つ時に最もよく利用されるものです。