Qt之右键菜单实现

转载 2015年11月20日 10:50:25

最近在看C++ GUI  Qt4部分其中有个例子对于扩展一个应用程序提供一个上下文菜单。

Qt中的部件的弹出菜单(ContextMenu),依据ContextMenuPolicy的值的不同,有四种形式:
一、默认菜单
此时,ContextMenuPolicy的值为Qt::DefaultContextMenu,这是默认值,其将显示部件定义的默认菜单
二、无菜单
此时,ContextMenuPolicy的值为Qt::NoContextMenu
三、由Action定义菜单
此时,ContextMenuPolicy的值为Qt::ActionsContextMenu,要为此部件定义这种菜单,很简单,只要把已经定义好的Action部件插入到要显示此菜单的部件中,部件将自动按顺序显示菜单。
QWidget::addAction(QAction *action);
四、自定义菜单
此时,ContextMenuPolicy的值为Qt::CustomContextMenu,这回,有两种方式来定义菜单,一种是响应
customContextMenuRequested()这个signal,在响应的槽中显示菜单(QMenu的exec()方法)。第二种是需要从这个部件的类中派生一个类,重写contextMenuEvent()这个函数显示菜单(QMenu的exec()方法显示)。


第三种很简单:

void MainWidget::createContextMenu()
{
    this->addAction(m_exitAction);    
    this->setContextMenuPolicy(Qt::ActionsContextMenu);
}

下面介绍 第四种Qt::CustomContextMenu:

 

#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:
    QMenu* m_menu;
    QAction* m_exitAction;
    QAction* m_aboutAction;

private:
    void createAction();
    void createMenu();
    void createContextMenu();
private slots:
    void contextMenuSlot(QPoint p);
};

#endif // WIDGET_H

 

 

#include "widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    createAction();
    createMenu();
    createContextMenu();
    connect(this,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(contextMenuSlot(QPoint)));
}

Widget::~Widget()
{

}
void Widget::createAction()
{
    m_exitAction = new QAction("exit",this);
    connect(m_exitAction,SIGNAL(triggered()),qApp,SLOT(quit()));

    m_aboutAction = new QAction("about",this);
    connect(m_aboutAction,SIGNAL(triggered()),qApp,SLOT(aboutQt()));
}
void Widget::createMenu()
{
    m_menu = new QMenu(this);
    m_menu->addAction(m_exitAction);
    m_menu->addSeparator();
    m_menu->addAction(m_aboutAction);
}
void Widget::createContextMenu()
{

    this->setContextMenuPolicy(Qt::CustomContextMenu);//将contextMenuPolicy属性要设置为:CustomContextMenu,这步不能忘记,否则右键无反应。
}
void Widget::contextMenuSlot(QPoint p)
{
    m_menu->exec(this->mapToGlobal(p));
}


以QTreeWidget为例:

在Qt+VS2010下,使用slot函数customContextMenuRequested(QPointpos)实现Treewidget的右键菜单栏。

1、要在某一种窗体内添加右键菜单栏,比如在QTreeWidget中添加,可以用到slot函数customContextMenuRequested(QPointpos)。

在新建的customContextMenuRequested(QPointpos)函数中便可以实现具体的菜单栏了。

为了判断右键点击的位置,即点即不同的item节点,会出现不同的右键菜单,我们可以用API中itemAt()函数实现。

而为了给每个节点赋予不同的键值,可以通过setData()来实现。

在属性设置中,将contextMenuPolicy属性要设置为:CustomContextMenu,这步不能忘记,否则右键无反应。

我在TreeWidget中添加右键菜单的实现代码:

2、为Treewidget添加节点,通过setData()来为每个节点赋予不同的键值。

QTreeWidgetItem *root;    

root = new QTreeWidgetItem(ui->treeWidget, QStringList(QString("Connection")));

QVariant var0(0);

root->setData(0,Qt::UserRole,var0);

3、在slot函数中使用itemAt()函数获取当前被点击的节点,然后为不同的节点添加不同的菜单。

void MainWindow::on_treeWidget_customContextMenuRequested(QPoint pos)

{

    QTreeWidgetItem* curItem=ui->treeWidget->itemAt(pos);  //获取当前被点击的节点

    if(curItem==NULL)return;           //这种情况是右键的位置不在treeItem的范围内,即在空白位置右击

    QVariant var = curItem->data(0,Qt::UserRole);

    if(0 == var)      //data(...)返回的data已经在之前建立节点时用setdata()设置好      {

       QMenu *popMenu =new QMenu(this);//定义一个右键弹出菜单

       popMenu->addAction(ui->action_newDB);//往菜单内添加QAction   该action在前面用设计器定义了

       popMenu->addAction(ui->action_openDB);

       popMenu->addAction(ui->action_delDB);

       popMenu->exec(QCursor::pos());//弹出右键菜单,菜单位置为光标位置    }

    else

    {

        QMenu *popMenu =new QMenu(this);//定义一个右键弹出菜单

        popMenu->addAction(ui->action_newTable);//往菜单内添加QAction   该action在前面用设计器定义了

        popMenu->addAction(ui->action_openTable);

        popMenu->addAction(ui->action_designTable);

        popMenu->exec(QCursor::pos());//弹出右键菜单,菜单位置为光标位置    

   }

}

 //////////////////////////////////////////////////////////////////////////

但是更高级的是重新定义事件处理函数void contextMenuEvent(QContextMenuEvent *event)。下面讲解其contextMenuEvent(QContextMenuEvent *event)。

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 )函数。

例子(该例子即是我改写的)

[cpp] 

void MainWindow::contextMenuEvent(QContextMenuEvent *event)  

{  

   Context = new QMenu();  

   Context->addAction(ui->actionCut);  

   Context->addAction(ui->actionCope);  

   Context->addAction(ui->actionPase);  

   spreadsheet->setContextMenuPolicy(Qt::DefaultContextMenu);  

   Context->exec(QCursor::pos());  

}

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());
    }
}



Qt界面添加右键菜单

Qt中添加右键菜单其实很简单,只需在构造函数中加入以下代码即可: //Structure Widget显示右键菜单 QAction *newMenu = new QAction("新建",...
  • dcba2014
  • dcba2014
  • 2016年09月08日 11:06
  • 1589

Qt右键菜单的添加

鼠标事件是学习Qt必不可少的一个事件,初学者总是会忽略这一点,而右键菜单在平常的使用中更是常见,下面就Qt中添加右键菜单的几种方法做一简单的介绍: 1、鼠标事件添加/**重写鼠标处理器*/ void...
  • tax10240809163com
  • tax10240809163com
  • 2016年01月19日 10:54
  • 1059

qt 实现右键菜单

右键菜单实现:通过重写contextMenuEvent(QContextMenuEvent *event)事件,QMenu+QAction即可完美实现! 实现方式:createActions用于创建...
  • swartz_lubel
  • swartz_lubel
  • 2017年02月06日 23:17
  • 215

使用QT实现右击菜单实例

1.首先用QT设计师实现一个继承于QWidget的UI,然后我们拖一个treeWidget控件到主窗体中,注意treeWidget还有一个属性要设置,contextMenuPolicy属性要设置为:C...
  • MyCodingLine
  • MyCodingLine
  • 2016年02月16日 13:13
  • 1354

在TreeView中增加右键菜单功能

实现代码如下: //头文件中申明; QMenu *m_grpMenu; QMenu *m_memberMenu; QMenu *m_addAreaMenu; Q...
  • liukang325
  • liukang325
  • 2014年04月01日 15:16
  • 3987

Qt学习之QPushButton添加右键菜单

  • 2016年03月19日 12:25
  • 8KB
  • 下载

给QTreeWidget添加右键菜单功能

1、在包含有QTreeWidget的窗体中添加customContextMenuRequested的信号处理,同时要添加setContextMenuPolicy(Qt::CustomContextMe...
  • wuli2496
  • wuli2496
  • 2015年03月17日 23:18
  • 2895

Qt添加右键菜单的方法

在Qt中QWidget控件以及其子类都可以添加右键菜单,Qt中所有界面上显示的控件基本都继承自QWidget控件,所以基本上Qt中的控件都可以添加右键菜单,下面举例说明为按钮添加右键菜单的方法: . ...
  • cqltbe131421
  • cqltbe131421
  • 2017年06月16日 10:41
  • 638

Qt学习之给QPushButton添加菜单CustomContextMenu方法

上篇也说了,题目虽然说是给QPushButton添加鼠标右键菜单,其实对于所有的QWidget都是适用的。之所以说QPushButton,是以QPushButton为例进行实现,写的类继承自QPush...
  • u011417605
  • u011417605
  • 2016年03月19日 12:58
  • 4835

QT 鼠标右键菜单

QWidget及其子类都可有右键菜单,因为QWidget有以下两个与右键菜单有关的函数: Qt::ContextMenuPolicy contextMenuPolicy () const ...
  • TJU355
  • TJU355
  • 2012年06月11日 14:13
  • 15765
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Qt之右键菜单实现
举报原因:
原因补充:

(最多只允许输入30个字)