QMenuBar: Fix repetitive emission of triggered() when using addAction(QString)

The action which added by QMenuBar::addAction(const QString &text) already
connected relevant signals and slots implicitly, however, while
QMenuBarPrivate::updateGeometry -ing, it reconnects them
if there's a extension button associated with a hidden popup menu.
In that case the QMenuBar::triggered would be fired twice.
Since the QAction's ownership may be changed or added dynamically,
there are still very rare cases like several widgets share the same
QAction object to result in this problem.

[ChangeLog][QtWidgets][QMenu] Fixed a bug in QMenu that caused QMenuBar::triggered
to be fired multiple times.

Task-number: QTBUG-25669
Change-Id: I4d52e82a2136a992e0b37118e41237d96a2c5d22
Reviewed-by: Frederik Gladhorn <frederik.gladhorn@qt.io>
This commit is contained in:
Yulong Bai 2017-12-18 12:55:15 +01:00
parent b3e7e9b182
commit 4d898a73e6
2 changed files with 33 additions and 5 deletions

View File

@ -3534,9 +3534,13 @@ void QMenu::actionEvent(QActionEvent *e)
if (d->tornPopup)
d->tornPopup->syncWithMenu(this, e);
if (e->type() == QEvent::ActionAdded) {
if(!d->tornoff) {
connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()));
if (!d->tornoff
&& !qobject_cast<QMenuBar*>(e->action()->parent())) {
// Only connect if the action was not directly added by QMenuBar::addAction(const QString &text)
// to avoid the signal being emitted twice
connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered()), Qt::UniqueConnection);
connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered()), Qt::UniqueConnection);
}
if (QWidgetAction *wa = qobject_cast<QWidgetAction *>(e->action())) {
QWidget *widget = wa->requestWidget(this);

View File

@ -148,11 +148,10 @@ private slots:
void taskQTBUG56275_reinsertMenuInParentlessQMenuBar();
void QTBUG_57404_existingMenuItemException();
#endif
void QTBUG_25669_menubarActionDoubleTriggered();
void taskQTBUG55966_subMenuRemoved();
void QTBUG_58344_invalidIcon();
void platformMenu();
void addActionQt5connect();
protected slots:
@ -1633,6 +1632,31 @@ void tst_QMenuBar::addActionQt5connect()
QVERIFY(flag);
}
void tst_QMenuBar::QTBUG_25669_menubarActionDoubleTriggered()
{
QMainWindow win;
win.menuBar()->setNativeMenuBar(false);
QAction *act1 = win.menuBar()->addAction("Action1");
QAction *act2 = win.menuBar()->addAction("Action2");
QSignalSpy spy(win.menuBar(), &QMenuBar::triggered);
win.show();
QApplication::setActiveWindow(&win);
QVERIFY(QTest::qWaitForWindowExposed(&win));
QPoint posAct1 = menuBarActionWindowPos(win.menuBar(), act1);
QPoint posAct2 = menuBarActionWindowPos(win.menuBar(), act2);
QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct1);
QTRY_COMPARE(spy.count(), 1);
QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct2);
QTRY_COMPARE(spy.count(), 2);
QTest::mouseClick(win.windowHandle(), Qt::LeftButton, Qt::NoModifier, posAct2);
QTRY_COMPARE(spy.count(), 3);
}
void tst_QMenuBar::slotForTaskQTBUG53205()
{
QWidget *parent = taskQTBUG53205MenuBar->parentWidget();