Qt Quick Controls 2: Retrieve standard value of a component - qt

I am making a layout in QML and I want to give my Label the same padding as an ItemDelegate.
How can I get the standard padding value of an ItemDelegate?
Thank you in advance!

Firstly, you'll need an instance of an ItemDelegate. If you don't have one, you can create one and set its visible property to false:
ItemDelegate {
id: itemDelegate
visible: false
}
Some of the built-in styles change as the design guidelines they're based on change, so it's not a good idea to hard-code the padding based on a style's current padding values unless you have control over that style.
In addition, each style sets a different default padding, and may also use different properties to do so. The following properties can be used to control padding, starting with the most general and ending with the most specific:
padding
horizontalPadding (available in Qt 5.12)
verticalPadding (available in Qt 5.12)
leftPadding
rightPadding
topPadding
bottomPadding
Because of this, the only way to guarantee that you'll get the correct padding for each side of the control is to use the most specific properties:
Label {
leftPadding: itemDelegate.leftPadding
rightPadding: itemDelegate.rightPadding
topPadding: itemDelegate.topPadding
bottomPadding: itemDelegate.bottomPadding
}

Related

QML: Canvas like a view

I have a set of rectangles provided by c++ backend, and I'd like to paint
each of them on qml side with some extra decorations, colors opacity etc (respecting rectangles' positions and sizes).
I was hoping for some special kind of view which would accept a model containing all these rectangles and then would use them in delegates to define items' positions and sizes.
The best I was able to find is 'Canvas' which I may use to fulfill my needs, but maybe there is something more suitable?
A Repeater can accept a model and instantiate your Rectangles at any size/position.
Repeater {
model: rectangleModel // Comes from C++
delegate: Rectangle {
x: model.x
y: model.y
width: model.width
height: model.height
}
}
You can try using listview delegate.
May be you can use QObjectList-based Model, as said in below link
https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html
In your c++ code expose the required data from rectangles using Q_PROPERTY

Font size when using non-Default style in Qt Quick Controls 2

When I use any method to select one of non-Default (or Base) styles in Qt Quick Controls 2 application (i.e. Universal or Material), then all the controls with text (like Label, TextField, whose font size must depend on QGuiApplication::font) uses font size value, which QCoreApplication has before changing:
QFont font = application.font();
bool ok = false;
font.setPointSize(QSettings{}.value("fontSize", 17).toInt(&ok));
Q_ASSERT(std::exchange(ok, false));
application.setFont(font);
Only Text, TextField are resized properly, but they are of no use in my GUI.
When I stick Default style, then all the mentioned items are resized properly.
How to make all the items be resized depending on global font.pointSize when used styles, other then Default?
Another connected question is how to get proper (means "contrast" and style-conformant) color for, say, highlighted text and background for the current style theme used? Using SystemPalette { id: palette } from ApplicationWindow in children gives colors suitable only for Default style (say palette.highlightedText is "white", palette.highlight is "blue" or "darkblue" (not sure)). It looks ugly in style themes, differs from Default.
Another important observation is: if I set font.pointSize: 17 (or equally font: Qt.application.font) in root ApplicationWindow, then all the items are resized properly, except of those of them which have new context: say, highlight: and delegate:s into *Views, sourceComponent:s into Loaders, default property item of Component and Repeater and others, where inheritance of the font breaks due to lost of the parent Item's context.
It seems, that I should to manually "inherit" ApplicationWindow.window.font for each new context. It is sad if so. It is boring, if e.g. in Repeater I use RowLayout with a plenty of Labels: in each of Label I have to add font: ApplicationWindow.window.font.
Orient, I know it is too late, but one can also set font size in QApplication like this:
QFont font = QApplication::font();
font.setPointSizeF(fontSize);
QApplication::setFont(font);

What is best way to load either Rectangle(drawn by code) or Image in Qml?

I have a Qml file with one 'Rectangle' and an 'Image'. I want to load either one based on the property set in my.cpp file.
Please help me to find a best way to do this.
Actually I could think two possible ways to do the same:
1) First approach is to have both the element (the image and rectangle), defined in the respective QML, and to control their visibility from my.cpp file. I can have a property, this property can control the visibility of either of the two. Drawback in this approach is that even though only one element has to be displayed, two will be created.
2) Second approach is that we can have two components and load either one using "Loader" depending on the property set from the my.cpp.
Ex:
'
Component
{
id:img
Image
{
id: myImage
source:currentdir + "/img_production/Separator/myImage.png"
width: 10
height: 79
}
}
Component
{
id:rect
Rectangle
{
id:re
height: 82
width: 10
color: "#FFFFFF"
}
}
Loader
{
id: itemDisplay
sourceComponent: style.flag? rect : img
anchors.fill: parent.fill
}
'
Looking for some expert suggestions.
PS: style.flag is property set by my.cpp to Qml.
In this case, where both items are simple base types, I would go for the visibility change.
Having both elements instantiated directly makes it easier to refer to them in bindings or bind to their properties.
It also means their allocation only happens once, reducing the chance of memory fragmentation
If you are worried about the image consuming too much memory while the rectangle is shown you could still make the image`s source property depend in the visiblity value, i.e. unload the image when not showing the Image element.

Why is a dynamically by C++ generated QML Item not aware of other pre-existing Items?

I have a QQuickView that displays a QML file which itself consists of several QML Items (in separate files). I'd like to add Items dynamically using C++ code. The dynamically added item should resize with the parent one, i.e. width and height properties reference parent.
For example, my target Item in QML looks like this:
// TargetContainer.qml
Grid {
id: fillMeWithItemsContainer
objectName: "fillMeWithItemsContainer"
}
The Item I want to add dynamically (maybe multiple times) looks like this:
// DynamicItem.qml
Rectangle {
color: "white"
height: fillMeWithItemsContainer.height
width: height * 4/3
}
Note that the rectangle references the container it is intended to reside in regarding height.
quickView is populated with TargetContainer:
QQuickView *quickView = new QQuickView();
quickView->setSource(QUrl("qrc:/foo/bar/TargetContainer.qml"));
So I load a component
QQmlComponent dynamicallyLoadedComponent(
quickView->engine(),
QUrl("qrc:/foo/bar/DynamicItem.qml")
);
And I create an Object out of it.
QObject *dynamicallyLoadedObject = dynamicallyLoadedComponent.create();
Here I get an error (in application output view):
DynamicItem.qml:4: ReferenceError: fillMeWithItemsContainer is not defined
quickView should be aware of the existence of fillMeWithItemsContainer, because it has been created before. However, fillMeWithItemsContainer is not a parent of dynamicallyLoadedObject (yet) and this could be the problem.
So I find the target Item by
QQuickItem *targetItem = quickView->rootObject()->findChild<QQuickItem*>("fillMeWithItemsContainer");
And reparent the previously created object
dynamicallyLoadedObject->setProperty("parent", QVariant::fromValue<QObject*>(targetItem ));
Note: I tried dynamicallyLoadedObject->setParent() before, but this seems to be a different kind of parent (QObject vs. parent property).
However, the width and height properties of dynamicallyLoadedObject are set to 0 (because of the reference error, I assume) and won't change. Even if I set them again programatically
dynamicallyLoadedObject->setProperty("height", "fillMeWithItemsContainer.height;");
dynamicallyLoadedObject->setProperty("width", "height * 4/3");
nothing changes.
If I define DynamicItem directly in QML it works:
Grid {
id: fillMeWithItemsContainer
objectName: "fillMeWithItemsContainer"
DynamicItem {}
}
How do I make sure that dynamically added items can access Items that have been in the QML view before? Alternatively: What am I doing wrong?
dynamicallyLoadedObject->setProperty("height", "fillMeWithItemsContainer.height;");
dynamicallyLoadedObject->setProperty("width", "height * 4/3");
This will not actually set a JavaScript binding on the properties. Instead, it will try to assign e.g. the string "fillMeWithItemsContainer.height;" to the property, which will fail since the property is of type int, not of type QString.
Assigning bindings to properties is actually not possible from within C++ (with some exceptions like QQmlBinding).
dynamicallyLoadedObject->setProperty("parent", QVariant::fromValue<QObject*>(targetItem ));
As Sergei mentioned, you need to call QQuickItem::setParentItem instead of setting the parent property. That is also a bit more typesafe than the general string-based setProperty API. Without a parent item, a QQuickItem will not be visible.
Reparenting will only change the parent item, which will affect layouting and a few other things. It will not change the context of the object. A context defines which objects/IDs are in the scope. The context can not be changed after an item has been created. Even if changing the parent would change the context, it is too late - the object has been created, and IDs/object are only looked up in the creation phase.
The solution is to pass the correct context to QQmlComponent::create(), which actually has an optional argument. You need to create your item in the context of fillMeWithItemsContainer, so you need to get a pointer to it (you did that already with findChild) and then retrieve its context, which is possible with QQmlEngine::contextForObject(). That should give you enough to figure out how to make it work.
I agree with Sergei though, you should prefer to dynamically create objects in JavaScript instead. Changing QML from within C++ is a layering violation, you should never access QML from C++, only the other way around, to have a nicer separation between UI and program logic.
I believe, QML engine treats DynamicItem instance as a non-graphical item since it is casted to QObject*. Thus it is not rendered. It has to be at least QQuickItem* to be rendered.
I believe you experience same problem with setParent() since parent property refers to parent QQuickItem and might no be the same as QObject parent.
Two questions:
Why wouldn't you create dynamic objects in JS?
Is it possible to use relative parent instead of absolute fillMeWithItemsContainer?
p.s. I assume you understand this is rather irregular way of using QML and have strong reasons for such hacky approach.

QML : If condition in delegate?

I'm designing a spinner list control, which displays 3 items at a time.
Its working fine as required behaviour the only issue am facing is I need the central element appearance little bigger.
The approach which I can think as of now is to have an if condition in the delegate, which on the basis of current index increases the font size.
Is the above approach is possible? Any suggestions to achieve the particular behaviour
Below is the code snippet
SpinnerData {
id: spinner
focus: true
model: 20
delegate: Text { font.pixelSize: spinner.height/4.5; text: index; height: spinner.height }
}
I don't know the details of your component but here you can see implementation of the same control in Qt Quick Components.

Resources