私はQMLが本当に好きです。コンポーネント(クラスと比較して)とそのプロパティを定義し、他の場所(オブジェクトと比較して)からそれらをインスタンス化する方法が好きです。
たとえば、ルックアンドフィールのあるボタンと、その上にラベルテキストを定義できます。これは、たとえば、次のコンポーネント定義(Button.qml
)を使用して実行できます。
Item {
id: button
property string label
anchors.fill: parent
Rectangle {
anchors.fill: parent
radius: 10
color: "gray"
Text {
anchors.centerIn: parent
font.pixelSize: 20
text: button.label
color: "white"
}
}
}
このメインファイル(main.qml
)にインスタンス化されています:
Rectangle {
width: 300
height: 200
Button {
anchors.centerIn: parent
anchors.margins: 50
label: "Hello button!"
}
}
しかし、次の制限があります。ボタンテンプレートを定義できるのは一部のプロパティを含むのみで、一部のプレースホルダーは定義できません。インスタンスで定義されたすべての子は、少なくともデフォルトでは直接の子になります。この動作を変更したいと思います。
ボタンにアイテム(画像としましょうが、Button
の定義に画像になることを伝えたくない)を配置したいとします。私はこのようなものを想像します:
Item {
id: button
property Item contents <-- the client can set the placeholder content here
anchors.fill: parent
Rectangle {
anchors.fill: parent
radius: 10
color: "gray"
Item {
id: placeholder <-- where the placeholder should be inserted
}
}
Component.onCompleted: {
// move the contents into the placeholder...
}
}
どうすればこれを達成できますか? Component.onCompleted
を使用することが正しい方法かどうかはわかりません。ただし、私の場合、内容は後で変更されないことに注意してください(少なくとも現在のアプリケーションの設計では...)。
また、プレースホルダー内でアンカーを機能させたいです。たとえば、コンテンツをText要素として定義し、その親(最初はテンプレート自体)を中心に配置するとします。次に、私のコードはこのTextインスタンスをプレースホルダーに移動し、親アンカーはテンプレートアイテムではなく、プレースホルダーアイテムのアンカーになります。
Qt Developer Days 2011 "Qt Quick Best Practices and Design Patterns" のプレゼンテーションで提案された、この質問に対するより良い答えを見つけました。
default property alias ...
を使用してalias子アイテムを任意のアイテムの任意のプロパティに使用します。 childrenにエイリアスを付けたくないが、エイリアスプロパティに名前を付けたい場合は、default
を削除してください。 (リテラルの子は、QML定義ごとにデフォルトプロパティの値です。)
Item {
id: button
default property alias contents: placeholder.children
anchors.fill: parent
Rectangle {
anchors.fill: parent
radius: 10
color: "gray"
Item {
id: placeholder <-- where the placeholder should be inserted
}
}
}
私のように他の誰かがここにたどり着いた場合に備えて、ネクロが答えます。
Qt5のどこかで、デフォルトのプロパティは「children」ではなく「 data "」になりました。これにより、「アイテム」以外のオブジェクトタイプを追加できます。例えば接続も追加できます(上記の私自身の質問に答えるため)
したがって、Qt5では次のことを行う必要があります。
Item {
id: button
default property alias contents: placeholder.data
anchors.fill: parent
Rectangle {
anchors.fill: parent
radius: 10
color: "gray"
Item {
id: placeholder <-- where the placeholder should be inserted
}
}
}
次の点に注意してください:placeholder.data
の代わりに placeholder.children
エイリアス名contents
を使用する必要がないことにも注意してください。これは任意の名前にすることができます。例:
Item {
id: button
default property alias foo: placeholder.data
...
}
実際、私が聞いたことからの正解は、 QMLローダー を使用して目的を達成することです。
[言われている;私はまだ実際に試していませんが、それは私の短期的な試用リストにあり、かなり簡単に見えます]
また、stackoverflowで他の "QML Loader" の質問を検索してください。開始するのに役立つ番号があります。
要するに(アイデアを示すために):
import QtQuick 1.1
Item {
width: 200
height: 100
//<-- the client can set the placeholder content here
property Item contents: Rectangle {
anchors.fill: parent
anchors.margins: 25
color: "red"
}
Rectangle {
id: container
anchors.fill: parent
radius: 10
color: "gray"
//<-- where the placeholder should be inserted
}
Component.onCompleted: {
contents.parent = container
}
}
やや長いバージョン(コンテンツの再割り当てをサポート):
import QtQuick 1.1
Item {
width: 200
height: 100
//<-- the client can set the placeholder content here
property Item contents: Rectangle {
//anchors can be "presupplied", or set within the insertion code
//anchors.fill: parent
//anchors.margins: 25
color: "red"
}
Rectangle {
id: container
anchors.fill: parent
radius: 10
color: "gray"
//<-- where the placeholder should be inserted
//Item {
// id: placeholder
//}
}
//"__" means private by QML convention
function __insertContents() {
// move the contents into the placeholder...
contents.parent = container
contents.anchors.fill = container
contents.anchors.margins = 25
}
onContentsChanged: {
if (contents !== null)
__insertContents()
}
Component.onCompleted: {
__insertContents()
}
}
お役に立てれば :)
次のコードを使用して、アイテムを移動できます(プレースホルダー内で複数のアイテムをサポートする場合)。
property list<Item> contents
Component.onCompleted: {
var contentItems = [];
for(var i = 0; i < contents.length; ++i)
contentItems.Push(contents[i]);
placeholder.children = contentItems;
}
QMLエンジンはリストプロパティに対しても単一の値を受け入れるため、contentsプロパティにアイテムのリストを指定する必要はないことに注意してください。