📄 qmenu.cpp
字号:
}/*! Displays the menu so that the action \a atAction will be at the specified \e global position \a p. To translate a widget's local coordinates into global coordinates, use QWidget::mapToGlobal(). When positioning a menu with exec() or popup(), bear in mind that you cannot rely on the menu's current size(). For performance reasons, the menu adapts its size only when necessary, so in many cases, the size before and after the show is different. Instead, use sizeHint() which calculates the proper size depending on the menu's current contents. \sa QWidget::mapToGlobal(), exec()*/void QMenu::popup(const QPoint &p, QAction *atAction){ Q_D(QMenu); if (d->scroll) { //reset scroll state from last popup d->scroll->scrollOffset = 0; d->scroll->scrollFlags = QMenuPrivate::QMenuScroller::ScrollNone; } d->tearoffHighlighted = 0; d->motions = 0; d->doChildEffects = true; ensurePolished(); // Get the right font emit aboutToShow(); d->updateActions(); QPoint pos = p; QSize size = sizeHint(); QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this); if (d->ncols > 1) { pos.setY(screen.top()+desktopFrame); } else if (atAction) { for(int i=0, above_height=0; i<(int)d->actionList.count(); i++) { QAction *action = d->actionList.at(i); if (action == atAction) { int newY = pos.y()-above_height; if (d->scroll && newY < desktopFrame) { d->scroll->scrollFlags = d->scroll->scrollFlags | QMenuPrivate::QMenuScroller::ScrollUp; d->scroll->scrollOffset = newY; newY = desktopFrame; } pos.setY(newY); if (d->scroll && d->scroll->scrollFlags != QMenuPrivate::QMenuScroller::ScrollNone && !style()->styleHint(QStyle::SH_Menu_FillScreenWithScroll, 0, this)) { int below_height = above_height + d->scroll->scrollOffset; for(int i2 = i; i2 < (int)d->actionList.count(); i2++) below_height += d->actionRects.value(d->actionList.at(i2)).height(); size.setHeight(below_height); } break; } else { above_height += d->actionRects.value(action).height(); } } } QPoint mouse = QCursor::pos(); d->mousePopupPos = mouse; const bool snapToMouse = (QRect(p.x()-3, p.y()-3, 6, 6).contains(mouse)); //handle popup falling "off screen" if (qApp->layoutDirection() == Qt::RightToLeft) { if(snapToMouse) //position flowing left from the mouse pos.setX(mouse.x()-size.width()); if (pos.x() < screen.left()+desktopFrame) pos.setX(qMax(p.x(), screen.left()+desktopFrame)); if (pos.x()+size.width()-1 > screen.right()-desktopFrame) pos.setX(qMax(p.x()-size.width(), screen.right()-desktopFrame-size.width()+1)); } else { if (pos.x()+size.width()-1 > screen.right()-desktopFrame) pos.setX(qMin(p.x()-size.width(), screen.right()-desktopFrame-size.width()+1)); if (pos.x() < screen.left()+desktopFrame) pos.setX(qMax(p.x(), screen.left() + desktopFrame)); } if (pos.y() + size.height() - 1 > screen.bottom() - desktopFrame) { if(snapToMouse) pos.setY(qMin(mouse.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1)); else pos.setY(qMax(p.y() - (size.height() + desktopFrame), screen.bottom()-desktopFrame-size.height()+1)); } else if (pos.y() < screen.top() + desktopFrame) { pos.setY(screen.top() + desktopFrame); } if (pos.y() < screen.top() + desktopFrame) pos.setY(screen.top() + desktopFrame); if (pos.y()+size.height()-1 > screen.bottom() - desktopFrame) { if (d->scroll) { d->scroll->scrollFlags |= uint(QMenuPrivate::QMenuScroller::ScrollDown); int y = qMax(screen.y(),pos.y()); size.setHeight(screen.bottom()-(desktopFrame*2)-y); } else { // Too big for screen, bias to see bottom of menu (for some reason) pos.setY(screen.bottom()-size.height()+1); } } setGeometry(QRect(pos, size));#ifndef QT_NO_EFFECTS int hGuess = qApp->layoutDirection() == Qt::RightToLeft ? QEffects::LeftScroll : QEffects::RightScroll; int vGuess = QEffects::DownScroll; if (qApp->layoutDirection() == Qt::RightToLeft) { if ((snapToMouse && (pos.x() + size.width()/2 > mouse.x())) || (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 > d->causedPopup.widget->x())) hGuess = QEffects::RightScroll; } else { if ((snapToMouse && (pos.x() + size.width()/2 < mouse.x())) || (qobject_cast<QMenu*>(d->causedPopup.widget) && pos.x() + size.width()/2 < d->causedPopup.widget->x())) hGuess = QEffects::LeftScroll; }#ifndef QT_NO_MENUBAR if ((snapToMouse && (pos.y() + size.height()/2 < mouse.y())) || (qobject_cast<QMenuBar*>(d->causedPopup.widget) && pos.y() + size.width()/2 < d->causedPopup.widget->mapToGlobal(d->causedPopup.widget->pos()).y())) vGuess = QEffects::UpScroll;#endif if (QApplication::isEffectEnabled(Qt::UI_AnimateMenu)) { bool doChildEffects = true;#ifndef QT_NO_MENUBAR if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) { doChildEffects = mb->d_func()->doChildEffects; mb->d_func()->doChildEffects = false; } else#endif if (QMenu *m = qobject_cast<QMenu*>(d->causedPopup.widget)) { doChildEffects = m->d_func()->doChildEffects; m->d_func()->doChildEffects = false; } if (doChildEffects) { if (QApplication::isEffectEnabled(Qt::UI_FadeMenu)) qFadeEffect(this); else if (d->causedPopup.widget) qScrollEffect(this, qobject_cast<QMenu*>(d->causedPopup.widget) ? hGuess : vGuess); else qScrollEffect(this, hGuess | vGuess); } else { // kill any running effect qFadeEffect(0); qScrollEffect(0); show(); } } else#endif { show(); }#ifndef QT_NO_ACCESSIBILITY QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuStart);#endif}/*! Executes this menu synchronously. This is equivalent to \c{exec(pos())}. This returns the triggered QAction in either the popup menu or one of its submenus, or 0 if no item was triggered (normally because the user pressed Esc). In most situations you'll want to specify the position yourself, for example, the current mouse position: \code exec(QCursor::pos()); \endcode or aligned to a widget: \code exec(somewidget.mapToGlobal(QPoint(0,0))); \endcode or in reaction to a QMouseEvent *e: \code exec(e->globalPos()); \endcode*/QAction *QMenu::exec(){ return exec(pos());}/*! \overload Executes this menu synchronously. Pops up the menu so that the action \a action will be at the specified \e global position \a p. To translate a widget's local coordinates into global coordinates, use QWidget::mapToGlobal(). This returns the triggered QAction in either the popup menu or one of its submenus, or 0 if no item was triggered (normally because the user pressed Esc). Note that all signals are emitted as usual. If you connect a QAction to a slot and call the menu's exec(), you get the result both via the signal-slot connection and in the return value of exec(). Common usage is to position the menu at the current mouse position: \code exec(QCursor::pos()); \endcode or aligned to a widget: \code exec(somewidget.mapToGlobal(QPoint(0, 0))); \endcode or in reaction to a QMouseEvent *e: \code exec(e->globalPos()); \endcode When positioning a menu with exec() or popup(), bear in mind that you cannot rely on the menu's current size(). For performance reasons, the menu adapts its size only when necessary. So in many cases, the size before and after the show is different. Instead, use sizeHint() which calculates the proper size depending on the menu's current contents. \sa popup(), QWidget::mapToGlobal()*/QAction *QMenu::exec(const QPoint &p, QAction *action){ Q_D(QMenu); createWinId(); QEventLoop eventLoop; d->eventLoop = &eventLoop; popup(p, action); QPointer<QObject> guard = this; (void) eventLoop.exec(); if (guard.isNull()) return 0; action = d->syncAction; d->syncAction = 0; d->eventLoop = 0; return action;}/*! \overload Executes this menu synchronously. The menu's actions are specified by the list of \a actions. The menu will pop up so that the specified action, \a at, appears at global position \a pos. If \a at is not specified then the menu appears at position \a pos. The function returns the triggered QAction in either the popup menu or one of its submenus, or 0 if no item was triggered (normally because the user pressed Esc). This is equivalent to: \code QMenu menu; QAction *at = actions[0]; // Assumes actions is not empty foreach (QAction *a, actions) menu.addAction(a); menu.exec(pos, at); \endcode \sa popup(), QWidget::mapToGlobal()*/QAction *QMenu::exec(QList<QAction*> actions, const QPoint &pos, QAction *at){ QMenu menu; for(QList<QAction*>::ConstIterator it = actions.constBegin(); it != actions.constEnd(); ++it) menu.addAction((*it)); return menu.exec(pos, at);}/*! \reimp*/void QMenu::hideEvent(QHideEvent *){ Q_D(QMenu); emit aboutToHide(); if (d->eventLoop) d->eventLoop->exit(); d->setCurrentAction(0);#ifndef QT_NO_ACCESSIBILITY QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuEnd);#endif#ifndef QT_NO_MENUBAR if (QMenuBar *mb = qobject_cast<QMenuBar*>(d->causedPopup.widget)) mb->d_func()->setCurrentAction(0);#endif d->mouseDown = 0; d->hasHadMouse = false; d->causedPopup.widget = 0; d->causedPopup.action = 0;}/*! \reimp*/void QMenu::paintEvent(QPaintEvent *e){ Q_D(QMenu); QPainter p(this); QRegion emptyArea = QRegion(rect()); //draw the items that need updating.. for (int i = 0; i < d->actionList.count(); ++i) { QAction *action = d->actionList.at(i); QRect adjustedActionRect = d->actionRect(action); if (!e->rect().intersects(adjustedActionRect) || d->widgetItems.value(action)) continue; //set the clip region to be extra safe (and adjust for the scrollers) QRegion adjustedActionReg(adjustedActionRect); emptyArea -= adjustedActionReg; p.setClipRegion(adjustedActionReg); QStyleOptionMenuItem opt; initStyleOption(&opt, action); opt.rect = adjustedActionRect; style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this); } const int fw = style()->pixelMetric(QStyle::PM_MenuPanelWidth, 0, this); QStyleOptionMenuItem menuOpt; menuOpt.initFrom(this); menuOpt.palette = palette(); menuOpt.state = QStyle::State_None; menuOpt.checkType = QStyleOptionMenuItem::NotCheckable; menuOpt.menuRect = rect(); menuOpt.maxIconWidth = 0; menuOpt.tabWidth = 0; //draw the scroller regions.. if (d->scroll) { const int scrollerHeight = style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this); menuOpt.menuItemType = QStyleOptionMenuItem::Scroller; menuOpt.state |= QStyle::State_Enabled; if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) { menuOpt.rect.setRect(fw, fw, width() - (fw * 2), scrollerHeight); emptyArea -= QRegion(menuOpt.rect); p.setClipRect(menuOpt.rect); style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this); } if (d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollDown) { menuOpt.rect.setRect(fw, height() - scrollerHeight - fw, width() - (fw * 2), scrollerHeight); emptyArea -= QRegion(menuOpt.rect); menuOpt.state |= QStyle::State_DownArrow; p.setClipRect(menuOpt.rect); style()->drawControl(QStyle::CE_MenuScroller, &menuOpt, &p, this); } } //paint the tear off.. if (d->tearoff) { menuOpt.menuItemType = QStyleOptionMenuItem::TearOff; menuOpt.rect.setRect(fw, fw, width() - (fw * 2), style()->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, this)); if (d->scroll && d->scroll->scrollFlags & QMenuPrivate::QMenuScroller::ScrollUp) menuOpt.rect.translate(0, style()->pixelMetric(QStyle::PM_MenuScrollerHeight, 0, this)); emptyArea -= QRegion(menuOpt.rect); p.setClipRect(menuOpt.rect); menuOpt.state = QStyle::State_None; if (d->tearoffHighlighted) menuOpt.state |= QStyle::State_Selected; style()->drawControl(QStyle::CE_MenuTearoff, &menuOpt, &p, this); } //draw border if (fw) { QRegion borderReg; borderReg += QRect(0, 0, fw, height()); //left borderReg += QRect(width()-fw, 0, fw, height()); //right borderReg += QRect(0, 0, width(), fw); //top borderReg += QRect(0, height()-fw, width(), fw); //bottom p.setClipRegion(borderReg); emptyArea -= borderReg; QStyleOptionFrame frame; frame.rect = rect(); frame.palette = palette(); frame.state = QStyle::State_None; frame.lineWidth = s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -