PDA

View Full Version : Detecting end of dialog move



darryl
8th September 2006, 16:07
Hello

I'm showing a QWidget as a dialog with a Qt::Dialog windows flag.
I need to be able to tell when I've finished moving this widget (ie. when the mouse button is released after dragging the dialog by its frame).
How can I do this?

I can't capture mouse release events triggered on the frame of the dialog, only on the widget itself.

Is there a way to globally detect whether the left mouse button is down or up, maybe?

Thanks

Darryl

wysota
8th September 2006, 17:35
How about making use of QWidget::moveEvent? You could use a timer to check if a move occured in a specified time and if not, treat it as an "end of move".

darryl
11th September 2006, 11:47
Hi Wysota

Thanks for replying. I originally thought i would do this. However, if a user still has the mouse down and pauses for a moment, I dont want the procedure to activate, only when they release the mouse button.

QT seems to have hidden all access to mouse button signals during window movement so you can't tell when such an event has occured :(

I've been trying to think of workarounds for a while now with no success.

windkracht8
11th September 2006, 12:20
Hello Darryl,

From Qt assistant:

void QWidget::moveEvent ( QMoveEvent * event ) [virtual protected]
This event handler can be reimplemented in a subclass to receive widget move events which are passed in the event parameter. When the widget receives this event, it is already at the new position.
The old position is accessible through QMoveEvent::oldPos().
See also resizeEvent(), event(), move(), and QMoveEvent.

So if you put the function "void yourWidget::moveEvent ( QMoveEvent * event )" in your dialog. It will be called when the user is finished moving the dialog.

Cheers,
Bart.

darryl
11th September 2006, 12:51
Hi Bart

This solution doesn't work for dialogs. For dockwidgets, yes, the event occurs at the end of a drag-move in the way you describe. However, for dialogs, the moveEvent is triggered at every point along its move.

You have no way of telling when the move is finished (ie. the mouse button has been released).

This difference in behaviour is shown graphically in that a drag-moved dockwidget is shown by a rubberband and only visually updated when you release the mouse button; whereas when you move a dialog, its full appearance is updated at every point along the move.

However, I need to use dialogs and not dock widgets in this case due to particular style effects which don't work for dockwidgets.

If only you could tell when a dialog drag-move was over, the implementation would be straightforward. All I need is to be able to interrogate the status of the mouse button but I can't see how to do this at all. Mouse events occuring over the frame of a window seem completely hidden.

jpn
11th September 2006, 13:03
Just curious, what does QApplication::mouseButtons() return? It may indeed be that Qt never receives title bar's mouse events (they are handled by the underlying system insted). If so, QApplication::mouseButtons() has no way of returning correct result, but it's worth try isn't it? ;)

windkracht8
11th September 2006, 13:39
This works:



void frmDialog::moveEvent(QMoveEvent * event){
this->grabMouse();
}

void frmDialog::mouseMoveEvent(QMouseEvent * event){
//move the widget your self
}

void frmDialog::mousePressEvent(QMouseEvent * event){
//remember mouse position
}

void frmDialog::mouseReleaseEvent(QMouseEvent * event){
this->releaseMouse();
}


Just don't got the code here to move the widget yourself, can look it up for you.

Cheers,
Bart.

windkracht8
11th September 2006, 13:53
This comes close:



void frmDialog::moveEvent(QMoveEvent * event){
if(!moving) this->grabMouse();
ui.label->setText("moving");
}

void frmDialog::mouseMoveEvent(QMouseEvent * event){
this->move(pos() + (event->globalPos() - position));
position = event->globalPos();
}

void frmDialog::mousePressEvent(QMouseEvent * event){
if(event->type() == QEvent::MouseButtonPress) position = event->globalPos();
}

void frmDialog::mouseReleaseEvent(QMouseEvent * event){
ui.label->setText("release");
this->releaseMouse();
moving = false;
}


Still some small bugs in there, but you get it to work. If not, you know where to ask ;).


[edit]
Small explination:
Grabbing the mouse when the dialog is moved will make Qt post the mouse events, which normally go somewhere else, to the dialog. You can then catch them to move the dialog(becausse Qt won't do it for you anymore) and know when the user stops to move it.
And then don't forget to release the mouse again, or you won't have any mouse event's in your desktop untill you kill the application(without the use of the mouse off course).

Cheers,
Bart.

wysota
11th September 2006, 14:07
When you move a window, the window manager takes complete control over it. If you don't have opaque moving enabled, you'll only receive the moveEvent after you release the mouse button. If you have opaque moving enabled, a "move" consists of many smaller moves (same with opaque resizing). You should simply react on the situation to come as close to a desired solution as possible. What is someone moves a window without holding any mouse buttons depressed? You shouldn't simply rely on mouse buttons being held (what about reversing left and right mouse buttons for lefties?).

windkracht8
11th September 2006, 14:25
When you move a window, the window manager takes complete control over it. If you don't have opaque moving enabled, you'll only receive the moveEvent after you release the mouse button. If you have opaque moving enabled, a "move" consists of many smaller moves (same with opaque resizing). You should simply react on the situation to come as close to a desired solution as possible. What is someone moves a window without holding any mouse buttons depressed? You shouldn't simply rely on mouse buttons being held (what about reversing left and right mouse buttons for lefties?).
ok.


Is there a way to globally detect whether the left mouse button is down or up, maybe?

Yes, one way is to grab the mouse.
Then you do get the mouseMoveEvent and you can check the state with:
'Qt::MouseButtons QMouseEvent::buttons ()'

Cheers,
Bart.

darryl
11th September 2006, 17:20
Thanks for your ideas Bart and wysota

The mouse grabbing idea doesn't seem to work. As far as I can tell, no mouse events can be captured when they are created over the window title bar, which is where you are dragging from. I can override mouseMoveEvent and set break points but the function is never called. Even if you setMouseTracking, or use grabMouse. mouseMoveEvents seem only ever to be emitted when you are moving over the main area of the widget and not its frame.

I would be interested in adjusting the opaque moving settings but they appear only to be accessible on QT3 classes and we use QT4 here.

Darryl

wysota
11th September 2006, 17:50
I would be interested in adjusting the opaque moving settings but they appear only to be accessible on QT3 classes and we use QT4 here.
It is all the window manager's responsibility. What exactly are you trying to achieve? Maybe there is a better/easier way of doing it?

windkracht8
12th September 2006, 09:16
This works on WinXP/ Qt4.1. But only the first move.

Cheers,
Bart.

darryl
12th September 2006, 09:21
Hope so

I need to implement a system for docking windows manually because:

1) The style of the floating dockable window must be like a dialog because of the clients wishes. This shows a shadowed effect when viewed infront of other windows on a mac.

2) My floating docked window contains two horizontal rows of icons. When docked against the sides it converts to a single vertical long row of icons. When approaching the sides, the rubber band that appears is the width of the floating window ie. much too wide - so this behaviour needs to be overridden. This is difficult, again, because you cant detect when a docking event is approaching. The moveEvent you could catch only activates after you release the mouse button with docked windows - the putting up and taking down of the rubber bands is all handled under the bonnet and seems inaccessible.

Darryl

darryl
12th September 2006, 09:36
Hi Bart

Thanks for that - I also tried your code in my application and it behaved similarly. It works the first time but then it ceases to detect events over the title bar.

I couldn't think how to change it - if you can get it to work all the time it would perfectly solve my problem.

Darryl

....update

The code stopped working as it should here. Now it doesn't detect the release event even the first time. Odd - I got exactly the same thing when integrating it into my code yesterday. It worked the first time then not. :confused:

windkracht8
12th September 2006, 10:39
Works now, you can move it as you like and it will keep track.
But only the first time you start the program. Somehow we are not allowed to grab the mouse twice in one session, a reboot does the trick. A recompile does the trick. We just can not grab the mouse twice.
Bug in Qt? bug in Windows? meant to be? I don't know.

Good luck figuring that one out,
Bart.

wysota
12th September 2006, 12:04
Works now, you can move it as you like and it will keep track.
But only the first time you start the program. Somehow we are not allowed to grab the mouse twice in one session, a reboot does the trick. A recompile does the trick. We just can not grab the mouse twice.
Bug in Qt? bug in Windows? meant to be? I don't know.

Do you actually release the grab when it is not required?

windkracht8
12th September 2006, 12:19
Do you actually release the grab when it is not required?
The first version released it when the moving of the window was done.(hence it only worked the first move)
the second version releases it when closing the window.(hence it works with every move and I had to re-implement(that word is wrong in a lot of ways) all the mousebuttons actions)

But maybe in the wrong way?
'this->releaseMouse();'

Cheers,
Bart.

windkracht8
12th September 2006, 12:24
From assistant:
void QWidget::grabMouse ()
[CUT]
See also releaseMouse(), grabKeyboard(), releaseKeyboard(), and grabKeyboard().

They really, really want you to look at grabKeyboard() :)

jpn
12th September 2006, 12:37
the second version releases it when closing the window.(hence it works with every move and I had to re-implement(that word is wrong in a lot of ways) all the mousebuttons actions)
Hmm, you cannot grab the mouse like that. It would prevent you from clicking anywhere outside the dialog (or whatever has grabbed the mouse).
IMO grabbing is generally a bad idea. It is VERY error prone. There's a reasonable note about grabbing bugs in the QWidget::grabMouse() docs.

windkracht8
12th September 2006, 14:04
Yeah I know, but do you have a better idea?
You should release the grab when the move is done, like the first version. But then you still need to figure out how to grab it twice. Else it only works ones.

Cheers,
Bart.