Qt学习—qt上下文菜单显示
Qwidget类及其子类都具有右键菜单响应功能,QWidget类提供了以下两个与右键菜单有关的函数:
1、 Qt::ContextMenuPolicy contextMenuPolicy()const
该函数用来获取控件上下文菜单项的显示策略。其返回值Qt::ContextMenuPolicy是枚举类型。
2、 void setContextMenuPolicy(Qt::ContextMenuPolicy policy )
该函数用来设置控件上下文菜单项的显示策略。其参数Qt::ContextMenuPolicy是枚举类型。
Qt::ContextMenuPolicy枚举类型定义的上下文菜单的显示策略如下:
① Qt::NoContextMenu(当前控件不支持上下文菜单功能,但具有请求路由功能)
该策略表示,当前控件没有上下文菜单显示功能,但是具有上下文菜单显示请求路由功能。即当用户在该控件上请求上下文菜单时(如单击鼠标右键),虽然当前控件没有显示上下文菜单的功能,但是可以将该请求路由给其父类处理。如果其父类的上下文菜单显示策略支持,则显示父类的上下文菜单,如果不支持,则不显示任何菜单。
② Qt::PreventContextMenu(当前控件不支持上下文菜单功能,也不具备请求路由功能)
该策略表示,当前控件没有上下文菜单显示功能,同时也不具备上下文菜单显示请求路由功能。即如果当前控件的上下文菜单显示策略被设置为该策略时,则上下文菜单显示请求仅由该控件处理,不会将显示请求路由给其他任何父类,则最终效果为,忽略用户的上下文菜单显示请求,不显示任何菜单。
③ Qt::DefaultContextMenu(当前控件支持上下文菜单功能,由上下文菜单事件函数响应用户请求)
该策略为默认的上下文菜单显示策略。当没有显式设定控件的上下文菜单显示策略时,默认为该策略。当用户在控件上请求上下文菜单时,显示请求会交由QWidget::contextMenuEvent( QContextMenuEvent *event)函数处理。(上下文菜单事件函数)
QWidget::contextMenuEvent( QContextMenuEvent *event)
该函数是一个虚函数,在子类中重写该函数,以实现子控件显示上下文菜单的功能。该函数是虚函数,所以只是提供了响应用户请求的接口,上下文菜单的具体实现需要自己编写。
构造函数中设置上下文菜单的显示策略
MainWindow::MainWindow(QWidget*parent): QMainWindow(parent), ui(newUi::MainWindow)
{
ui->setupUi(this);
QObject::connect(ui->saveScreenButton,SIGNAL(clicked()),this,SLOT(savepicture()));
QObject::connect(ui->exitButton,SIGNAL(clicked()),this,SLOT(exit()));
//设置上下文菜单项的显示策略
ui->label_picture->setContextMenuPolicy(Qt::DefaultContextMenu);
}
上下文菜单响应事件函数中,构造菜单并显示菜单
voidMainWindow::contextMenuEvent(QContextMenuEvent*event)
{
//判断鼠标右键点击的位置是否在ui->label_picture控件的范围内
//通过ui->label_picture控件的左上角点和右下角点的坐标判定
if(ui->label_picture->mapFromGlobal(QCursor::pos()).x()>=
ui->label_picture->rect().topLeft().x()&&
ui->label_picture->mapFromGlobal(QCursor::pos()).y()>=
ui->label_picture->rect().topLeft().y()&&
ui->label_picture->mapFromGlobal(QCursor::pos()).x()<=
ui->label_picture->rect().bottomRight().x()&&
ui->label_picture->mapFromGlobal(QCursor::pos()).y()<=
ui->label_picture->rect().bottomRight().y()
)
{
QMenu*menu=newQMenu(this); //创建上下文菜单
QAction*Act_Saveas=newQAction(this); //新建菜单项
QAction*Act_Process=newQAction(this); //新建菜单项
Act_Saveas->setText("另存为"); //设置菜单项文本
Act_Process->setText("启动记事本"); //设置菜单项文本
//设定菜单项的信号与槽
QObject::connect(Act_Saveas,SIGNAL(triggered()),this,SLOT(savepicture()));
QObject::connect(Act_Process,SIGNAL(triggered()),this,SLOT(startprocess()));
menu->addAction(Act_Saveas); //添加菜单项
menu->addSeparator(); //添加菜单项分隔线
menu->addAction(Act_Process); //添加菜单项
menu->exec(QCursor::pos()); //在鼠标右键单击位置处创建并执行上下文菜单
}
}
注意:当上下文菜单的显示策略为Qt::DefaultContextMenu时,菜单项(action)是加载到菜单(menu)中,借助菜单显示出来的。
④Qt::ActionsContextMenu(当前控件支持上下文菜单功能,菜单项的显示不依托菜单)
该策略表示,将该控件上所支持的所有菜单项(action)作为一个上下文菜单显示出来。为了理解更清楚,和典型的上下文菜单做一下对比。
对于典型的上下文菜单来说,一般是新建一个菜单(menu),然后在新建一个活多个菜单项(action),之后将所有的菜单项(action)加载到菜单(menu)中,最后通过执行菜单的QMenu::exec()函数来显示整个上下文菜单。即,菜单是菜单项的载体,所有的菜单项(action)通过菜单(menu)得以显示。
如果某一控件的上下文菜单显示策略设置为Qt::ActionsContextMenu的话,则可以省略菜单(menu)这一载体。因为所有的控件都是由QWidget类继承而来,QWidget类提供了QWidget::addAction(QAction *action)函数来加载菜单项(action)。所以,使用该策略时,首先新建若干菜单项(action),之后通过控件(QWidget的子类)的addAction(QAction *action)函数来加载所有的菜单项到控件上,最后设置显示策略为Qt::ActionsContextMenu。当用户请求显示上下文菜单时,所有菜单项就会作为一个菜单(menu)显示出来。
构造函数中设置上下文菜单的显示策略
MainWindow::MainWindow(QWidget*parent): QMainWindow(parent), ui(newUi::MainWindow)
{
ui->setupUi(this);
QObject::connect(ui->saveScreenButton,SIGNAL(clicked()),this,SLOT(savepicture()));
QObject::connect(ui->exitButton,SIGNAL(clicked()),this,SLOT(exit()));
//设置上下文菜单项的显示策略
ui->label_picture->setContextMenuPolicy(Qt::ActionsContextMenu);
}
上下文菜单响应事件函数中,构造菜单并显示菜单
voidMainWindow::contextMenuEvent(QContextMenuEvent*event)
{
//判断鼠标右键点击的位置是否在ui->label_picture控件的范围内
//通过ui->label_picture控件的左上角点和右下角点的坐标判定
if(ui->label_picture->mapFromGlobal(QCursor::pos()).x()>=
ui->label_picture->rect().topLeft().x()&&
ui->label_picture->mapFromGlobal(QCursor::pos()).y()>=
ui->label_picture->rect().topLeft().y()&&
ui->label_picture->mapFromGlobal(QCursor::pos()).x()<=
ui->label_picture->rect().bottomRight().x()&&
ui->label_picture->mapFromGlobal(QCursor::pos()).y()<=
ui->label_picture->rect().bottomRight().y()
)
{
QAction*Act_Saveas=newQAction(this); //新建菜单项
QAction*Act_Process=newQAction(this); //新建菜单项
Act_Saveas->setText("另存为"); //设置菜单项文本
Act_Process->setText("启动记事本"); //设置菜单项文本
//设定菜单项的信号与槽
QObject::connect(Act_Saveas,SIGNAL(triggered()),this,SLOT(savepicture()));
QObject::connect(Act_Process,SIGNAL(triggered()),this,SLOT(startprocess()));
//直接将菜单项加载到控件上
ui->label_picture->addAction(Act_Saveas);
ui->label_picture->addAction(Act_Process);
}
}
注意:当上下文菜单的显示策略为Qt::ActionsContextMenu时,菜单项(action)是直接加载到控件上,以列表的形式显示出来的。当然也可以借助菜单显示出来的。
⑤ Qt::CustomContextMenu
该策略表示,当前控件可以支持上下文菜单。和其他显示策略不同的是,该策略完全由用户自己定制,即应用程序没有提供默认的接口函数,仅仅只提供了信号函数,注意仅仅只是发信号,意味着要自己写显示右键菜单的SLOT槽函数。该信号的发出条件是:用户请求contextMenu(常规就是鼠标右击)且同时被击的widget其上下文菜单显示策略contextMenuPolicy被设置为Qt::CustomContextMenu。
void QWidget::customContextMenuRequested (const QPoint & pos )[signal]
这个信号是QWidget唯一与右键菜单有关的信号(也是自有的唯一信号),同时也是很容易被忽略的signal。
注意:pos是该widget接收右键菜单事件的位置,一般是在该控件的坐标系中。但是对于QAbstratScrollArea及其子类例外,是对应着其视口viewport()的坐标系。如常用的QTableView、QHeaderView就是QAbstratScrollArea的子类。
构造函数中设置上下文菜单的显示策略
MainWindow::MainWindow(QWidget*parent): QMainWindow(parent), ui(newUi::MainWindow)
{
ui->setupUi(this);
QObject::connect(ui->saveScreenButton,SIGNAL(clicked()),this,SLOT(savepicture()));
QObject::connect(ui->exitButton,SIGNAL(clicked()),this,SLOT(exit()));
QObject::connect(ui->label_picture,SIGNAL(customContextMenuRequested(constQPoint&)),
this,SLOT(slot_contextmenu(constQPoint&)));
//设置上下文菜单项的显示策略
ui->label_picture->setContextMenuPolicy(Qt::CustomContextMenu);
}
自定义上下文菜单响应事件函数中,构造菜单并显示菜单
voidMainWindow::slot_contextmenu(constQPoint&pos)
{
QPointpoint=ui->label_picture->mapTo(ui->label_picture,pos);
//判断鼠标右键点击的位置是否在ui->label_picture控件的范围内
//通过ui->label_picture控件的左上角点和右下角点的坐标判定
if(point.x()>=ui->label_picture->rect().topLeft().x()&&
point.y()>=ui->label_picture->rect().topLeft().y()&&
point.x()<=ui->label_picture->rect().bottomRight().x()&&
point.y()<=ui->label_picture->rect().bottomRight().y()
)
{
QMenu*menu=newQMenu(this); //创建上下文菜单
QAction*Act_Saveas=newQAction(this); //新建菜单项
QAction*Act_Process=newQAction(this); //新建菜单项
Act_Saveas->setText("另存为"); //设置菜单项文本
Act_Process->setText("启动记事本"); //设置菜单项文本
//设定菜单项的信号与槽
QObject::connect(Act_Saveas,SIGNAL(triggered()),this,SLOT(savepicture()));
QObject::connect(Act_Process,SIGNAL(triggered()),this,SLOT(startprocess()));
menu->addAction(Act_Saveas); //添加菜单项
menu->addSeparator(); //添加菜单项分隔线
menu->addAction(Act_Process); //添加菜单项
menu->exec(QCursor::pos()); //在鼠标右键单击位置处创建并执行上下文菜单
//menu->exec(pos);//是在viewport显示
}
}
注意:当上下文菜单的显示策略为Qt:: CustomContextMenu时,默认的上下文菜单响应函数已经不在起作用了,需要编程人员重新编写响应函数,并在构造函数中指定响应的信号和槽的连接。
坐标变换函数
1、全局坐标系
从屏幕的左上角起,向右为X轴正向,向下为Y轴正向。屏幕坐标系是绝对坐标系。点的位置在屏幕上发生变化时,点的坐标值会发生相应的变化。坐标点的值是相对于屏幕左上角的绝对坐标值。
2、控件坐标系
从控件的左上角起,向右为X轴正向,向下为Y轴正向。控件坐标系是相对坐标系。控件的位置相对屏幕发生变化时,只要保持点相对于控件的位置不发生变化,则虽然点的位置在屏幕坐标系中发生了变化,但是点的坐标值不会改变。点的坐标值是相对于控件左上角的绝对坐标值。
① QPoint QWidget::mapFrom ( QWidget * parent, const QPoint & pos) const
将点pos在parent控件上的坐标值转换为当前控件坐标系的坐标值。例如:
ui->label_picture->mapFrom(ui->newScreenButton,pos);
pos表示点在ui->newScreenButton控件上的坐标值,ui->label_picture控件调用mapFrom()函数将pos的坐标值转换为点在ui->label_picture
② QPoint QWidget::mapFromGlobal (const QPoint & pos ) const
将点pos在全局坐标系上的坐标值转换为当前控件坐标系的坐标值。例如:
ui->label_picture->mapFromGlobal(QCursor::pos());
QCursor::pos() 函数用来获得鼠标单击点的全局位置
③ QPoint QWidget::mapFromParent (const QPoint & pos ) const
将点pos在父控件坐标系上的坐标值转换为当前控件坐标系的坐标值。例如:
ui->label_picture->mapFromParent(pos);
④ QPoint QWidget::mapTo ( QWidget * parent, const QPoint & pos ) const
将点pos在当前控件坐标系的坐标值转换为parent控件上的坐标值。
ui->label_picture->mapTo(ui->newScreenButton,pos); //此时pos的为label_picture下的坐标值
⑤ QPoint QWidget::mapToGlobal (const QPoint & pos ) const
将点pos在当前控件坐标系的坐标值转换为全局坐标系上的坐标值。
ui->label_picture->mapToParent(pos); //此时pos的为label_picture下的坐标值
⑥ QPoint QWidget::mapToParent (const QPoint & pos ) const
将点pos在当前控件坐标系的坐标值转换为父控件坐标系上的坐标值。
ui->label_picture->mapToParent(pos); //此时pos的为label_picture下的坐标值