Combobox doesn't open popup if MouseArea is above it - qt

I have a listview with a delegate that has MouseArea covering the whole of a delegate. In that MouseArea's onClick slot I specifically set
mouse.accepted = false
but the Combobox from QtQuick.Controls 1.4 that lives in that delegate still refuses to open its popup on clicks. I've tested that combobox should receive the click with:
ComboBox {
id: cbChapters
model: chapters
MouseArea {
anchors.fill: parent
onClicked: {
mouse.accepted = false
console.log("arrived")
}
}
}
And the click events do arrive into this inner mouse area, just not into the combobox itself it seems... what might be the problem?

Answering my own question:
Problem seems to be that MouseArea automatically accepts Pressed events and in the Combobox code itself there's this:
onPressed: {
if (!Settings.hasTouchScreen)
popup.toggleShow()
}
onClicked: {
if (Settings.hasTouchScreen)
popup.toggleShow()
}
So it seems like Clicked requires touchscreen to open the popup(which is not present on the desktop, obviously)
This leaves only Pressed to open the popup, but it's being suppressed at the uppermost MouseArea as it is not a composed event and propagateComposedEvents does nothing for it.
The solution could be :
1) to go through your mouse area chain and in each one of them set:
onPressed: {
mouse.accepted = false
}
2) call popup directly in "clicked" handler
ComboBox {
id: cbChapters
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onClicked: {
cbChapters.__popup.toggleShow()
}
}
}

Related

QML: monitoring mouse moving event in the "whole" window

Hmm... maybe this task should be implemented in C++? I don't know...
I'm using QML to making a media-player like (e.g. QuickTime in OSX) interface, which can detect mouse event:
When mouse idle for a period, hide all control panels and show only VideoOutput. Or as soon as mouse out of the window, do the same things immediately.
So my requirements are:
monitor mouse move event within the whole window
don't block original mouse event on any other component.
Or more precisely, see pseudo code:
MouseArea {
anchors.fill: applicationWindow // <- This is wrong and will throw error
hoverEnabled: true
/* After reading the Qt doc, this property seems should be
placed in a MouseArea, which is under another MouseArea.
When child has mouse event, it propagate up to parent MouseArea.
So this should be also wrong. */
propagateComposedEvents: true
onClicked: mouse.accepted = false;
onPressed: mouse.accepted = false;
onReleased: mouse.accepted = false;
onDoubleClicked: mouse.accepted = false;
onPressAndHold: mouse.accepted = false;
onPositionChanged: {
console.log("moved!", mouse.x, mouse.y)
mouse.accepted = false
}
}
The Problem with QML is, that there are certain Event-Chains that you can either handle or leave it.
So if you want to handle the clicked-event in one MouseArea you can't propagate the pressed-event.
This however might be a sufficient solution:
Rectangle {
width: 50
height: 50
color: 'orchid'
MouseArea {
anchors.fill: parent
drag.target: parent
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
onMouseXChanged: console.log(mouseX)
onPressed: {
mouse.accepted = false
}
}
You handle the mouse-movement in the MouseArea that lies uppon everything else, while not handling anything as long as a button is pressed.
If you need information about the MouseMovement even then, you can create a singleton signal you... ring... in every other MouseArea you use... or propagate the signals through every qml-file of yours.
So instead of writing: mouse.accepted = false in every MouseArea you write: mySingleton.mouseEventSignal(). You might even add the Item and the coordinates, so you can then map the coordinates to what ever you want...
This might be sufficient for a fast and dirty prototype. For the real thing, maybe you need to do it in C++ as Kevin Krammer proposed

How to vertical scroll to a specific item

I have a ListView including a lot of radio buttons. The list is bigger than the visible area. One of the radio buttons is checked. Sometimes, if the selected radio button is outside the visible area I want to scroll to it:
ScrollView {
anchors.fill:parent
ListView {
anchors.fill: parent
model: valuesList
delegate: RadioButton {
id: radioBtn
//check of value is index type and do the corresponding checked? test
checked: valueIsIndex ? (parseInt(valueFromParent) == index ? true : false) : (valueFromParent == valueString ? true : false)
onClicked: {
root.selected(valueString, index)
}
Component.onCompleted: {
if(checked)
//Here i want to scroll the list to display this radiobutton
}
}
}
}
Any ideas howto to get the list scrolled? I've played around a lot of with hightlights and contentY but nothing worked.
I've use the ScrollView around the ListView to automatically get the systems scrollbars on the desktop. On mobile devices i have just the flickable ListView.
EDIT
I get it on the way with the help of BaCaRoZzo. Here is my current working example:
ScrollView {
id: scrollView
anchors.fill:parent
property int yOfCheckedRadioButton: 0
ListView {
id:listView
anchors.fill: parent
spacing: Math.round(appWindow.height*0.05)
model: internalValuesList
delegate: RadioButton {
id: radioBtn
//check of value is index type and do the corresponding checked? test
checked: checktest()
style: MyRadioButtonStyle {
myRadioBtn: radioBtn
labelString: value
}
Component.onCompleted: {
//set the position of the checked RadioButton to scroll to it later onContentHeightChange
if(checked) {
var checkedRadioBtnPositionY = Math.round((radioBtn.height + listView.spacing) * index - radioBtn.height * 1.5)
if( checkedRadioBtnPositionY > 0)
scrollView.yOfCheckedRadioButton = checkedRadioBtnPositionY
else
scrollView.yOfCheckedRadioButton = 0
}
}
}
onContentHeightChanged: {
//scroll to the checked RadioButton
contentY = scrollView.yOfCheckedRadioButton
}
}
}
I recall problems with scroll before Qt 5.4 when I found a workaround like:
ScrollView {
anchors.fill: parent // mind how you stretch it
contentItem:
Flow {
id: flow
spacing: 10 // mind gaps
width: parent.parent.width - 20 // select proper width
// Put anything you would like to scroll in here
// Mind that Flow positions items one after another
// left to right, top to bottom
// You can also try containers other than Flow
// but whether it works or not may depend on Qt version
ExclusiveGroup { id: tabPositionGroup }
RadioButton {
text: "RB1"
checked: true
exclusiveGroup: tabPositionGroup
}
RadioButton {
text: "RB2"
exclusiveGroup: tabPositionGroup
}
}
}
Whether ScrollView needs an explicit contentItem or not is another matter and it certainly may not need it but that does not hurt if the SrollView needs to resolve what it actually scrolls.

How to show a context menu on right click in Qt5.5 qml TreeView

I want to show a context menu when right-clicking on Qt5.5 qml TreeView item, but it has clicked signal. How to show a context menu on right click?
TreeView {
id: tree_view
anchors.fill: parent
model: tree_model
headerVisible: false
backgroundVisible: false
TableViewColumn {
role: "display"
}
onClicked: {
console.log("clicked", index)
}
onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index)
}
It's actually quite easy, you just need a MouseArea configured to accept only right click events, and it won't interfere with the mouse handling performed by the TreeView itself:
TreeView {
id: tree_view
anchors.fill: parent
model: tree_model
TableViewColumn {
role: "display"
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
var index = parent.indexAt(mouse.x, mouse.y)
if (index.valid) {
console.log("show context menu for row: " + index.row)
}
}
}
}
Can you simply define your menu somewhere and use the popup method to show it? That method open the menu near to the mouse cursor, so to the right position.
Of course, you have to define your itemDelegate as well and let the event flows out of your item if needed (do not consume it).
The documentation for the clicked signal of a TreeView explicitly refers to the item delegate to consume those events, so I guess this is the intended approach.

QtQuick 2 Pass function to elements

I have a QML element "Button" which has a MouseArea element inside.
What I want to do is to send a function to the item and then pass it to MouseArea:
Example:
Button{
id: smth
...
...
onClicked: console.log("Someone Clicked Me!")
}
And my element could be something like this:
Rectangle{
property var onClicked
...
MouseArea{
onClicked : parent.onClicked
}
}
I found out that I can pass the function like in native js without parentheses, but I think there is a way to implement it like MouseArea element does.
The usual way to handle this situation in QML is to let the Button emit a signal, which is then handled by the user of Button.
Button.qml:
Rectangle {
id: root
signal clicked
MouseArea {
anchors.fill: parent
onClicked: root.clicked();
}
}
Usage:
Button {
onClicked: console.log("Button was clicked!");
}

QML dynamic list of widgets

I have a QStringList property, and I basically want to turn that into a group of radio buttons dynamically, so that when the QStringList property changes the number of buttons and their labels is automatically updated.
I can sort of do it with a ListView, but it has problems:
It's not really a desktop widget so you have all the mobile bounciness.
I can't get the ListView selection and the radio button checks to interact nicely.
Here's my attempt anyway. I'd ideally like to do it without a ListView though:
ListView {
id: myList
orientation: ListView.Horizontal
ExclusiveGroup {
id: myListExclusiveGroup
}
Component {
id: myDelegate
RadioButton {
text: modelData
onCheckedChanged: {
if (checked)
myList.currentIndex = index
}
exclusiveGroup: myListExclusiveGroup
}
}
model: myListOfStrings
delegate: myDelegate
focus: true
}
Thanks to koopajah, I changed it to use Repeater and it works now. Note that it seems Repeater adds everything to the end of its parent's children, which means you can't rely on its position in a layout - you have to put it inside another layout, for example like this:
ExclusiveGroup {
id: myListExclusiveGroup
}
RowLayout {
Repeater {
id: myList
RadioButton {
text: modelData
exclusiveGroup: myListExclusiveGroup
}
model: myListOfStrings
focus: true
}
}

Resources