QT右键菜单的创建及相关问题解决
2011-09-07 16:18
489 查看
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。
它是利用右键菜单事件contextMenuEvent()来处理(which means the contextMenuEvent() handler is called)。就是要重写contextMenuEvent( QContextMenuEvent * event )函数。
2)使用Qt::CustomContextMenu。
它是发出QWidget::customContextMenuRequested信号,注意仅仅只是发信号,意味着要自己写显示右键菜单的slot。
这个信号是QWidget唯一与右键菜单有关的信号(也是自有的唯一信号),同时也是很容易被忽略的signal:
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。
把部件的所有action即QWidget::actions()作为context menu显示出来。
还是上面的例子,要在表格(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().
补充:
使用Qt::ActionsContextMenu比较简洁,但是如果需要根据当前菜单弹出的位置来定义不同菜单,或者像上个例子,在表格(QTableView类型)表头显示右键菜单时,我需要知道是哪一列表头被点击,从而在后来调用sort_ascend()排序函数时能够根据不同列进行不同排序策略,那么Qt::ActionsContextMenu就做不到了。
这种需要捕捉弹出位置的情况只好用Qt::ActionsContextMenu了,customContextMenuRequested ( const QPoint & pos )信号返回点击位置pos(在表头视口坐标系中位置),然后表头即可调用logicalIndexAt(pos)函数得到被点击section对应的index即被点击部分的列号,然后存下来可供后面action激活的排序槽使用。
show_contextmenu(const QPoint& pos)
{
//get related column of headerview
contextmenu_column = datatable->horizontalHeader()->logicalIndexAt(pos);
//show contextmenu
if(cmenu)
{
cmenu->exec(QCursor::pos());
}
}
【相关问题】
1.问题:当把 QTreeWidget 放在别的 QWidget 中以后,发现右键总是捕捉不到最下面的一个Item 节点。
错误代码:
void ShowItems::contextMenuEvent
( QContextMenuEvent
* event
)
原因:我们认为的(0,0)点的坐标与实际的有差距
解决:使用viewport()返回的QWidget作为当前的坐标QWidget
修改后,代码:
void
ShowItems::contextMenuEvent
(QContextMenuEvent
*event
)
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。
它是利用右键菜单事件contextMenuEvent()来处理(which means the contextMenuEvent() handler is called)。就是要重写contextMenuEvent( QContextMenuEvent * event )函数。
2)使用Qt::CustomContextMenu。
它是发出QWidget::customContextMenuRequested信号,注意仅仅只是发信号,意味着要自己写显示右键菜单的slot。
这个信号是QWidget唯一与右键菜单有关的信号(也是自有的唯一信号),同时也是很容易被忽略的signal:
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。
把部件的所有action即QWidget::actions()作为context menu显示出来。
还是上面的例子,要在表格(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().
补充:
使用Qt::ActionsContextMenu比较简洁,但是如果需要根据当前菜单弹出的位置来定义不同菜单,或者像上个例子,在表格(QTableView类型)表头显示右键菜单时,我需要知道是哪一列表头被点击,从而在后来调用sort_ascend()排序函数时能够根据不同列进行不同排序策略,那么Qt::ActionsContextMenu就做不到了。
这种需要捕捉弹出位置的情况只好用Qt::ActionsContextMenu了,customContextMenuRequested ( const QPoint & pos )信号返回点击位置pos(在表头视口坐标系中位置),然后表头即可调用logicalIndexAt(pos)函数得到被点击section对应的index即被点击部分的列号,然后存下来可供后面action激活的排序槽使用。
show_contextmenu(const QPoint& pos)
{
//get related column of headerview
contextmenu_column = datatable->horizontalHeader()->logicalIndexAt(pos);
//show contextmenu
if(cmenu)
{
cmenu->exec(QCursor::pos());
}
}
【相关问题】
1.问题:当把 QTreeWidget 放在别的 QWidget 中以后,发现右键总是捕捉不到最下面的一个Item 节点。
错误代码:
void ShowItems::contextMenuEvent
( QContextMenuEvent
* event
)
{
QPoint p = tree->mapFromGlobal(QCursor::pos());
if(tree->itemAt(p) != NULL)
{
QMenu* popMenu = new QMenu(this);
popMenu->addAction(insertItemAction);
popMenu->addAction(deleteItemAction);
popMenu->exec(QCursor::pos());
}
}
原因:我们认为的(0,0)点的坐标与实际的有差距
解决:使用viewport()返回的QWidget作为当前的坐标QWidget
QWidget * QAbstractScrollArea::viewport () const
修改后,代码:void
ShowItems::contextMenuEvent
(QContextMenuEvent
*event
)
{
QWidget *w = tree->viewport();
QPoint p = w->mapFromGlobal(QCursor::pos());
if(tree->itemAt(p) != NULL)
{
QMenu* popMenu = new QMenu(this);
popMenu->addAction(insertItemAction);
popMenu->addAction(deleteItemAction);
popMenu->exec(QCursor::pos());
}
}
相关文章推荐
- Qt:解决QListWidget/QTreeWidget选取Item不准确/偏移问题(右键菜单)
- Qt5 MySql驱动问题(qt和mysql各种小白问题亲测解决,若有相关问题可留言交流)
- 安装Qt及相关问题解决
- 我创建了一个托盘图标,可以正常使用,点击右键打开菜单。问题是如果点击右键后不选择其中一个菜单项进行操作的话,它就总不消失。
- 【原创】关于Winrar右键解压菜单失效问题的解决
- 解决VS2010中在项目上右键鼠标,无“添加STS引用”菜单的问题
- QT右键菜单及位置捕捉问题
- Qt5 MySql驱动问题(qt和mysql各种小白问题亲测解决,若有相关问题可留言交流)
- 俺的gVim配置文件(解决了菜单栏,右键菜单和提示框中文乱码问题)(for windows,linux下应该也没问题)
- 如何解决Qt 4GUI程序中动态创建内存的泄露问题
- 解决 qtcreator编辑*.ui文件时右键菜单不能正常显示但的问题
- 某些开发版中的Qt Designer菜单等中文显示为乱码问题解决方法初探
- 解决右键菜单没有新建的问题
- C#中解决zedgraph右键菜单的中文问题(转)
- maven创建webapp项目 相关问题解决
- Qt创建右键菜单的方法
- Windows 系统右键菜单假死问题解决一例
- [QT]创建鼠标右键菜单
- [转]QT右键菜单及位置捕捉问题
- Qt的右键菜单及位置捕捉问题