PDA

View Full Version : MousePressEvent on Widget stops event propagation



superpacko
6th July 2011, 21:48
Hi,
I have built a custom combo box, its basically a Widget with 2 buttons. Clicking on any of them displays another widget below them, showing the combo.
This combo displays the items with a Tree View, This is used to display an AddressBar, where the main/root items are the names of the contacts and the subitems (childs) are the several emails of each person.

The thing is that in order to simulate the QComboBox behaviour, the combo must disappear when the user clicks outside or when clicking on the buttons again.

For the combo i have used a Widget as a wrapper for the TreeView, applying the Qt::Popup flag. That didnt help. Popup widgets by default get hidden when clicking outside, but in the case i click on the button, the combo was hidden and as a result of clicking outside of the view, then the click was detected on the button and the view was shown again, since it was not visible. I couldnt hide the view when clicking back on the button.

What i found out is that: when the QWidget is visible, it get the mouse press event. Checks if the event position is inside it, and if so, hides it. When the widget is hidden, then the click event is detected on the button.
So i overrided the implementation of MousePressEvent in the QWidget that wrapps the QTreeView to play a little, copying exactly what QWidget does, and i found that if i DONT hide the QWidget on the mousePressEvent, then the click is NOT detected on the button.

Is it possible that the MousePressEvent is not propagating the event when the QWidget is visible? The QWidget has no parent at all, but when hidden by the mouse click, the event is informed to the button.

Any ideas?
Thanks

wysota
7th July 2011, 01:28
The second half of your post is somewhat unclear (to many "it" in one sentence, I guess...). You want the event to be propagated or not? And in what conditions? If you override some event handler and don't call ignore() then the event is accepted and no propagation occurs. I don't know if that answers your question...

superpacko
7th July 2011, 15:06
mmm yeah i had a hard time trying to make it clear.

The thing is: if i click on the button, i want the QWidget that handles the view, NOT to be hidden because of an outside click, and handle the click event on the button.
i tried several combinations of ignore, accept. I also tried verifying the position of the click, and only hiding the QWidget if the position didnt include the view nor the button. In that case the view wasnt hidden, but the button never got the click event.

Somehow when the QWidget that is catching the mouse events on the MousePressEvent, is not hidden, the event doesnt propagate. It only escalates if i hide the widget.

Is it clearer now?
Thanks!

wysota
7th July 2011, 15:18
I'm still not clear what the problem is. Qt::Popup works in such a way that the widget gets hidden regardless where you click if you click outside the widget area and I don't think there is anything you can do about it. The event won't propagate anywhere because the popup widget doesn't have a parent. The only thing you can do is to install the event filter on the popup, detect that the click happens outside the widget area and at that moment post another event to the widget under the cursor, letting the original event close the popup.

superpacko
7th July 2011, 17:45
I created a custom QWidget, that is NOT a qt::Popup, i overrided the MousePressEvent and put the same logic that the QWidget has in that method.
The source code of the QWidget hides the widget only if the click was made outside the widget's QRect.

And it is a fact that when i click on the button , the event is first catched on the MousePressEvent of the widget. If i hide the widget in that method, then the button recieves the click event. If i DONT hide the widget, then the button doesnt get the click event.

this is the overriden method:



void PrivateView::mousePressEvent(QMouseEvent *event)
{
//LoggerManager::LogDebug("[PrivateView::mousePressEvent] press event");
event->accept();
QWidget* w;
while ((w = QApplication::activePopupWidget()) && w != this)
{
w->close();
if (QApplication::activePopupWidget() == w) // widget does not want to dissappear
{
w->hide(); // hide at least
}
}

QPoint source = mapToGlobal(event->pos());
//check if the click is outside the widget and the button
if (source.x() >= this->x()
&& source.x() <= (this->x() + this->width())
&& source.y() >= (this->y() - btnHeight)
&& source.y() <= (this->y() + this->height()) )
{
// the click was made inside the widget or inside the button
}
else
{
hide();
}

}



Added after 1 58 minutes:

So here's a slight modification. Here you'll see that im filtering the mouse press event, when the click was made inside or in the button, then we dont hide it and ignore the event. Otherwhise we hide the view and accept the event.



void PrivateView::mousePressEvent(QMouseEvent *event)
{
//LoggerManager::LogDebug("[PrivateView::mousePressEvent] press event");
QWidget* w;
while ((w = QApplication::activePopupWidget()) && w != this)
{
//LoggerManager::LogDebug("[PrivateView::mousePressEvent] hide: " + w->objectName());
w->close();
if (QApplication::activePopupWidget() == w) // widget does not want to dissappear
{
w->hide(); // hide at least
}
}

QPoint source = mapToGlobal(event->pos());
QPoint viewGlobalPoint = this->pos();//mapToGlobal(this->pos());

//check if the click is outside the widget and the button
if (source.x() >= viewGlobalPoint.x()
&& source.x() <= (viewGlobalPoint.x() + 200)
&& source.y() >= (viewGlobalPoint.y() - 25)
&& source.y() <= viewGlobalPoint.y())
{
// the click was made inside the button
event->ignore();
//hide(); --> if uncomment this, then the button recieves the click event
qDebug() << "click in the button area -> Do not hide, and ignore event";
}
else if (this->rect().contains(event->pos()))
{
// the click was made inside the widget
event->ignore();
qDebug() << "click inside view -> Do not hide, and ignore event";
}
else
{
event->accept();
hide();
emit clickOutside(source);
qDebug() << "hides the view, and accepts event";
}
}


In this case eventhough i ignore the event, the button doesnt recieve the click event. If i add the "hide()" in that block, then the button recieves the event.
Why is that happening? shouldnt the button recieve the event allways? why is the visible state of the widget interfering in the event procesing?

Thanks for your help!

superpacko
15th July 2011, 19:59
anyone? any ideas?