QML SplitView: How this control handle their children items into internal item? - qt

I looking into source code of SplitView (%QT_SOURCE_PATH%\qml\QtQuick\Controls\SplitView.qml) and noticed that it used 3 Items to maipulate splitters and items:
Item {
id: contents
visible: false
anchors.fill: parent
}
Item {
id: splitterItems
anchors.fill: parent
}
Item {
id: splitterHandles
anchors.fill: parent
}
According to code, new items is placing into item splitterItems by the function addItem_impl(item). The fuction addItem_impl(item) are called from function init() that pass every child item from Item with id contents. But I wonder how all the children from root item were placed into contents Item?

Via a default property:
default property alias __contents: contents.data
From the documentation:
An object definition can have a single default property. A default property is the property to which a value is assigned if an object is declared within another object's definition without declaring it as a value for a particular property.
[...]
You will notice that child objects can be added to any Item-based type without explicitly adding them to the children property. This is because the default property of Item is its data property, and any items added to this list for an Item are automatically added to its list of children.
Default properties can be useful for reassigning the children of an item. See the TabWidget Example, which uses a default property to automatically reassign children of the TabWidget as children of an inner ListView. See also Extending QML.

Related

Is there a way to distinguish internally defined children from externally defined ones in QML?

I have defined a MyElement element (in the MyElement.qml file) as the following:
Rectangle {
Item {
}
Component.onCompleted: {
console.warn(children.length)
}
}
Let's call the Item element defined within MyElement the internal child. Now, I'm using the MyElement element in the following way:
MyElement {
Item {
}
}
Here another one Item element is used as a child of MyElement. Let's call this Item element the external child. To understand my question below one should clearly understand the difference between internal and external children.
The output for the presented code will be 2, i.e. both Item elements are calculated as children.
In the future I want to iterate in the block Component.onCompleted only over external children, not over internal (external children go after internal). But for this I have to know a children index from which I have to start (in the given example this index is 1). Is there a way to get this index or, in other words, the number of internal children? Thanks.
There is no internal mechanism in Qt to distinguish internal children from those which are defined outside of the own QML definition.
My workaround is as follow
//MyElement.qml
Rectangle {
id: root
readonly property Item last_item: lastone
Item {
id: someitem
}
Item {
id: lastone
}
Component.onCompleted: {
var external_started = false;
for(var i = 0 ; i < root.children.length ; ++i)
{
if(external_started)
console.log(root.children[i].toString(), 'is external');
else if(root.children[i]===last_item)
external_started = true;
}
}
}
and
MyElement {
Item {
objectName: 'I am external'
}
}
It's a dirty hack but it works.
I'm saving a reference to the last item in a readonly property called last_item and that will distinguish my last item in qml definition.
Other items which are added outside of the qml file, will be placed after this item in the children list.

Trying to style Qt QML items by inserting child styling item

I'm trying different approaches to styling a QT's app QML items. My goal is to:
limit the amount of code in the main files (hide all styling stuff in styling files, unlike in the Style Singleton approach)
not have to define every single type of item I'm going to use (unlike in the Custom Component approach)
possibly be able to mix and match different pre-defined styles in a single item.
Maybe there is a clear strategy to get this, I just didn't read about it yet. And maybe it doesn't make any sense anyway :-)
I've been playing with the idea of defining different components, one for each style type I want to define. The idea is to:
- define a component which is going to modify its parent
- insert that component where I want to adopt that specific style
A first approach relies on some javascript calls:
MyStyle.qml:
Item {
Component.onCompleted: {
parent.color = "lightblue"
parent.radius = 5
parent.border.width = 3
parent.border.color = "black"
}
}
And in my main code:
Rectangle {
id: testRectangle
anchors.fill: parent
MyStyle {}
}
This gives me the result I want, but it doesn't feel right:
I'd like for the styling to be applied statically, once and for all
if I start using this all over the place, won't I see artifacts when objects get created, and slow down my interface?
So I tried this too:
MyRectangleStyle.qml:
Item {
property Rectangle styleTarget
styleTarget.color: "lightblue"
styleTarget.radius: 5
styleTarget.border.width: 3
styleTarget.border.color: "black"
}
and in my main code:
Rectangle {
id: testRectangle
anchors.fill: parent
MyStyle {styleTarget: testRectangle}
}
But:
well, it doesn't work :-) (no warnings though, qml simply doesn't load)
and I'm sort of back to having to define every single type of items I'm going to use.
So, is there a better way to achieve what I'm trying to do here? Thanks!
Your second method does not work because your Component sets properties to an item that does not necessarily exist at the time of creating the Component, instead it sets the property when the styleTarget changes. On the other hand, it is not necessary for MyStyle to be an Item since it is not shown, instead use QtObject, and finally to generalize your method change property Item styleTarget toproperty Rectangle styleTarget:
QtObject {
property Item styleTarget
onStyleTargetChanged: {
styleTarget.color = "lightblue"
styleTarget.radius = 5
styleTarget.border.width = 3
styleTarget.border.color= "black"
}
}

Put rectangle in the center of display

I have one Item in one of my QML components and I need to know how to set x and y to put this rectangle in the center of the Display, whatever is the parent component, I just need put this particular Item in the center every time. I have tried with Screen component but I cannot set properly. Any idea?
This is my component:
Component {
id: example
CustomItem {
id: itemExample
}
}
What I need to set in CustomItem qml file to ensure that when I instance this component WHEREVER (in wherever parent), this CustomItem appears in on the center of display and on top of all other components?
EDIT: CustomItem is an Item and it not possible to use Window or ApplicationWindow.

Embed child in child of a custom type

I'm creating a custom type in QML that has a Column inside a GroupBox. When users of the type add components to CustomType, they should be inside the Column, not GroupBox. How can this be achieved without making extra wrapper files?
//CustomType.qml
GroupBox {
Column {
}
}
//Main.qml
CustomType {
CheckBox {//This should be inside the Column of the GroupBox in CustomType
}
}
You can create a property alias for the children of the GroupBox in CustomType.qml and declare it to be the default property, like this:
//CustomType.qml
GroupBox {
default property alias children: body.children
Column {
id: body
}
}
Whenever you add items to a CustomType, they will go into the Column.

Get index of the delegate currently displayed - QML ListView

I created a ListView, which displays a couple of pages of content defined by the user (plain text). The page displayed is a delegate. Only one page is visible at a time. I decided to use it to get snapping to one item, in the same way the iOS' launcher works. The user simply flicks between the pages. (this is to be used on touch screens)
I need to have the index of the currently displayed page for some operation. currentIndex of the ListView always stays == 0. How can I get it?
For those who prefer code:
ListView
{
onCurrentIndexChanged: console.log(currentIndex) // this gets called only once - at startup
delegate: Column
{
// The page displayed, only one page at a time
}
}
Thanks
There are many ways to get the index of current item that is displayed in the screen. If you can get the x-y coordinate of current page, you can use indexAt method in ListView.
And in each delegate, you can find the index using index role within the scope of the delegate. The index is like a role you declared in your model, and is automatically assigned by ListView. For example,
ListView
{
delegate: Column
{
property int indexOfThisDelegate: index
//...
}
}
The index role is introduced here:
A special index role containing the index of the item in the model is also available to the delegate. Note this index is set to -1 if the item is removed from the model...
Another way is to explicitly assign value to the currentItem property in ListView, so the view can scroll by itself. Here is an simple example in Qt documentation, which is similar to your application.
I know this is quite old but I had the same problem and spend some time trying to find a way to get currentIndex that would work for me. In my case sometimes I need to change the width of my ListView so I have to recalculte currentIndex manualy every time I resize it.
But I found a highlightRangeMode property. When it's set to ListView.StrictlyEnforceRange then currentIndex is always updated automaticly and contains correct index of the currently visible item.
ListView {
highlightRangeMode: ListView.StrictlyEnforceRange
// ...
}
You can do like that:
QModelIndex index =this->indexAt(event->pos());
this ->setCurrentIndex(index);
You can use attached properties of ListView class (ListView). They are attached to each instance of the delegate.
See ListView.isCurrentItem or ListView.view example:
ListView {
width: 180; height: 200
Component {
id: contactsDelegate
Rectangle {
id: wrapper
width: 180
height: contactInfo.height
color: ListView.isCurrentItem ? "black" : "red"
Text {
id: contactInfo
text: name + ": " + number
color: wrapper.ListView.isCurrentItem ? "red" : "black"
}
}
}
model: ContactModel {}
delegate: contactsDelegate
focus: true
}

Resources