QML: Canvas like a view - qt

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

Related

Wrong filling order when loading ListView elements with Loader

I'm using a Loader in a ListView delegate to increase the performance when loading expensive delegate models.
My code looks like this:
delegate: Component {
Loader {
asynchronous: true
sourceComponent: MyDelegateComponent {}
}
}
The model comes from C++ (QAbstractListModel implementation).
The problem is that the filling order of the list is wrong. It comes from bottom to top, creating a strange view for the user, who needs to wait to see the first list element.
Is it possible to change this filling order to load top element first? The model in the C++ data is well ordered.

Qt Quick Controls 2: Retrieve standard value of a component

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
}

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.

How do I create a QtWidgets ListView equivalent in Qt Quick Controls?

This question is a little specific, but I've been unable to find someone with the same problem or a clean solution to the problem.
I'm creating a Qt Quick program, and I want to use a QListView as it appears in QtWidgets. This QtWidgets program has three such views, with checkable items (which is optional: not all QListViews have checkable items).
Because Qt Quick Components doesn't appear to have a QListView equivalent, I set out to make my own from existing components. And the result is ... meh. It looks like this and doesn't exactly behave in the same fashion. Clicking on the text/whitespace of an item checks the item, instead of highlighting it. And the border is just ugly, and doesn't appear in GTK-themed environments. It also doesn't obey custom desktop themes, because the background of the items will always be white.
The code for this custom component is fairly brief, and looks like this:
import QtQuick 2.4
import QtQuick.Controls 1.3
// GroupBox creates a border... most of the time. Not in GTK envs
GroupBox {
id: root
property var model: null
// This wraps the ListView up with a scrollbar
ScrollView {
anchors.fill: parent
ListView { // This is the view component
anchors.fill: parent
model: root.model
// This is the white box that the CheckBox is drawn on
delegate: Rectangle {
width: parent.width
height: box.height
// This is the actual item
CheckBox {
id: box
anchors.fill: parent
text: thing // `thing` is just a placeholder value from the model
}
}
}
}
}
Use a QApplication instead of a QGuiApplication. It will require you to add widgets support (and ship Qt widgets libs). This way, Qt Quick Components will automatically get access to much more system theming like background color in text selection.
Additionally, SystemPalette will provide you with a bunch of native colors that you can use if you want.
Unsatisfying system integration using QGuiApplication:
Nice integration using QApplication:

ListView positionViewAtIndex() not working

I have two ListViews in a QML project that are both running off of the same model. I am trying to get them to start out at different indices (the model starts with 2 ListElements in it). In order to do this, I call positionViewAtIndex when the component completes:
ListView {
model: mymodel
Component.onCompleted: positionViewAtIndex(1,ListView.Beginning)
//...
}
However, neither ListView actually is positioned at the desired index. Is there something I'm not doing? The only solution that I have seen for this problem is to ensure that you're not calling the method before the ListView completes, but I am doing that.
I am using Qt 5.2/QtQuick 2.0.
Edit: After playing around with the other positioner functions, I have found that none of them work. I have also found that changing currentIndex does not work either. Furthermore, I have found that currentIndex is not being changed with the view -- onCurrentIndexChanged is never being fired.
So, I figured it out. It turns out that a ListView instantiates its delegates before it worries about its own properties...so the delegate was only reading off of the ListView's width before the ListView set its own dimensions. When a delegate has a width/height property in the orientation of the view equal to zero, the view will not know where to scroll to when positionViewAtIndex() is called. So, in order to fix this, you have to use a conditional binding:
Component {
id: myDelegate
Item {
width: ListView.view.width == 0 ? 480 /*or some preset*/ : ListView.view.width
}
}
This will give the delegate a nonzero width and cause the positionViewAtIndex() function to work.
Of course, if your ListView is vertical, then you need to set the height property and not the width property.
Alternatively you can set currentIndex to 1

Resources