QML using Repeater and Delegate, old list is shown - qt

I am using Repeater and Delegate to display a list, it all works fine but when i clean the model the GUI does not clean it, still old list is shown. I pass the model from cpp connector to qml.
I have tried update(), repaint() but no avail.
Any leads would be helpful.
Cpp code:
void ModelCpp::clearMessage() {
qDeleteAll(messageList);
messageList.clear();
emit messageListUpdated();
}
QML
ColumnLayout {
spacing: 1
Repeater{
model: modelCpp.messageList
delegate: Rectangle {
visible: true
color: colorBoxShader
Layout.preferredWidth: 100
Layout.preferredHeight: 20
RowLayout{
anchors.fill: parent
Text {
text: modelData.label
Layout.alignment: Qt.AlignLeft
Layout.leftMargin: layoutLeftMargin
color: "white"
font.bold: true
...
```
Edit:
I narrowed down to QStackedWidget, I am using QStackedWidget to load different pages. It was clear on one screen but now I noticed it is happening on all screen. Until the qml page is not current page, it is not updated and has old value. How can I rerender page in background when it is not current page.

I figured out the issue. With QStackedWidget only the visible page is updated/repainted but not the invisible page. When the invisible page becomes visible it is painted and you will see old values briefly before new values are painted. Create new QQuickWidget each time and add it to QStackedWidget.

Related

QML - How to drag a ToolButton?

The QT documentation has this tutorial.
I initially followed it exactly, and it works. I then made two modifications:
I replaced the ListView with a GridView (that works without #2).
I attempted to add a ToolButton to my delegate inside the Rectangle "content" like so:
Rectangle {
id: content
ToolButton {
id: toolButton
icon.color = "transparent"
icon.source = "image://Loader/iconName"
}
Drag.active: dragArea.held
Drag.source: dragArea
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
}
This does not work, the ToolButton appears to be processing the mouse movements and not propagating the messages (I can click the button, but I can not drag it)? This is actually somewhat expected to be honest.
So that said, does anyone have a good way of dragging ToolButtons around? Or is it just accepted that you can't do that? I have tried various combinations of Rectangles and MouseAreas but I can't seem to do one without breaking the other (ie either the drag fails or the button fails).
You can move the MouseArea as a child of the ToolButton to manage the drag with pressAndHold, and propagate the click to keep the button behavior:
Rectangle {
id: content
ToolButton {
id: toolButton
// bind the visual state of the button to the MouseArea
background: Rectangle {
color: marea.pressed
? Qt.darker("blue")
: marea.containsMouse
? Qt.lighter("blue")
: "blue" // use your desired colors
}
MouseArea {
id: marea
property bool held: false
drag.target: held ? content : undefined
drag.axis: Drag.YAxis
anchors.fill: parent
hoverEnabled: true
onPressAndHold: held = true
onReleased: held = false
onClicked: toolButton.clicked() // propagate clicked event to the ToolButton
}
}
// ...
}

QML ListView greys out or removes text of element when adjacent element is selected

So in testing my program, I discovered the strangest thing.
So, I have a ListView element with a custom C++ model, and a fairly simple delegate. Each delegate is a MyButton class, which is simply a Text class(z:2), an Image class(z:1), and a MouseArea class. That Image class is the background, and contains a translucent image which becomes opaque when MouseArea is onPressed().
Now the strange part.
When the ListView has 4 elements, it operates normally -except- when the user selects entry #3, then entry #2 or #1.
When the selected entry goes from #3->#1, the text in entry #2 grays out as opposed to its normal white.
When the selected entry goes from #3->#2, the text in entry #2 completely disappears.
After hours of testing and banging head against desk, I've uncovered a bit more:
The opacity of MyButton or any of its children never changes.
The color of MyButton's text element never changes
The content of MyButton's test element never changes
After offsetting the text partially outside of MyButton, this abnormal behavior only affects the text remaining inside the bounds of MyButton's Image child.
The Z level of MyButton or any of its children never changes, though it appears as if MyButton's Image is being placed on top of its Text.
Another image is never placed on top of a MyButton element. If this was the case, when going from #3->#1 you would see the image of entry #2 become darker.
When the ListView is scrolled, everything returns to normal.
When ListView contains 4 elements, below are the abnormalities:
when #4->#1: #2 and #3 gray out
when #4->#2: #2 disappears
when #4->#3: #3 disappears
when #3->#2: #2 disappears
when #3->#1: #2 grays out
This is consistent to the image and text inside the MyButton class being re-ordered, placing the image a Z level above the text. However the z levels are forced in the MyButton definition, and an onZChanged signal is never created when these events happen.
Below is the relevant code:
//MyButton:
import QtQuick 2.0
Item {
id: button
property string source: ""
property string source_toggled: source
property string button_text_alias: ""
signal pressed
width: button_image.sourceSize.width
height: button_image.sourceSize.height
property bool toggled: false
Image{
id: button_image
z: 1
source: toggled ? parent.source_toggled : parent.source
}
MyText{
z: 2
text_alias: button_text_alias
anchors.centerIn: parent
}
MouseArea {
id: button_mouse
anchors.fill: parent
onPressed: button.pressed()
}
}
//ListView:
Component{
id: p_button
MyButton{
source: picture_path + "bar.png"
source_toggled: picture_path + "bar_selected.png"
toggled: model.isCurrent
onClicked: {
profile_model.setCurrent(model.index)
}
button_text_alias: model.display
}
}
ListView{
id: p_list
width: 623
height: count*74 -1
spacing: 1
interactive: false
model: p_model
delegate: p_button
}
I can't think of -anything- that could cause this behavior.. any ideas?
I was able to solve this error by breaking up my delegate into:
Component{
id: p_button
Item{
property bool toggled: model.isCurrent
width: button_image.sourceSize.width
height: button_image.sourceSize.height
Image{
id: button_image
visible: !toggled
source: picture_path + "bar.png"
}
Image{
visible: toggled
source: picture_path + "bar_selected.png"
}
MouseArea{
anchors.fill: parent
onClicked: p_model.setCurrent(model.index)
}
MyText{
text_alias: model.display
anchors.centerIn: parent
}
}
}
So instead of swapping the source of an object, there are two objects which become visible/invisible based on a boolean value. This prevented the issue, though I still don't know the cause.

QML: referencing root window by parent reference is unreliable

Qt/QML question. Using Qt 5.7.
Take the following simple QML program that displays a red rectangle and a blue rectangle aligned vertically. Click handlers for both rectangles attempt to change the color of the parent host window. But with a subtle difference. The red rectangle references the host window directly by it's id (rootWindow). The blue click handler changes color via a parent reference.
The former case works fine. The latter case does not work. It seems like the root window is treated specially and isn't directly part of the parent/child hierarchy, even if the Rectangles are logically nested in the code that way.
Can someone explain the rule around this?
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
id: rootWindow
color: "#ffffee"
Rectangle {
id: rect1; width: 50; height: 50; color:"red"
MouseArea {
anchors.fill: parent;
onClicked: {
print("rect1 clicked");
rootWindow.color = "green"; // works fine
}
}
}
Rectangle {
id: rect2; width: 50; height: 50; color:"blue"
anchors.top: rect1.bottom
MouseArea {
anchors.fill: parent;
onClicked: {
print("rect2 clicked");
rect2.parent.color = "pink"; // does not work
}
}
}
}
If you add the following line to the onClicked handler, you'll see that its parent isn't the Window:
print(rect2.parent)
Output:
qml: QQuickRootItem(0x18b18147bc0)
This is explained not-so-visibly in the documentation for Window:
If you assign an Item to the data list, it becomes a child of the Window's contentItem, so that it appears inside the window. The item's parent will be the window's contentItem, which is the root of the Item ownership tree within that Window.
The window itself isn't an item, so it uses contentItem instead so that child items can have a parent.
However, in Qt 5.7, Window got an attached property that can be used to access the window of an item:
rect2.Window.window.color = "pink";
Whichever item comes before the Window.window part will be the item that the attached property is used on. You could use it on any item in this scene (e.g. the MouseArea), as they all belong to the same window.
Note that attached properties create a QObject-derived object for each unique item they're used on, so be mindful of how you use them, especially in items that are created in very large numbers.

Get MouseEvents while MousePressed

I have several QML Items that all have Mouse Areas.
What I want to achieve is:
Click one of the items and start tracking the mouse
Add every other Item that the mouse enters into a list
End the tracking once the mouse is released
Sample Code:
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
visible: true
width:500; height: 200;
Rectangle{
anchors.left: parent.left
color: 'red'
width: 200; height: 200;
MouseArea {
anchors.fill: parent
hoverEnabled: true
onReleased: console.log('onReleased red')
onEntered: console.log('onEntered red')
onPressed: {
console.log('onPressed red')
mouse.accepted = false
}
}
}
Rectangle{
anchors.right: parent.right
color: 'blue'
width: 200; height: 200;
MouseArea {
anchors.fill: parent
hoverEnabled: true
onReleased: console.log('onReleased blue')
onEntered: console.log('onEntered blue')
onPressed: console.log('onPressed blue')
}
}
}
Expected behaviour:
Click one Rectangle
Get on entered event if I enter the other element
Get the Released event
The sample code has both Version I tried, with and without accepting the mousePressed event.
What happens is:
If I press the mouse over one rectangle I do not get the onEnter event for all my other rectangles.
If I do not accept the onPressed event, I get the onEnter Events but not the onReleased event.
Note:
I already found this Answer which uses a DropArea as workaround which is not what I want to use if there is any other solution.
Even though the Example may look like Drag&Drop it is not what I want.
Please see the "What I want to achieve" at the top of this Question.
You will not be able to achieve what you want just using standart MouseArea components. Standart QML components are kinda limited in their functionality.
What you have to do is to create your own MouseArea component through QML extension.
In our project we also encountered lots of problems with mouse handling, so how we managed to do it was:
Subclassed QQuickItem, and inside of this class we just tracked the mouse movement, and mouse buttons states. One important thing wass to install EventFilters defined by this class.
In QML, created a Simple Component that Checks if mouse is inside of currrent component.
If you need, i could post also a code here so you have an idea.
The implementation is not the prettiest, but it works

Qt QML TextEdit component do no get a slidebar when the text is to large to fit

SDK: Qt Creator 2.4.1
Target: Nokia N9 and Windows 7
If I do the following in a qml file
import QtQuick 1.1
import com.nokia.meego 1.0
Page {
id: myShowChangeLogPage
TextEdit {
id: changeLogArea
anchors.top: titleBackground.bottom
width: parent.width
height: 300
text: "1\n1\n1\n1\n2\n1\n1\n1\n1\n1\n3\n1\n1\n1\n4\n1\n1\n1\n1\n5\n1\n1\n1\n6\n1\n1\n1\n7\n1\n1\n1\n8\n\n\n\n\n9"
font.pixelSize: 20
textFormat: TextEdit.AutoText
readOnly: true
wrapMode: TextEdit.WordWrap
}
}
The TextEdit area do not behave as I expected.
The String will be printed outside the size of the TextEdit area, that is,
it continues beneath the bottom screen edge.
There is no scrollbar/slider to the right
I was expecting that the the TextEdit element should automatically create a
scrollbar/slider if the string is to large to fit within the boundaries.
I have been told that TextEdit should do this and there is no need for a Flicker
or ScrollArea.
I have tried other type of components such as Text and TextEdit and also encapsulate
the TextEdit in a rectangle without any luck.
Regards
I read this right at the beginning of the documentation regarding the TextEdit element:
Note that the TextEdit does not implement scrolling, following the
cursor, or other behaviors specific to a look-and-feel.
There is also a complete example of how to implement scrolling for following the cursor.
TextEdit in qml doesn't implement scrolling. You must to use another one, such as TextArea (https://doc.qt.io/qt-5/qml-qtquick-controls2-textarea.html), then place it inside a ScrollView. Here's an example:
// Creating a scrollable TextEdit
ScrollView {
id: view
anchors.fill: parent
TextArea {
text: "TextArea\n...\n...\n...\n...\n...\n...\n"
}
}

Resources