5
votes

Something seems to have changed in Qt 5: you can't get a drop or move event if you don't move at least one pixel from the start point where you were when QDrag::exec() was called. Try putting a breakpoint in the dropEvent of the Draggable Icons Sample, then click a boat and release it without moving the mouse. That generates an "ignore" without any drop signal.

(This is on Kubuntu 13.10 with Qt 5.1.)

When teaching how to start a drag operation, the documentation suggests you might use manhattanDistance() to determine if the mouse has moved enough to really qualify as "the user intending to start a drag". But you don't have to use that; you can start up a QDrag on the click itself.

Anyone know of a workaround to have that same kind of choice on the drop side, or is that choice gone completely? :-/


Why I care: I've long had frustrations trying to get a tight control on mouse behavior in GUI apps—Qt included. There seems to be no trustworthy state transition diagram you can draw of the invariants. It's a house of cards you can disprove very easily with simple tests like:

virtual void enterEvent(QEvent * event) {
    Q_ASSERT(!_entered);
    _entered = true;
}

virtual void leaveEvent(QEvent * event) {
    Q_ASSERT(_entered);
    _entered = false;
}

This breaks all kinds of ways, and how it breaks depends on the platform. (For the moment I'll talk about Kubuntu 13.10 with Qt 5.1.) If you press the mouse button and drag out of the widget, you'll receive a leaveEvent when you cross the boundary...and then another leaveEvent when the button is released. If you leave the window and activate another app in a window on screen and then click inside the widget to reactivate the Qt app, you'll get two consecutive enterEvents.

Repeat this pattern for every mouse event, and try and get a solid hold on the invariants...good luck! Nailing these down into a bulletproof app that "knows" it's state and doesn't fall apart (especially in the face of wild clicking and alt-Tabbing) is a bit of a lost cause.

This isn't good if your program does allocations and has heavy processing, and doesn't want to do a lot of sweeping under the rug (e.g. "Oh, I was doing some processing in response to being entered... but I just got entered again without a leave. Hm, I guess that happens! Throw the current calculations away and start again...")

In the past what I've done is to handle all my mouse operations (even simple clicking) with drag & drop. Getting the OS drag & drop facility involved in the operation tended to produce a more robust experience. I can only presume this is because the testers actually had to consider things like task switching with alt-Tab, etc. and not cause multiple drop operations or just forget that an operation had been started.

But the "baked in at a level deeper than the framework" aspect actually makes this one-pixel-move requirement impossible to change. I tried to hack around it by setting a timer event, then faking a QMouseEvent to bump the cursor to a new position once the drag was in effect. However, I surmise that the drag and drop is hooked in at the platform level, and doesn't consult the ordinary Qt event queue: src/plugins/platforms/xcb/qxcbdrag.cpp

1
Since no one seems to know a workaround yet, I've opened an issue in the Qt tracker about this.HostileFork says dont trust SE
I had the same problem and I`ve workarrounded it with calling system api methods of simulating mouse move when the drag is starteddvvrd
@dvvrd I've opened a bounty. If you could share your code, that sounds like a good candidate for getting it... !HostileFork says dont trust SE
Seems that your bug was finally noticed and will be soon fixed. So now I must ask if you really need that code, moreover my workaround is a very dirty and ugly hack and I feel a bit shame to put it here :) The idea is just to simulate some mouse events on drag start (with QTest or even native system API).dvvrd

1 Answers

0
votes

The issue has--as of 1-May-2014--been acknowledged as a bug by the Qt team:

https://bugreports.qt-project.org/browse/QTBUG-34331

It seems that me bountying it here finally brought it to their attention, though it did not generate any SO answers I could accept to finalize the issue. So I'm writing and accepting my own. Good work, me. (?) Sorry for not having a better answer. :-/

There is another unfortunate side effect of the Qt5 change, pointed out by a "Dmitry Mordvinov":

Same problem here. Additionally app events are not handled till the first mouse event after drag started and this is really nasty bug. For example all app animations are suspended during that moment or application hangs up when you try to drag with touch monitor.

@dvvrd had to work around it, but felt the workaround was too ugly to share. So it seems that if you're affected by the problem, the right thing to do is go weigh in...and add your voice to the issue tracker to perhaps raise the priority of a solution.

(Or even better: patch it and submit the patch. 'tis open source, after all...)