How to pass two arguments to AppListView separator - qt

I would like to display AppListView with separators of custom delegates. Separators should have 2 properties - color defined as string and text also defined as a string - both coming from my model as roles and they always come in pairs so for example
if color is #b3b3b3 text is always AA,
if color is #eeeeee text is always BB.
I cannot find any option to pass two arguments to my section, so I can make both color and text to be displayed on my separator.
For those who prefer code:
AppListView {
id: list
section {
property: "separatorTextRole" /* here I set my first role to be separator property */
criteria: ViewSection.FullString
delegate: CustomSeparatorDelegate {
itemColor: /* how can I pass also my separatorColorRole here? */
itemText: section /* here I access my separatorTextRole */
}
}
delegate: CustomListDelegate {
text: nameRole
row: rowRole
value: valueRole
}
}

Related

How to make TextInput cursorDelegate wider + taller

Is there a way to style the cursorDelegate on a TextArea/TextInput so that it ends up taller and thicker than the default one?
With the following code, I can currently get one that has the following properties:
Thicker than normal, at 4px wide
Taller than the rest of the text, with bits sticking out above/below the line as wanted. BUT, this only works until the user moves the cursor. Then, the vertical size gets clipped again, and can't be reset.
TextArea {
id: editor
cursorDelegate: Rectangle {
width: 4
property int vpad: 4
y: editor.cursorRectangle.y - (vpad / 2)
height: editor.cursorRectangle.height + vpad
}
}
It looks like the y and height bindings are getting overwritten by whatever sets those automatically internally.
Trying to overwrite these again myself using a onCursorPositionChanged handler on the TextArea fails, as you cannot write to cursorDelegate.
Managed to find a solution. Instead of setting these values in the normal way, you need to set these on the change handlers for those properties.
TextArea {
id: editor
cursorDelegate: Rectangle {
width: 4
property int vpad: 4
onYChanged: editor.cursorRectangle.y - (vpad / 2)
onHeightChanged: editor.cursorRectangle.height + vpad
}
}
This seems to resist the widgets auto behaviour that was overwriting our values.

Qml - passing property value between two components

This is a simplification of the situation I am dealing with in main.qml file:
Component {
id: component1
property string stringIneedToPass: "Hello"
Text { text: stringIneedToPass }
}
Component {
id: component2
Rectangle {
id: myRectangle
property string stringIneedToReceive = component1.stringIneedToPass; //this doesn't work
}
}
Obviously my situation is more complicated. But in the end I just need to understand how this kind of transfer should be done!
Thank you all!
First of all, a Component element cannot have properties. Components are either loaded from files, or defined declaratively, in the latter case they can contain only one single root element and an id.
Second - you cannot do assignment in the body of an element, only bindings.
Third - you cannot reference properties defined inside an element inside a component from the outside, as that object doesn't exist until the component is instantiated. Such objects can only be referenced from inside.
Other than that, it will work as expected, if you can reference it, you can bind or assign it to a property, depending on what you want.
So you can simply have the string property external:
property string stringIneedToPass: "Hello"
Component {
id: component1
Text {
text: stringIneedToPass
}
}
Component {
id: component2
Rectangle {
id: myRectangle
property string stringIneedToReceive: stringIneedToPass
}
}

Custom attached properties in QML

I'm creating a custom QML component (a specialization of ListView that allows multiple selection). I'd like to provide attached properties to objects provided to my component. I see how to create attached properties using C++. However, I cannot find information on adding custom properties in pure QML. Is this possible using QML?
Is this possible using QML?
No.
There is an alternative, easy and clean way to this in QML - just use an adapter object that implements the desired properties. Then instead of attaching just nest into the adapter - use it as as a parent / container. You can also nest objects into the adapter, getting another C++ exclusive - grouped properties. A possible way to minimize the overhead of this is to use JS objects and properties, with a downside - no change notifications, which you can somewhat mitigate by emitting manually.
An example:
// Adapter.qml - interface with attached properties
Item {
id: adapter
property int customInt : Math.random() * 1000
property var group : {"a" : Math.random(), "b" : Math.random() }
default property Component delegate
width: childrenRect.width
height: childrenRect.height
Component.onCompleted: delegate.createObject(adapter)
}
// usage
ListView {
width: 100
height: 300
model: 5
delegate: Adapter {
Row {
spacing: 10
Text { text: index }
Text { text: customInt }
Text { text: group.a }
Text { text: group.a }
}
}
}
It is fairly painless and convenient compared to some other QML workarounds. You don't even have to do parent.parent.customInt - the properties are directly accessible as if they are attached, this works because of dynamic scoping. The default property allows to avoid setting the inner delegate as a property you just nest the delegate you want directly in the adapter.
In many cases those acrobatics are overkill, you can just wrap in place:
ListView {
width: 100
height: 300
model: 5
delegate: Item {
width: childrenRect.width
height: childrenRect.height
property string custom1: "another"
property string custom2: "set of"
property string custom3: "properties"
Row {
spacing: 10
Text { text: index }
Text { text: custom1 }
Text { text: custom2 }
Text { text: custom3 }
}
}
}
The only key part really is the binding for the size of the adapter object so that the view can properly layout the objects. I routinely use a Wrap element which essentially does the same but is implemented in C++, which is much more efficient than a QML binding.

Bidirectional Binding of mutually dependent Properties in QML

While learning QML I stumbled over the problem, that I have to properties that are mutually dependent.
E.g. the user may set a value with a slider, or enter it with a textinput.
While moving the slider, the text in the textinput should be updated while when entering a value in the textinput, the sliders position needs to be adjusted.
Now I have the two properties: the x-value of the slider, and the text in the textinput. I need to convert them into the same format (for example: percent), and update them vice versa.
Setting up two bindings would result in a binding loop, which is probably not a good thing to have.
I think, this is a very common problem, so I am sure there is some "gold standard" to solve it. However I can't find a suitable solution.
The only way that comes to my mind, is not to use bindings at all, but handling the signals, that one of the values has changed manually (if I can't overwrite the setter in C++).
Is that all you can do?
Good day to you!
-m-
EDIT:
I now tried it with conditionally binding the value of the slider to the percentage value.
The object handle is the marker on the slider, handleArea is the MouseArea attached to it, that allows the dragging.
Binding {
target: root
property: 'percent'
value: handle.x / handleBar.width
when: handleArea.drag.active
}
Binding {
target: handle
property: 'x'
value: root.percent * handleBar.width
when: !handleArea.drag.active
}
It works. But is it a good style?
I would make one property that will store the mutual value. When user inputs text or moves slider they will use a function to update the mutual value. They will also listen to the value change and adjust their value to it.
Here is working example
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
id: window
visible: true
width: 400
height: 80
title: "Mutual value test"
property double mutualValue: 0
function setMutualValue(value)
{
if (typeof(value) === "string")
{
value = value.replace(",", ".");
value = parseFloat(value)
}
mutualValue = value
}
TextInput {
width: 200
height: 40
validator: DoubleValidator {}
onEditingFinished:
{
focus = false
setMutualValue(text)
}
onFocusChanged:
{
if (text === inputHelp && focus)
text = ""
}
property alias mutualValue: window.mutualValue
onMutualValueChanged: setValue(mutualValue)
property string inputHelp
color: (text === inputHelp && !focus ? "grey" : "black")
function setValue(mutualValue)
{
inputHelp = mutualValue.toFixed(3)
text = inputHelp
}
}
Slider {
x: 200
width: 200
height: 40
onValueChanged: setMutualValue(value)
property alias mutualValue: window.mutualValue
onMutualValueChanged: setValue(mutualValue)
function setValue(mutualValue)
{
value = mutualValue
}
}
Text {
x: (parent.width - width) / 2
y: 40 + (40 - height) / 2
text: "Current value is: " + (window.mutualValue * 100).toFixed(2) + "%"
}
}

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.

Resources