📄 qmenu.cpp
字号:
/* This is poor-mans eventfilters. This avoids the use of eventFilter (which can be nasty for users of QMenuBar's). */bool QMenuPrivate::mouseEventTaken(QMouseEvent *e){ Q_Q(QMenu); QPoint pos = q->mapFromGlobal(e->globalPos()); if (scroll && !activeMenu) { //let the scroller "steal" the event bool isScroll = false; if (pos.x() >= 0 && pos.x() < q->width()) { const int scrollerHeight = q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q); for(int dir = QMenuScroller::ScrollUp; dir <= QMenuScroller::ScrollDown; dir = dir << 1) { if (scroll->scrollFlags & dir) { if (dir == QMenuScroller::ScrollUp) isScroll = (pos.y() <= scrollerHeight); else if (dir == QMenuScroller::ScrollDown) isScroll = (pos.y() >= q->height()-scrollerHeight); if (isScroll) { scroll->scrollDirection = dir; break; } } } } if (isScroll) { if (!scroll->scrollTimer) scroll->scrollTimer = new QBasicTimer; scroll->scrollTimer->start(50, q); return true; } else if (scroll->scrollTimer && scroll->scrollTimer->isActive()) { scroll->scrollTimer->stop(); } } if (tearoff) { //let the tear off thingie "steal" the event.. QRect tearRect(0, 0, q->width(), q->style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q)); if (scroll && scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) tearRect.translate(0, q->style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, q)); q->update(tearRect); if (tearRect.contains(pos) && hasMouseMoved(e->globalPos())) { setCurrentAction(0); tearoffHighlighted = 1; if (e->type() == QEvent::MouseButtonRelease) { if (!tornPopup) tornPopup = new QTornOffMenu(q); tornPopup->setGeometry(q->geometry()); tornPopup->show(); hideUpToMenuBar(); } return true; } tearoffHighlighted = 0; } if (q->frameGeometry().contains(e->globalPos())) //otherwise if the event is in our rect we want it.. return false; for(QWidget *caused = causedPopup.widget; caused;) { bool passOnEvent = false; QWidget *next_widget = 0; QPoint cpos = caused->mapFromGlobal(e->globalPos());#ifndef QT_NO_MENUBAR if (QMenuBar *mb = qobject_cast<QMenuBar*>(caused)) { passOnEvent = mb->rect().contains(cpos); } else#endif if (QMenu *m = qobject_cast<QMenu*>(caused)) { passOnEvent = m->d_func()->actionAt(cpos); next_widget = m->d_func()->causedPopup.widget; } if (passOnEvent) { if(e->type() != QEvent::MouseButtonRelease || mouseDown == caused) { QMouseEvent new_e(e->type(), cpos, e->button(), e->buttons(), e->modifiers()); QApplication::sendEvent(caused, &new_e); return true; } } if (!next_widget) break; caused = next_widget; } return false;}void QMenuPrivate::activateAction(QAction *action, QAction::ActionEvent action_e, bool self){ Q_Q(QMenu);#ifndef QT_NO_WHATSTHIS bool inWhatsThisMode = QWhatsThis::inWhatsThisMode();#endif if (!action || !q->isEnabled() || (action_e == QAction::Trigger#ifndef QT_NO_WHATSTHIS && !inWhatsThisMode#endif && (action->isSeparator() ||!action->isEnabled()))) return; /* I have to save the caused stack here because it will be undone after popup execution (ie in the hide). Then I iterate over the list to actually send the events. --Sam */ const QList<QPointer<QWidget> > causedStack = calcCausedStack(); if (action_e == QAction::Trigger) { for(QWidget *widget = qApp->activePopupWidget(); widget; ) { if (QMenu *qmenu = ::qobject_cast<QMenu*>(widget)) { if(qmenu == q) hideUpToMenuBar(); widget = qmenu->d_func()->causedPopup.widget; } else { break; } }#ifndef QT_NO_WHATSTHIS if (inWhatsThisMode) { QString s = action->whatsThis(); if (s.isEmpty()) s = whatsThis; QWhatsThis::showText(q->mapToGlobal(actionRect(action).center()), s, q); return; }#endif }#ifdef QT3_SUPPORT const int actionId = q->findIdForAction(action);#endif if(self) action->activate(action_e); for(int i = 0; i < causedStack.size(); ++i) { QPointer<QWidget> widget = causedStack.at(i); if (!widget) continue; //fire if (QMenu *qmenu = ::qobject_cast<QMenu*>(widget)) { widget = qmenu->d_func()->causedPopup.widget; if (action_e == QAction::Trigger) { emit qmenu->triggered(action);#ifdef QT3_SUPPORT emit qmenu->activated(actionId);#endif } else if (action_e == QAction::Hover) { emit qmenu->hovered(action);#ifdef QT3_SUPPORT emit qmenu->highlighted(actionId);#endif }#ifndef QT_NO_MENUBAR } else if (QMenuBar *qmenubar = ::qobject_cast<QMenuBar*>(widget)) { if (action_e == QAction::Trigger) { emit qmenubar->triggered(action);#ifdef QT3_SUPPORT emit qmenubar->activated(actionId);#endif } else if (action_e == QAction::Hover) { emit qmenubar->hovered(action);#ifdef QT3_SUPPORT emit qmenubar->highlighted(actionId);#endif } break; //nothing more..#endif } } if (action_e == QAction::Hover) {#ifndef QT_NO_ACCESSIBILITY if (QAccessible::isActive()) { int actionIndex = indexOf(action) + 1; QAccessible::updateAccessibility(q, actionIndex, QAccessible::Focus); QAccessible::updateAccessibility(q, actionIndex, QAccessible::Selection); }#endif QWidget *w = causedPopup.widget; while (QMenu *m = qobject_cast<QMenu*>(w)) w = m->d_func()->causedPopup.widget; action->showStatusText(w); }}void QMenuPrivate::_q_actionTriggered(){ Q_Q(QMenu); if (QAction *action = qobject_cast<QAction *>(q->sender())) {#ifdef QT3_SUPPORT //we store it here because the action might be deleted/changed by connected slots const int id = q->findIdForAction(action);#endif emit q->triggered(action);#ifdef QT3_SUPPORT emit q->activated(id);#endif }}void QMenuPrivate::_q_actionHovered(){ Q_Q(QMenu); if (QAction *action = qobject_cast<QAction *>(q->sender())) {#ifdef QT3_SUPPORT //we store it here because the action might be deleted/changed by connected slots const int id = q->findIdForAction(action);#endif emit q->hovered(action);#ifdef QT3_SUPPORT emit q->highlighted(id);#endif }}bool QMenuPrivate::hasMouseMoved(const QPoint &globalPos){ //determines if the mouse has moved (ie its intial position has //changed by more than QApplication::startDragDistance() //or if there were at least 6 mouse motions) return motions > 6 || QApplication::startDragDistance() < (mousePopupPos - globalPos).manhattanLength();}/*! Initialize \a option with the values from this menu and information from \a action. This method is useful for subclasses when they need a QStyleOptionMenuItem, but don't want to fill in all the information themselves. \sa QStyleOption::initFrom() QMenuBar::initStyleOption()*/void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) const{ if (!option || !action) return; Q_D(const QMenu); option->initFrom(this); option->palette = palette(); option->state = QStyle::State_None; if (window()->isActiveWindow()) option->state |= QStyle::State_Active; if (isEnabled() && action->isEnabled() && (!action->menu() || action->menu()->isEnabled())) option->state |= QStyle::State_Enabled; else option->palette.setCurrentColorGroup(QPalette::Disabled); option->font = action->font(); if (d->currentAction && d->currentAction == action && !d->currentAction->isSeparator()) { option->state |= QStyle::State_Selected | (d->mouseDown ? QStyle::State_Sunken : QStyle::State_None); } option->menuHasCheckableItems = d->hasCheckableItems; if (!action->isCheckable()) { option->checkType = QStyleOptionMenuItem::NotCheckable; } else { option->checkType = (action->actionGroup() && action->actionGroup()->isExclusive()) ? QStyleOptionMenuItem::Exclusive : QStyleOptionMenuItem::NonExclusive; option->checked = action->isChecked(); } if (action->menu()) option->menuItemType = QStyleOptionMenuItem::SubMenu; else if (action->isSeparator()) option->menuItemType = QStyleOptionMenuItem::Separator; else if (d->defaultAction == action) option->menuItemType = QStyleOptionMenuItem::DefaultItem; else option->menuItemType = QStyleOptionMenuItem::Normal; option->icon = action->icon(); QString textAndAccel = action->text();#ifndef QT_NO_SHORTCUT if (textAndAccel.indexOf(QLatin1Char('\t')) == -1) { QKeySequence seq = action->shortcut(); if (!seq.isEmpty()) textAndAccel += QLatin1Char('\t') + QString(seq); }#endif option->text = textAndAccel; option->tabWidth = d->tabWidth; option->maxIconWidth = d->maxIconWidth; option->menuRect = rect();}/*! \class QMenu \brief The QMenu class provides a menu widget for use in menu bars, context menus, and other popup menus. \ingroup application \ingroup basicwidgets \mainclass A menu widget is a selection menu. It can be either a pull-down menu in a menu bar or a standalone context menu. Pull-down menus are shown by the menu bar when the user clicks on the respective item or presses the specified shortcut key. Use QMenuBar::addMenu() to insert a menu into a menu bar. Context menus are usually invoked by some special keyboard key or by right-clicking. They can be executed either asynchronously with popup() or synchronously with exec(). Menus can also be invoked in response to button presses; these are just like context menus except for how they are invoked. \raw HTML <table align="center" cellpadding="0"> <tr> <td> \endraw \inlineimage plastique-menu.png \raw HTML </td> <td> \endraw \inlineimage windowsxp-menu.png \raw HTML </td> <td> \endraw \inlineimage macintosh-menu.png \raw HTML </td> </tr> <tr> <td colspan="3"> \endraw A menu shown in \l{Plastique Style Widget Gallery}{Plastique widget style}, \l{Windows XP Style Widget Gallery}{Windows XP widget style}, and \l{Macintosh Style Widget Gallery}{Macintosh widget style}. \raw HTML </td> </tr> </table> \endraw A menu consists of a list of action items. Actions are added with addAction(). An action is represented vertically and rendered by QStyle. In addition, actions can have a text label, an optional icon drawn on the very left side, and shortcut key sequence such as "Ctrl+X". There are three kinds of action items: separators, actions that show a submenu, and actions that perform an action. Separators are inserted with addSeparator(). For submenus use addMenu(). All other items are considered action items. When inserting action items you usually specify a receiver and a slot. The receiver will be notifed whenever the item is \l{QAction::triggered()}{triggered()}. In addition, QMenu provides two signals, activated() and highlighted(), which signal the QAction that was triggered from the menu. You clear a menu with clear() and remove individual action items with removeAction(). A QMenu can also provide a tear-off menu. A tear-off menu is a top-level window that contains a copy of the menu. This makes it possible for the user to "tear off" frequently used menus and position them in a convenient place on the screen. If you want this functionality for a particular menu, insert a tear-off handle with setTearOffEnabled(). When using tear-off menus, bear in mind that the concept isn't typically used on Microsoft Windows so some users may not be familiar with it. Consider using a QToolBar instead. See the \l{mainwindows/menus}{Menus} example for an example of how to use QMenuBar and QMenu in your application. Important inherited functions: addAction(), removeAction(), clear(), addSeparator(), and addMenu(). \sa QMenuBar, {fowler}{GUI Design Handbook: Menu, Drop-Down and Pop-Up}, {Application Example}, {Menus Example}, {Recent Files Example}*//*! Constructs a menu with parent \a parent. Although a popup menu is always a top-level widget, if a parent is passed the popup menu will be deleted when that parent is destroyed (as with any other QObject).*/QMenu::QMenu(QWidget *parent) : QWidget(*new QMenuPrivate, parent, Qt::Popup){ Q_D(QMenu); d->init();}/*! Constructs a menu with a \a title and a \a parent. Although a popup menu is always a top-level widget, if a parent is passed the popup menu will be deleted when that parent is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -