ListView: Long press and release to initiate a grab, move mouse to scroll, then click to release
-
Hello,
I am trying to figure out how to change the way ListView responds to mouse events. I have a large, scrollable list, and I want to "long press" on the ListView widget to initiate scrolling. After the long press (and release), the list is "grabbed" and any movement of the mouse along the y-axis should result in scrolling of the List. A single click should release grabbed list.
Is this possible?
Thanks,
Matt -
I think that it is possible only by custom plugin with class inherited from listview (or maybe from flickable). Not sure, but I'll be at your place I will start from this point while solving this issue.
-
-
2beers, hm, can't find how to track mouse without buttons pressed
-
Hmm, I thought I was being clever, but this doesn't work. When I try to set grabMouse() on the ListView, the program crashes. On the MouseArea, QGraphics complains there is no scene.
@class MySystem : public QObject
{
Q_OBJECT
Q_INVOKABLE void grabMouse(QDeclarativeItem *item) { if(item) item->grabMouse(); }
};int main(void)
{
...
...
view.rootContext()->setContextProperty("mysys", new MySystem());
}QML
Item {
ListModel { id: myModel; ListElement { type: "Dog"; age: 8 } ListElement { type: "Dog"; age: 8 } }
Component { id: myDelegate; Text { text: type + ", " + age } }
ListView {
id: myList
model: myModel
delegate: myDelegate
MouseArea {
id: mymouse
anchors.fill: parent
onPressAndHold: {
// This crashes:
mysys.grabMouse(myList);// This complains: QGraphicsItem::grabMouse: cannot grab mouse without scene // mysys.grabMouse(mymouse); // This complains: QGraphicsItem::grabMouse: cannot grab mouse while invisible // mysys.grabMouse(listItem) } }
}
}
@ -
Thinking out loud here, I could create a MouseGrabArea class similar to MouseArea...
No idea if something like this would work, but will try tomorrow:
@ListView {
id: mylistMouseGrabArea { height: parent.height; width: parent.width; }
...
...
}// Psuedo code...
class MouseGrabArea : public QDeclarativeItem
{
public slot:
void onMousePress() { m_press_time = gettime(); } // Time in milliseconds
void onMouseRelease() { if(gettime() - m_press_time > 800) { this.grabMouse(); } else { this.releaseMouse(); } }
};
@ -
Hi,
Are you looking for standard "flicking" behavior after the long press, or just panning? If the latter, putting a MouseArea over the ListView, and using it to manually manipulate the ListView's position (using e.g. positionViewAtIndex, or contextX/Y) might work.
Regards,
Michael -
I solved this with a little help from C++. Using rootContext->setContextProperty(), I created a C++ class with Q_INVOKABLE methods that:
@setGrabCursor(bool doit) const
{
if(doit)
QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor));
else
QApplication::restoreOverrideCursor();
}@From my app, when I detect a long press on my ListView delegate, I call setGrabCursor(true) and make a full screen mousearea active that marks mouse events as accepted. I tie the mouse y coordinate to the listview contentY inside of a onPositionChanged() handler. On single click of the mousearea, I call setGrabCursor(false).