PDA

View Full Version : Popup Menu not closing after clicking custom widget



stefanadelbert
15th April 2010, 03:22
I have a QMenu that contains one QActionWidget. The QActionWidget contains a custom QWidget (CSpinBoxWidget), which comprises a QSpinBox and a custom QPushButton (CTitleButton).

When the CTitleButton is clicked I would like the QMenu to close.

I read here (http://lists.trolltech.com/qt-interest/2007-06/thread00463-0.html) that I will most likely need to do something with the handling of mouseReleaseEvent. I decided to use a QPushButton, but I did try with a QToolButton and couldn't get it working.

When the CTitleButton is clicked, CTitleButton::mouseReleaseEvent gets called. Then the event is passed to the parent of the CTitleButton, which is the CSpinBoxWidget.

Note: I tried connecting CSpinBoxWidget::titleClicked [signal] to QActionWidget::trigger [slot], but this didn't help.


class CTitleButton : public QPushButton
{
Q_OBJECT

public:
CTitleButton(QWidget* parent = 0) : QPushButton(parent) {}
void mouseReleaseEvent(QMouseEvent* event) {
QPushButton::mouseReleaseEvent(event);
QWidget::mouseReleaseEvent(event);
}
};

class CSpinBoxWidget : public QWidget
{

Q_OBJECT

public:
CSpinBoxWidget(const QString& t, QWidget* parent = 0) :
QWidget(parent)
{
value = new QSpinBox(parent);
value->setContextMenuPolicy(Qt::NoContextMenu);

title = new CTitleButton(parent);
title->setText(t);

QHBoxLayout* hLayout = new QHBoxLayout(parent);
hLayout->addWidget(title);
hLayout->addWidget(value);
hLayout->setSpacing(2);
hLayout->setMargin(2);
setLayout(hLayout);

// When the title button is clicked
connect(title, SIGNAL(clicked()),
this, SIGNAL(titleClicked()));
}
~CSpinBoxWidget() {}

public:
int Value() { return value->value(); }
void SetValue(int val) { value->setValue(val); }
void SetMinimum(int min) {
value->setMinimum(min);
}
void SetMaximum(int max) {
value->setMaximum(max);
}

signals:
void titleClicked();

private:
void mouseReleaseEvent(QMouseEvent* e) {
QWidget::mouseReleaseEvent(e);
}

private:
QSpinBox* value;
QPushButton* title;
};

But I don't understand how the event handling is supposed to work. When I create the QMenu, QWidgetAction and CSpinBox widget, does it matter who is whose parent as far as the event handling goes?

"QWidget::mouseReleaseEvent(event);" in CTitleButton::mouseReleaseEvent(QMouseEvent* event) ends up calling "event->ignore();", so does nothing really.

There is a documentation snippet in qwidgetaction.cpp that reads:


Note that it is up to the widget to activate the action, for example by reimplementing mouse event handlers and calling QAction::trigger().

But this doesn't make sense to me. How does the widget activate the action? Which mouseReleaseEvent functions need to be reimplemented? Who needs to call QAction::trigger (could only be derived QWidgetAction or QMenu)?

Any ideas?

Stefan

stefanadelbert
15th April 2010, 03:55
QMenu is receiving the mouseReleaseEvent, but is doing nothing with it.

d->mouseDown != this resolves to true so

d->mouseDown = 0;
return;
is being run.

Here is QMenu::mouseReleaseEvent (see qmenu.cpp):

void QMenu::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QMenu);
if (d->aboutToHide || d->mouseEventTaken(e))
return;
if(d->mouseDown != this) {
d->mouseDown = 0;
return;
}

d->mouseDown = 0;
d->setSyncAction();
QAction *action = d->actionAt(e->pos());

if (action && action == d->currentAction) {
if (action->menu())
action->menu()->d_func()->setFirstActionActive();
else {
#if defined(Q_WS_WIN)
//On Windows only context menus can be activated with the right button
if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
#endif
d->activateAction(action, QAction::Trigger);
}
} else if (d->hasMouseMoved(e->globalPos())) {
d->hideUpToMenuBar();
}
}

Does this mean that the menu thinks that it wasn't actually clicked? What does d->mouseDown actually represent?

norobro
15th April 2010, 04:51
A simplistic look at this, but will connecting the titleClicked() signal to the QMenu::hide() slot not work?

stefanadelbert
15th April 2010, 04:59
Sometimes simple is best. I'll give that a try and I reckon that it'll do that trick.

EDIT: Of course that works! Those were a few hours of my life that I won't get back.

@norobro: thanks

EDIT: I've been able to remove a fair amount of code now, notably the derived QPushButton with reimplemented mouseReleaseEvent. It would be nice to use the event/action framework as intended, but...

norobro
15th April 2010, 05:15
Glad I could help! You were way over my head delving into the event/action framework. I'm the two S'es of the K.I.S.S. principle.

stefanadelbert
15th April 2010, 05:38
Any idea how I mark a thread as solved or closed?