I'm trying to make some qml components that are more general but have the flexibility of defaults but for items. Here are some example components
A.qml
import QtQuick 2.15
Rectangle {
property alias inner: inside.data
color: "red"
width: 40
height: 40
Item {
id: inside
}
}
B.qml
import shared.debug 1.0 as Debug
import QtQuick 2.15
Debug.A {
inner: Rectangle {
width: 30
height: 30
color: "blue"
}
}
C.qml
import shared.debug 1.0 as Debug
import QtQuick 2.15
Debug.B {
inner: Rectangle {
width: 20
height: 20
color: "black"
}
}
qmldir
module shared.debug
A 1.0 A.qml
B 1.0 B.qml
C 1.0 C.qml
Used here
Column {
spacing: 10
Debug.A {}
Debug.B {}
Debug.C {}
}
Im looking for a way to make the Debug.C show just the red and black squares, i understand why the blue is showing but i was hoping i could make a straight forward default and then have it be removed and overwritten when used by a child element.
Ive tried to make properties that dont use alias but thats the same problem. Ive also tried just hiding the original content but that feels roundabout in that the original items are still there just not visible.
I would suggest using a Loader instead of an Item in A.qml:
import QtQuick 2.15
Rectangle {
property alias inner: inside.sourceComponent
color: "red"
width: 40
height: 40
Loader {
id: inside
}
}
Then you can replace that inside field with a Component of your choosing:
B.qml:
Debug.A {
inner: Component {
Rectangle {
width: 30
height: 30
color: "blue"
}
}
}
The data property is of type list<QtObject>. It seems like binding to it multiple times will append.
Column {
spacing: 10
A { Component.onCompleted: console.log("A", inner.length) } // 0
B { Component.onCompleted: console.log("B", inner.length) } // 1
C { Component.onCompleted: console.log("C", inner.length) } // 2
}
Similar like making the alias to the data property the default which means all child items of component A would be appended to the list.
component A: Rectangle {
default property alias inner: inside.data
color: "red"; width: 80; height: 80
Item {
id: inside
}
}
component B: A {
Rectangle { width: 40; height: 40; color: "blue" }
}
component C: B {
Rectangle { width: 20; height: 20; color: "black" }
}
To circumvent this you could make inner an Item and bind it to the data or children property.
DANGER Keep in mind that this is a "hack". You should only use it if you know what you're doing. You can't add any other item into the inner Item because the binding on data will always overwrite it.
component A: Rectangle {
property Item inner
color: "red"; width: 80; height: 80
Item {
data: [inner]
}
}
component B: A {
inner: Rectangle { width: 40; height: 40; color: "blue" }
}
component C: B {
inner: Rectangle { width: 20; height: 20; color: "black" }
}
Column {
spacing: 10
A {}
B {}
C {}
}
Related
It seems should have a solution for sure.
Suppose I have a Test.qml file containing this:
import QtQuick 2.0
Rectangle {
color: "green"
Row {
id: row
spacing: 10
anchors.fill: parent
Rectangle {
color: "red";
width: 100;
height: 100;
}
Rectangle {
color: "red";
width: 100;
height: 100;
}
Rectangle {
color: "red";
width: 100;
height: 100;
}
}
}
Now suppose we want to use this Test.qml within another file like main.qml:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: window
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Test {
anchors.fill: parent;
// I want to be able to add new items (rects) to the row inside Test.qml
}
}
Now suppose we want to extend items to the row object in Test.qml, But we want to add from main.qml. How we can do that? is that even possible?
(FYI: The application of this feature would be to develop a placeholder form and fill the items in the other items so we can skip duplicate codes. )
You can do this without creating objects dynamically. You need to use a default property that is aliased to the contents of your Row. A default property means Items that get added to your object will actually be assigned to that property instead. In Test.qml, add this:
Rectangle {
color: "green"
default property alias contents: row.data
Row {
id: row
...
}
}
Now you can add other items to it from main.qml, like this:
Test {
anchors.fill: parent;
// Automatically gets added to 'row'
Rectangle {
color: "blue"
width: 100
height: 100
}
}
You can create objects dynamically:
MyRow.qml:
Row {
id: row
spacing: 10
anchors.fill: parent
Rectangle {
color: "red";
width: 100;
height: 100;
}
}
main.qml:
MyRow{
id: myRow
Component.onCompleted: Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "green"; width: 100; height: 100}', myRow)
}
[EDIT]: I want to remove some controls which are created in Column QML type dynamically and also how to access the children of a layout? .Following is the code which is not dynamic and is just for reference:
import QtQuick 2.6
import QtQuick.controls 2.2
Item
{
Column {
id:col
spacing: 2
//Initially Adding controls.
Rectangle { color: "red"; width: 50; height: 50 }
Rectangle { color: "green"; width: 20; height: 50 }
Rectangle { color: "blue"; width: 50; height: 20 }
}
Button
{
id:button
onClicked:
{
//How to remove a perticular element from above column which is created dynamically?
}
}
// [EDIT] - Code to add controls dynamically to column.
}
//How to remove perticular element from above column ?
Use the below mentioned code [Reference: https://stackoverflow.com/a/8852535/3459185]:
col.children[index_to_destroy].destroy()
[EDIT] Sample code to add and delete elements dynamically in a column:
Item
{
ListModel {
id: elementModel
ListElement { elementColor: "red"; elementWidth: 50; elementHeight: 50}
ListElement { elementColor: "green"; elementWidth: 20; elementHeight: 50}
ListElement { elementColor: "blue"; elementWidth: 50; elementHeight: 20}
}
Column {
id:col
spacing: 2
Repeater {
model: elementModel
Rectangle { color: elementColor; width: elementWidth; height: elementHeight }
}
}
Button
{
id: deleteButton; x: 200; y: 200; height: 50; width: 50; text: "Delete"
onClicked:
{
//How to remove perticular element from above column ?
elementModel.remove(index)
}
}
Button
{
id: addButton; x: 400; y: 200; height: 50; width: 50; text: "Add"
onClicked:
{
// Code to add controls dynamically to column.
elementModel.insert(index, { "elementColor": "red", "elementWidth": 50, "elementHeight": 50})
}
}
}
I wonder if it is possible to somehow use an ObjectModel as the model for multiple DelegateModel to use it's ability to create Groups.
For example, I might have an ObjectModel containing multiple Rectangle as this
ObjectModel {
id: rootModel
Rectangle { width: 50; height: 20; color: 'red' }
Rectangle { width: 80; height: 50; color: 'blue' }
Rectangle { width: 50; height: 20; color: 'green' }
Rectangle { width: 80; height: 50; color: 'orchid' }
Rectangle { width: 50; height: 20; color: 'black' }
}
My goal might be to display all Rectangle with the width: 50 in one View, while those with the width: 80 in another view.
So I create a DelegateModel
DelegateModel {
id: delMod1
model: rootModel
groups: [
DelegateModelGroup { name: 'width50' },
DelegateModelGroup { name: 'width80' }
]
}
As far as I understood the documentation I need to attach the property
item.DelegateModel.inWidth50: ....width === 50
item.DelegateModel.inWidth80: ....width === 80
or something like this, to add my elements to the groups. But this is where I fail as I don't know where and how to do this.
Though there are tons of workarounds (such as disassembling the Objects in the ObjectModel and using a ListModel, recreating the Objects in the DelegateModel delgate, which robbs a lot of the versatility as the Objects and it's children would need to have a predictable structure...) I think it would be wonderful, if it is possible to make this idea run.
Takk fyrir,
-m-
I may need to read or write to some of the properties of the Loader's sourceComponent from some outside function.
What is the way to access the property x of the object inside this Loader's sourceComponent?
import QtQuick 2.0
Item {
width: 200; height: 200
Loader {
anchors.fill: parent
sourceComponent: rect
}
Component {
id: rect
Rectangle
{
width: 50
height: 50
color: "red"
property int x
}
}
}
When you need to expose an inner object/property to the outside, you should create an alias to it.
import QtQuick 2.0
Item {
width: 200; height: 200
property alias loaderItem: loader.item
Loader {
id: loader
anchors.fill: parent
sourceComponent: rect
}
Component {
id: rect
Rectangle
{
width: 50
height: 50
color: "red"
property int x
}
}
}
It would seem that in the design of QML user reparent was not really "envisioned", because even though it is possible, it involves creating and changing states, which is just not convenient to add to each and every item.
import QtQuick 1.0
Item {
width: 200; height: 100
Rectangle {
id: redRect
width: 100; height: 100
color: "red"
}
Rectangle {
id: blueRect
x: redRect.width
width: 50; height: 50
color: "blue"
states: State {
name: "reparented"
ParentChange { target: blueRect; parent: redRect; x: 10; y: 10 }
}
MouseArea { anchors.fill: parent; onClicked: blueRect.state = "reparented" }
}
}
I was wondering if there is a more elegant way to reparent items without polluting items with unnecessary states?
not certain if you need to use QtQuick 1.0, but with 2.0 this also works and is imo more straight forward.
import QtQuick 2.0
Item {
width: 200; height: 100
Rectangle {
id: redRect
width: 100; height: 100
color: "red"
}
Rectangle {
id: blueRect
x: redRect.width
width: 50; height: 50
color: "blue"
MouseArea { anchors.fill: parent; onClicked:
{ blueRect.parent = redRect; blueRect.x = 10; blueRect.y = 10 }
}
}
}