Getting a mouse drop event in Qt 5 if mouse doesn't move before mouse release - qt

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

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...)

Related

Mouse button status

From what I see, QApplication::mouseButtons() may return no buttons even when a button is held down. This happens when you have clicked a side of a window for re-sizing. It's coherent with the docs because mouseButtons() reflects the state from the flow of QEvent::mouseButtonPress, etc. However, I need just to know if the button is held down. Does any one know if it's possible through the Qt API?
I think it's not possible. Mouse events outside an application's window are not passed to its event handlers. Dragging mouse borders is one of such events, it's processed by the window system. Another example is clicking on other windows. Usually an application doesn't know what the user does with other windows. You need to install system-wide event listener or use native API features(e.g. GetAsyncKeyState on Windows) to determine that. This behavior is unusual and possibly dangerous. In most cases it's not useful, and it seems that Qt doesn't have this ability.

QMainWindow that ignore clicks, passes them on to background windows

I'd like to create a semi-transparent information window that doesn't get in the way of the user's other activities. Any clicks on the window should just pass through as if the window wasn't there.
How would you recommend implementing such behavior? Is there an easy way to do it or do I have to follow a clumsy workaround? I'm thinking of hiding the window, re-executing the click, then making the window visible again. But this would still screw up drag'n'drop gestures.
Take a look at an enum value of Qt::WidgetAttribute: Qt::WA_TransparentForMouseEvents:
When enabled, this attribute disables the delivery of mouse events to
the widget and its children. Mouse events are delivered to other
widgets as if the widget and its children were not present in the
widget hierarchy; mouse clicks and other events effectively "pass
through" them. This attribute is disabled by default.
I did a little more research into "mouse event transparency" (didn't know the exact terminology) and I found this.
I don't think there is a general and easy approach to your problem. You will probably have to dig into the native API. Once events reach an application they are not forwarded to other applications on their own.
What do you guys think? Am I doomed to work with the native APIs of each OS?

How do you register an event listener to the appear/disappear events of the virtual keyboard on Blackberry Playbook using Flex?

Not why no one has been complaining about this but I'm have a lot of problems with the Blackberry Playbook Virtual Keyboard on the Simulator.
I have an richedit component in the middle of the screen and as soon as the virtual keyboard appears to enter text, it completely hides the text input. I'd like to move the text input up when the keyboard appears/disappears. Is there any way to do this? I don't want to muck around with the focus_in and focus_out events on the richedit. I've tried, and it's not very reliable.
Thank you in advance!
We expect the next release of the SDK (long overdue at this point but, I think, imminent) to provide much more complete support for the virtual keyboard. Until that occurs, I think it's a waste of time to attempt to do anything special with it.
I also think there's a chance it will automagically move your whole stage up when it would cover up a text input, so maybe you won't have to do anything about it anyway.
Edit: Actually I published code in January describing an undocumented way to support this, using some rudimentary PPS support. It also shows how you can programmatically control the keyboard opening and closing. I don't recommend it yet for real code...

Force immediate paint in JavaFX

Is there a way to force a JavaFX app to repaint itself before proceeding? Similar to a Swing Panel's paint(Graphic g) method (I might be getting the keywords wrong there).
Consider the following example: you write a TicTacToe app along with the AI required for a computer player. You would like the ability to show two computer players duke it out. Maybe you put in a two second pause between computer turns to give it a life-like affect. When you hit your "Go" button, there's a large pause of unresponsiveness (the time it takes for the 9 turns to go by with faked pauses for the computer to 'decide') and then suddenly the app's visual is updated in with the completed game's state.
It seems like JavaFX repaints once processing in the app's thread is finished? I'm not completely sure here.
Thanks!
You are right. JavaFX is event-driven and single-threaded. This means that repaint and event response can not be done simultaneously. Long-running task should be executed on separate thread so they do not block the rendering of the UI, When the task is finished it can sync back to the FX thread by calling FX.deferAction() which will simply execute the code on the main thread.
This won't be the most helpful answer as I have toyed around with JavaFX for all of half a day, but wouldn't you use Timelines, Keyframes, and binding to accomplish your repaints instead of calling them explicitly like you have described?
See this tutorial for an example.
JavaFX's model is to separate you from the painting of the "stuff" on the screen. This is very powerful but is a change from how you might be familiar with.
whaley is correct that the appropriate way of doing this in JavaFX is to make a timeline where the move is done every X seconds and will be drawn at that keyframe.
If you have a question about how to do this, try it and make a new question with some code.

Flex Post Event Screen Updates

I came across this topic today while investigating something very strange. Doing certain things in our Flex app can cause the number of frames rendered to rocket, from 12fps to ~30fps: loaded animations start playing at high speed and the GUI starts to lock up.
Since everything I've read on Flex/Flash hammers home the point "the frame rate is capped at the fps set in the top level app", it seems the only way these extra renders can be happening is due to some events causing them (no programmatic changes to the stage's framerate are done anywhere). Since it only happens when I put my update logic in the ENTER_FRAME handler, I'm trying to figure out what might be happening which to apparently causing Flex to go render-crazy.
Hypothesis: something in my update function is triggering an immediate screen update, this raises another ENTER_FRAME immediately, which means my update loop gets called, which triggers another immediate screen update, ...
We have Flex components used in our GUI, if this is a factor. I don't really know where to go next on this.
Clarifications:
When I say things speed up, there
are two ways this manifests.
Firstly, my ENTER_FRAME handler gets
called far more often.
Secondly, a
loaded Flash SWF with a looping
animation built in suddenly speeds
up to te point it looks silly.
I am not using updateAfterEvent, I only
found this existed when researching
this problem. Apparently, some
events on Sprite subclasses
automatically call this and I wonder
if that's the root cause.
I am not doing any direct messsing about with rendering at all. Background animations play automatically as they have timelines built-in from CS3 authoring, all our update function does is change the position of DisPlayObjects or add/remove them etc
Update:
I added a label to my app to print out stage.frameRate, and discovered at certain times, it suddenly changes from 12 to 1000 (the maximum allowed value). While it was trivial to add a line to my ENTER_FRAME handler to reset it that's hardly a big help.
Also, even doing this, the rendering is all messed up. Certain actions (like raising an Alert popup) make it all spring back into life.
Unfortunately, I am not able to view the source of the Stage class to set a breakpoint on the setter property.
That's very interesting about the Flex loading 'set to 1000fps' thing. What we have are several Flex applications which all provide a common interface. A master app is in charge of loading these modules as required through the SWFLoader class. However, the loading process already takes into account the delayed loading... when the SWF loads we then wait for the APPLICATION_COMPLETE from the SystemManager. Once this is received, shouldn't the applications completion have occurred?
Flex sets the frame rate to 1000 during "phased instantiation" of Flex components, which occurs only during initial load of a flex swf. This allows it to build all components very quickly.
Are you waiting for the Flex app to be fully loaded and constructed? You should be waiting for FlexEvent.CREATION_COMPLETE before working with your Flex content.
If you would like a reference to where this occcurs, look in the Flex LayoutManager class, line 326 (using Flex SDK 3.0.194161), in the setter for the property usePhasedInstantiation.
Update:
APPLICATION_COMPLETE should have you covered for the initial load.
This actually happens any time components are created directly from MXML. So there are a few other cases to look for. Are you using any Repeaters? Do you use any navigation containers that are building their children on demand?
One thing I'm not clear on - are you seeing that the actual screen refreshes are occurring faster than the published framerate? Or is it that your animations are moving faster but the screen refreshes are unchanged? (i.e., it used to move 10 pixels per second, but now it moves faster than that, regardless of how often the screen is drawn.)
An easy way to check this would be to try publishing your content at 1 fps. It should be clear whether the screen is redrawing once per second, but animated elements are being moved more frequently than that, or whether the screen is actually updating more frequently.
If the latter, are you using any updateAfterEvent() methods in your code? This can cause actual screen refreshes to occur faster than the published framerate. It shouldn't affect ENTER_FRAME events though. You should still only get one of those per frame update.
Alternately, are the things you're animating just Sprites and so on, or are you implementing them as Flex components, and trying to redraw them with invalidate() methods and RENDER events and so on?
If you could clarify a few of these points in the question the answer might be clearer. Thanks...
Thanks for the clarifications. If a loaded clip with a animation (I assume you mean a frame animation) is speeding up, then that certainly sounds like something is changing your playback framerate, as opposed to other things that could be going on. With that said it's not a problem I've seen crop up before, but I do think there are some things you could try that ought to narrow down where the problem is:
You might as well try tracing out stage.frameRate during the speed-up. Presumably nothing ought to be changing your framerate, but since that would explain your issues you might as well rule it out.
Try removing as many GUI components as possible and seeing if the problem still occurs, if it's possible to trigger the problem without them.
One sanity check you could try, if it's feasible, is to copy some of the contents of your game into a fresh project and try it there. Sometimes mysterious issues like this happen because some class or SWC is being imported somewhere that everyone forgot about.
You could try driving your code from a different event. For example, as far as I know driving it from Event.EXIT_FRAME or Event.FRAME_CONSTRUCTED ought to look the same, but if it doesn't then that's a hint. Alternately, you could try driving it from something like a keyboard event or MouseEvent.MOUSE_MOVE. Then if updates occur even though you're not firing events, you'll know something else is driving things besides your event loop.
Those are the things I'd try, anyway. Hope you track it down...

Resources