I have to put component X inside of a ScrollView. Component X has to handle mouse wheel event, but ScrollView handles it. So, following example (simplified) doesn't work.
How to let Rectangle's mouse area handle OnWheel event?
import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Window 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
width: 640
height: 480
ScrollView {
height: 100
width: 100
ColumnLayout{
Rectangle {
color: "red"
width: 50
height: 50
MouseArea {
anchors.fill: parent
onWheel: {
console.log("onWheel"); // it doesn't work
}
onClicked: {
console.log("onClicked"); // it works
}
}
}
}
}
}
This as actually a bug in Qt:
https://bugreports.qt.io/browse/QTBUG-38083
This is being resolved in:
https://codereview.qt-project.org/#change,82572
https://codereview.qt-project.org/#change,82576
I find a way to solve it, but I can't properly explain it. :(
This document illustrates the concept of visual parent and object parent, but it dosen't tell how they affect the event propagation.
Hope someone would give a clear explaination.
ApplicationWindow {
width: 640
height: 480
ScrollView {
id: scroll // add an id
height: 100
width: 100
ColumnLayout{
Rectangle {
id: rect // add an id
color: "red"
width: 50
height: 50
MouseArea {
parent: scroll // specify the `visual parent`
anchors.fill: rect // fill `object parent`
onWheel: {
console.log("onWheel"); // now it works
}
onClicked: {
console.log("onClicked"); // it works
}
}
}
Repeater {
model: 30
Text{ text: index }
}
}
}
}
Related
It seems should have a solution for sure.
Suppose I have a Test.qml file containing this:
import QtQuick 2.0
Rectangle {
color: "green"
Row {
id: row
spacing: 10
anchors.fill: parent
Rectangle {
color: "red";
width: 100;
height: 100;
}
Rectangle {
color: "red";
width: 100;
height: 100;
}
Rectangle {
color: "red";
width: 100;
height: 100;
}
}
}
Now suppose we want to use this Test.qml within another file like main.qml:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: window
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Test {
anchors.fill: parent;
// I want to be able to add new items (rects) to the row inside Test.qml
}
}
Now suppose we want to extend items to the row object in Test.qml, But we want to add from main.qml. How we can do that? is that even possible?
(FYI: The application of this feature would be to develop a placeholder form and fill the items in the other items so we can skip duplicate codes. )
You can do this without creating objects dynamically. You need to use a default property that is aliased to the contents of your Row. A default property means Items that get added to your object will actually be assigned to that property instead. In Test.qml, add this:
Rectangle {
color: "green"
default property alias contents: row.data
Row {
id: row
...
}
}
Now you can add other items to it from main.qml, like this:
Test {
anchors.fill: parent;
// Automatically gets added to 'row'
Rectangle {
color: "blue"
width: 100
height: 100
}
}
You can create objects dynamically:
MyRow.qml:
Row {
id: row
spacing: 10
anchors.fill: parent
Rectangle {
color: "red";
width: 100;
height: 100;
}
}
main.qml:
MyRow{
id: myRow
Component.onCompleted: Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "green"; width: 100; height: 100}', myRow)
}
I have some experience with Qt Widgets, but only recently started to use QML.
The problem I face is that I'd like some layouts defined in QML to automatically adjust to fit their contents. This works, but not dynamically, i.e. if the content changes the layout does not adapt. With the old-style (non-QML) Layout/Widget approach, this happened automatically.
Here is an example (my code looks different and consists of different files, but I pasted this MWE together to demonstrate the problem):
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.2
Window {
id: root
visible: true
width: 640
height: 480
property var nbx: 3
Column {
RowLayout {
Repeater {
model: 3
Rectangle {
width: childrenRect.width
height: childrenRect.height
color: "green"
ColumnLayout {
Rectangle {
height: 10
}
RowLayout {
Repeater {
model: root.nbx
Rectangle {
width: 20
height: 20
color: "orange"
}
}
}
}
}
}
}
Button {
text: "5 boxes"
onClicked: root.nbx= 5;
}
Button {
text: "2 boxes"
onClicked: root.nbx = 2;
}
}
}
How can I achieve the same with QML?
You can make it work by setting the implicit size of the green Rectangle to the implicit size of the child ColumnLayout. I'm not exactly sure why, it seems the childrenRect properties are not propertly updated.
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.2
Window {
id: root
visible: true
width: 640
height: 480
property var nbx: 3
ColumnLayout {
RowLayout {
Repeater {
model: 3
Rectangle {
implicitHeight: col1.implicitHeight // <--- here is the change
implicitWidth: col1.implicitWidth
color: "green"
ColumnLayout {
id: col1
Rectangle {
height: 10
}
RowLayout {
Repeater {
model: root.nbx
Rectangle {
width: 20
height: 20
color: "orange"
}
}
}
}
}
}
}
Button {
text: "5 boxes"
onClicked: root.nbx= 5;
}
Button {
text: "2 boxes"
onClicked: root.nbx = 2;
}
}
}
Suppose you have a long horizontal content, so you put it in flickable for your user to swipe through. This might be a picture or a graph or something else. When the content is swiped right so that it's left side is hidden, and you pop the page from stack, a stack animation occurs where all the content is moved right. However, the before hidden part of flickable content then slides to the right also and becomes visible until the animation is over. I want to find a way to prevent this.
Here is the picture of a red rectangle lingering, carefully captured at 25 frames per second:
Here is the minimal example code to illustrate the problem:
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
header: ToolBar {
contentHeight: toolButton.implicitHeight
ToolButton {
id: toolButton
text: "<"
onClicked: {
stackView.pop()
}
}
}
StackView {
id: stackView
initialItem: pageZero
anchors.fill: parent
}
Component {
id: pageZero
Column {
Label {
text: "Page zero"
}
Button {
text: "next"
onClicked: { stackView.push(pageOne) }
}
}
}
Component {
id: pageOne
Flickable {
height: 200
width: 200
contentHeight: 200
contentWidth: 300
Rectangle {
height: 200
width: 300
color: "red"
}
}
}
}
The question is, what handlers should i put to hide the flickable before the animation starts?
Alright, i found how, actually this solution wasn't that hard. (= What i need to do is to have my flickable hidden during the transition, and also shown after the transition has ended, so I add the two lines:
Flickable {
height: 200
width: 200
contentHeight: 200
contentWidth: 300
// watch this next line
StackView.onDeactivating: {rect.visible = false}
StackView.onActivating: {rect.visible = true}
Rectangle {
id: rect
height: 200
width: 300
color: "red"
}
}
I encountered this:
ListView {
id: listView
model: ["Lorem","Ipsum"]
delegate: Item {
height: 20
Text {
z: 2
text: modelData
anchors.fill: parent
}
Rectangle {
z: 1
color: "red"
// this does not work:
anchors.fill: parent
// this works, but I have mixed feelings about it:
// height: 20; width: listView.width
}
}
}
So, apparently, anchors do not work in a delegate's subitem (in this case, Rectangle is not displayed at all). I would like to understand the mechanism behind this. Also, I'd like to ask what is the preferred way to deal with this situation?
Thank You!
Item has an implicitWidth and implicitHeight of zero, so making your Rectangle and Text fill it will result in them having no size as well.
There are two things wrong with your code:
The ListView has no width or height specified.
Your delegate has no width specified.
Here's one way of doing it correctly:
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
width: 300
height: 300
visible: true
ListView {
id: listView
anchors.fill: parent
model: ["Lorem","Ipsum"]
delegate: Item {
width: listView.width
height: textItem.implicitHeight
Text {
id: textItem
z: 2
text: modelData
width: parent.width
}
Rectangle {
z: 1
color: "red"
anchors.fill: parent
}
}
}
}
The documentation of ListView has more information.
I may need to read or write to some of the properties of the Loader's sourceComponent from some outside function.
What is the way to access the property x of the object inside this Loader's sourceComponent?
import QtQuick 2.0
Item {
width: 200; height: 200
Loader {
anchors.fill: parent
sourceComponent: rect
}
Component {
id: rect
Rectangle
{
width: 50
height: 50
color: "red"
property int x
}
}
}
When you need to expose an inner object/property to the outside, you should create an alias to it.
import QtQuick 2.0
Item {
width: 200; height: 200
property alias loaderItem: loader.item
Loader {
id: loader
anchors.fill: parent
sourceComponent: rect
}
Component {
id: rect
Rectangle
{
width: 50
height: 50
color: "red"
property int x
}
}
}