一、关联菜单策略 QWidget:: contextMenuPolicy
帮助文档:
This property holds how the widget shows a context menu.
The default value of this property is Qt::DefaultContextMenu, which means the contextMenuEvent() handler is called. Other values are Qt::NoContextMenu,Qt::PreventContextMenu, Qt::ActionsContextMenu, and Qt::CustomContextMenu. With Qt::CustomContextMenu, the signal customContextMenuRequested() is emitted.
中文大概是说:
这个属性(contextMenuPolicy)决定了如何显示上下文菜单(通常是右键弹出菜单)。默认的属性值是Qt::DefaultContextMenu,这意味着contextMenuEvent()函数将会被调用。
其他属性值值:
Qt::NoContextMenu,Qt::PreventContextMenu, Qt::ActionsContextMenu, Qt::CustomContextMenu. Qt::CustomContextMenu,将会发出信号customContextMenuRequested()。
方法一、void QWidget::contextMenuEvent ( QContextMenuEvent * event ) [virtual protected]
This event handler, for event event, can be reimplemented in a subclass to receive widget context menu events.
The handler is called when the widget's contextMenuPolicy is Qt::DefaultContextMenu.
The default implementation ignores the context event. See the QContextMenuEvent documentation for more details.
中文意思:这个事件处理函数,可以被QWidget的子类重新实现去接收上下文菜单事件。当属性contextMenuPolicy 的值是Qt::DefaultContextMenu的时候,这个函数才会被调用。默认的函数实现忽略了上下文菜单事件。
所以,我们重载contextMenuEvent函数实现上下文菜单。
mainWidget.h
#ifndef MAINWIDGET_H #define MAINWIDGET_H #include <QtGui/QWidget> class QMenu; class mainWidget : public QWidget { Q_OBJECT public: mainWidget(QWidget *parent = 0); ~mainWidget(); private: QMenu *menuTest; protected: virtual void contextMenuEvent(QContextMenuEvent *); }; #endif // MAINWIDGET_H
mainWidget.cpp
#include "mainwidget.h" #include <QMenu> #include <QAction> #include <QContextMenuEvent> mainWidget::mainWidget(QWidget *parent) : QWidget(parent) { menuTest=new QMenu(this); QAction *actionTest=new QAction("test",this); menuTest->addAction(actionTest); } mainWidget::~mainWidget() { } void mainWidget::contextMenuEvent(QContextMenuEvent *event) { menuTest->exec(event->globalPos()); }
这是可以实现的。
方法二、信号customContextMenuRequested
为了发出这个信号,我们设置setContextMenuPolicy(Qt::CustomContextMenu);
并且关联QObject::connect(this,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(showMenu(QPoint)));
showMenu(QPoint)是自定义的一个信号槽,处理菜单的显示。
mainWidget.h
#ifndef MAINWIDGET_H #define MAINWIDGET_H #include <QtGui/QWidget> class QMenu; class mainWidget : public QWidget { Q_OBJECT public: mainWidget(QWidget *parent = 0); ~mainWidget(); private: QMenu *menuTest; private slots: void showMenu(QPoint); }; #endif // MAINWIDGET_H
mainWidget.cpp
#include "mainwidget.h" #include <QMenu> #include <QAction> #include <QContextMenuEvent> mainWidget::mainWidget(QWidget *parent) : QWidget(parent) { menuTest=new QMenu(this); QAction *actionTest=new QAction("test",this); menuTest->addAction(actionTest); //必须设置此属性,否则不会发出信号customContextMenuRequested setContextMenuPolicy(Qt::CustomContextMenu); connect(this,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(showMenu(QPoint))); } mainWidget::~mainWidget() { } //private slot void mainWidget::showMenu(QPoint p) { /* p是相对于窗体坐标系的,即p的坐标相对与窗体的左上角坐标(0,0) 如果窗体左上角为(100,100),p为(10,20) 则mapToGlobal(p)为(110,120) 经过坐标转化,才能在正确的位置显示菜单 */ menuTest->exec(mapToGlobal(p)); }
在窗体中创建弹出菜单位置不正确解决:
mainWidget.h
#ifndef MAINWIDGET_H #define MAINWIDGET_H #include <QtGui/QWidget> class QMenu; class QListWidget; class mainWidget : public QWidget { Q_OBJECT public: mainWidget(QWidget *parent = 0); ~mainWidget(); private: QMenu *menuTest; QListWidget *listTest;//添加一个窗体,弹出菜单 private slots: void showMenu(QPoint); }; #endif // MAINWIDGET_H
mainWidget.cpp
#include "mainwidget.h" #include <QMenu> #include <QAction> #include <QListWidget> #include <QVBoxLayout> mainWidget::mainWidget(QWidget *parent) : QWidget(parent) { menuTest=new QMenu(this); QAction *actionTest=new QAction("test",this); menuTest->addAction(actionTest); listTest=new QListWidget; //必须设置此属性,否则不会发出信号customContextMenuRequested listTest->setContextMenuPolicy(Qt::CustomContextMenu); connect(listTest,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(showMenu(QPoint))); QVBoxLayout *mainLayout=new QVBoxLayout; mainLayout->addWidget(listTest); setLayout(mainLayout); } mainWidget::~mainWidget() { } //private slot void mainWidget::showMenu(QPoint p) { /* p是相对于窗体坐标系的,即p的坐标相对与窗体的左上角坐标(0,0) 如果窗体左上角为(100,100),p为(10,20) 则mapToGlobal(p)为(110,120) 经过坐标转化,才能在正确的位置显示菜单 */ menuTest->exec(mapToGlobal(p)); }
但是,问题出现了,总是不能在正确的位置弹出菜单。
看帮助文档发现,customContextMenuRequested发出的QPoint p是相对于发出这个信号的窗体的左上角(0,0)的。所以,必须先转化为相对于父窗口的坐标,然后再转化为相对于全局的坐标。
把menuTest->exec(mapToGlobal(p));修改为menuTest->exec(mapToGlobal(mapToParent(p)));
结果还是不能正确显示,这就是我对类的概念模糊了。
menuTest->exec(mapToGlobal(mapToParent(p)));等价于menuTest->exec(this->mapToGlobal(this->mapToParent(p)));
而本意是把子窗体坐标转化为父窗体坐标,所以,应该改为:menuTest->exec(this->mapToGlobal(listTest->mapToParent(p)));
这样就显示正常了。
经过这么一想,其实改成menuTest->exec(listTest->mapToGlobal(p));也是正确的。
当然,最简便的还是menuTest->exec(QCursor::pos());
感想:Qt接触将近一个月了。感觉对类这个概念理解的清楚了一点。但还是不好。以至于连this指针都忘了。