QWidget及其子类都可有右键菜单,因为QWidget有以下两个与右键菜单有关的函数:
Qt::ContextMenuPolicy contextMenuPolicy () const
void setContextMenuPolicy ( Qt::ContextMenuPolicy policy )
Qt::ContextMenuPolicy 枚举类型包括:Qt::DefaultContextMenu, Qt::NoContextMenu, Qt::PreventContextMenu, Qt::ActionsContextMenu, and Qt::CustomContextMenu。
使用方式如下:
1)默认是Qt::DefaultContextMenu。
---->通过事件QContextMenuEvent完成
2)使用Qt::CustomContextMenu。
void customContextMenuRequested ( const QPoint & pos )
该信号的发出条件是:用户请求contextMenu(常规就是鼠标右击啦)且同时被击的widget其contextMenuPolicy又是 Qt::CustomContextMenu。
注重:pos是该widget接收右键菜单事件的位置,一般是在该部件的坐标系中。但是对于QAbstratScrollArea及其子类例外,是对应着其视口viewport()的坐标系。如常用的QTableView、QHeaderView就是QAbstratScrollArea的子类。
因为仅发信号,所以需自己写显示右键菜单的slot来响应。
---->通过信号槽完成
例如一个表格(QTableView类型)表头的显示右键菜单槽:
datatable->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); connect(datatable->horizontalHeader(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(show_contextmenu(const QPoint&)));//this是datatable所在窗口 QMenu *cmenu = NULL; show_contextmenu(const QPoint& pos) { if(cmenu)//保证同时只存在一个menu,及时释放内存 { delete cmenu; cmenu = NULL; } QMenu cmenu = new QMenu(datatable->horizontalHeader()); QAction *ascendSortAction = cmenu->addAction("升序"); QAction *descendSortAction = cmenu->addAction("降序"); QAction *filterAction = cmenu->addAction("过滤"); QAction *reshowAction = cmenu->addAction("重载"); connect(ascendSortAction, SIGNAL(triggered(bool)), this, SLOT(sort_ascend())); connect(descendSortAction, SIGNAL(triggered(bool)), this, SLOT(sort_descend())); connect(filterAction, SIGNAL(triggered(bool)), this, SLOT(show_filter_dlg())); connect(reshowAction, SIGNAL(triggered(bool)), this, SLOT(reshow_data())); cmenu->exec(QCursor::pos());//在当前鼠标位置显示 //cmenu->exec(pos)是在viewport显示 }
也可先做好cmenu,好处是始终使用一个:
QMenu cmenu = new QMenu(datatable->horizontalHeader()); QAction *ascendSortAction = cmenu->addAction("升序"); QAction *descendSortAction = cmenu->addAction("降序"); QAction *filterAction = cmenu->addAction("过滤"); QAction *reshowAction = cmenu->addAction("重载"); connect(ascendSortAction, SIGNAL(triggered(bool)), this, SLOT(sort_ascend())); connect(descendSortAction, SIGNAL(triggered(bool)), this, SLOT(sort_descend())); connect(filterAction, SIGNAL(triggered(bool)), this, SLOT(show_filter_dlg())); connect(reshowAction, SIGNAL(triggered(bool)), this, SLOT(reshow_data())); show_contextmenu(const QPoint& pos) { if(cmenu) { cmenu->exec(QCursor::pos()); } }
3)使用 Qt::ActionsContextMenu。
---->通过setContextMenuPolicy(Qt::ActionsContextMenu)完成
还是上面的例子,要在表格(QTableView类型)表头显示右键菜单:
QAction *ascendSortAction = new QAction("升序", this); QAction *descendSortAction = new QAction("降序", this); QAction *filterAction = new QAction("过滤", this); QAction *unfilterAction = new QAction("取消过滤", this); connect(ascendSortAction, SIGNAL(triggered(bool)), this, SLOT(sort_ascend())); connect(descendSortAction, SIGNAL(triggered(bool)), this, SLOT(sort_descend())); connect(filterAction, SIGNAL(triggered(bool)), this, SLOT(filter_table())); connect(unfilterAction, SIGNAL(triggered(bool)), this, SLOT(unfilter_table())); datatable->horizontalHeader()->addAction(ascendSortAction); datatable->horizontalHeader()->addAction(descendSortAction); datatable->horizontalHeader()->addAction(filterAction); datatable->horizontalHeader()->addAction(unfilterAction); datatable->horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);
另外两个就是不显示context menu了:
Qt::NoContextMenu
the widget does not feature a context menu, context menu handling is deferred to the widget's parent.
Qt::PreventContextMenu
the widget does not feature a context menu, and in contrast to NoContextMenu, the handling is not deferred to the widget's parent. This means that all right mouse button events are guaranteed to be delivered to the widget itself through mousePressEvent(), and mouseReleaseEvent().
补充:
show_contextmenu(const QPoint& pos) { //get related column of headerview contextmenu_column = datatable->horizontalHeader()->logicalIndexAt(pos); //show contextmenu if(cmenu) { cmenu->exec(QCursor::pos()); } }

