PDA

View Full Version : Receiving QMousePressEvents above QPushButton in the parrent widget



aMan
19th September 2007, 22:17
Hi,
I'm trying to move a frameless widget with the mouse. It works well if the mouse is on a line edit or on the widget itself, but doesn't work well on a button and not at all on a deactivated button. I've attached a screenshot of the widget.

I've reimplemented mousePressEvent() and mouseMoveEvent() in the widget. The first one is for getting the mouse position (otherwise the widget would jump to the mouse position) and the second is for actually moving the widget.

I have to problems with the PushButtons:
On the activeted one I'm getting a mouseMoveEvent but not mousePressEvent. So the widget is still jumping if you grab it at a push button. I've figured out, that I can reimplement the mousePressEvent() method in the QPushButton. But then I would have to compute the position of the widget, add it to the local position and finaly send it to the parent. That's a little bit of work and I don't think it is the best way to do it.

On the deactiveted push buttons I even don't get a mouseMoveEvent. Do I realy have to reimplement the QPushButton::event() method? Shouldn't it be possible to handle these events in the parent object/widget?

marcel
19th September 2007, 22:32
Sounds like you need an event filter for the widgets.
You could install the frameless, parent widget as event filter for all its children and catch mouse events in there, but if you have a lot of widgets that won't look pretty.

Maybe you can do something with QCoreApplication::setEventFilter, but that's a bit harder to implement.

aMan
19th September 2007, 22:53
As of my understanding an eventFilter can only block events, but not redirect them. I've tried already eventFilters on the pushbuttons and the main widget in various combinations, but they didn't work as i want (probably i haven't understood them correctly). Could you kindly say exactly what i should do?

marcel
19th September 2007, 23:00
Well, not necessarily block them. Just acknowledge them. Think of it as a way for the frameless widget to know that mouse was pressed or moved somewhere inside it.
So there is no need to block them, just let them pass through, but also do something specific: move the widget.

The mouse coordinates can be extracted from the event itself, so you need only a function in the frameless widget that moves it. You can call it from the event filter for every mouse move event that you get. As for the rest, just call the base class version of eventFilter, don't interfere with the events.

aMan
19th September 2007, 23:18
BinCalc::BinCalc(QWidget *parent) {
..
pushButton_0->installEventFilter(this);
}

bool BinCalc::eventFilter(QObject* watched, QEvent* event) //BinCalc is the frameless widget
{
if(event->type()==QEvent::MouseButtonPress) {
QPoint posInPushButton=dynamic_cast<QMouseEvent*>(event)->pos();
QPoint posOfPushButton=dynamic_cast<QWidget*>(watched)->pos();
m_moveStartPos=posInPushButton+posOfPushButton;
}

return QWidget::eventFilter(watched, event);
}

This code works but is very slow (It flickers when moving. This doesn't happen when moving with the line edit.) Is there a possibility to make it faster?

edit: I've noticed, that the button isn't activated (it doesn't get the event). So it doesn't work :p
edit2: it is activated, but it has no animation :mad:

marcel
19th September 2007, 23:25
I'm not sure.
Can you post the part where you move the widget and how do you call it?

aMan
19th September 2007, 23:29
Sure

void BinCalc::mouseMoveEvent(QMouseEvent* event) {
move(event->globalX()-m_moveStartPos.x(),
event->globalY()-m_moveStartPos.y());
}

void BinCalc::mousePressEvent(QMouseEvent* event) {
m_moveStartPos = event->pos();
QWidget::mousePressEvent(event);
}

marcel
19th September 2007, 23:33
You're moving the widget for every move event.
try adding a boolean flag in your class. Set it to true when the mouse button is pressed and to false on release.

In mouse move event, move the widget only if the flag is true.



edit: I've noticed, that the button isn't activated (it doesn't get the event). So it doesn't work :p
edit2: it is activated, but it has no animation :mad:

That's not normal. It should get the events and behave normal.

aMan
19th September 2007, 23:45
You're moving the widget for every move event.
try adding a boolean flag in your class. Set it to true when the mouse button is pressed and to false on release.

In mouse move event, move the widget only if the flag is true.
Are you sure? If mouse tracking is of, mouseMoveEvent is only called if the button is pressed.

marcel
19th September 2007, 23:53
I don't trust mouse tracking :). Well of course it gets called only when the button is press, I just forget that.

Anyway, you get flicker because you m_moveStartPos is in local widget coordinates. It should also be in global coordinates.

Somewhere in the QWidget documentation it is stated that when performing moves, the passed coordinates should be global, to avoid flicker.

aMan
20th September 2007, 00:33
Thank you for you help, problem solved. I had to add the mouse move event to the filter too.



bool BinCalc::eventFilter(QObject* watched, QEvent* event)
{
if(event->type()==QEvent::MouseButtonPress) {
QPoint posInPushButton=dynamic_cast<QMouseEvent*>(event)->pos();
QPoint posOfPushButton=dynamic_cast<QWidget*>(watched)->pos();
m_moveStartPos=posInPushButton+posOfPushButton;
}
else if(event->type()==QEvent::MouseMove) {
mouseMoveEvent(dynamic_cast<QMouseEvent*>(event));
}

return QWidget::eventFilter(watched, event);
}