
如果想要在某一窗口中顯示右鍵菜單, 其處理方式大體上有兩種, 這兩種方式分別為基于鼠標(biāo)事件實(shí)現(xiàn)和基于窗口的菜單策略實(shí)現(xiàn)。其中第二種方式中又有三種不同的實(shí)現(xiàn)方式, 因此如果想要在窗口中顯示一個(gè)右鍵菜單一共四種實(shí)現(xiàn)方式, 下面依次為大家講解…1. 基于鼠標(biāo)事件實(shí)現(xiàn)1.1 實(shí)現(xiàn)思路使用這種方式實(shí)現(xiàn)右鍵菜單的顯示需要使用事件處理器函數(shù), 在Qt中這類函數(shù)都是回調(diào)函數(shù), 并且在自定義窗口類中我們還可以自定義事件處理器函數(shù)的行為因?yàn)樽宇惱^承了父類的這個(gè)方法并且這類函數(shù)是虛函數(shù)。實(shí)現(xiàn)步驟如下在當(dāng)前窗口類中重寫鼠標(biāo)操作相關(guān)的的事件處理器函數(shù)有兩個(gè)可以選擇// 以下兩個(gè)事件二選一即可, 只是事件函數(shù)被調(diào)用的時(shí)機(jī)不同罷了 // 這個(gè)時(shí)機(jī)對(duì)右鍵菜單的顯示沒有任何影響 [virtual protected] void QWidget::mousePressEvent(QMouseEvent *event); [virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event);在數(shù)據(jù)表事件處理器函數(shù)內(nèi)部判斷是否按下了鼠標(biāo)右鍵如果按下了鼠標(biāo)右鍵創(chuàng)建菜單對(duì)象(也可以提前先創(chuàng)建處理), 并將其顯示出來// 關(guān)于QMenu類型的菜單顯示需要調(diào)用的 API // 參數(shù) p 就是右鍵菜單需要顯示的位置, 這個(gè)坐標(biāo)需要使用屏幕坐標(biāo) // 該位置坐標(biāo)一般通過調(diào)用 QCursor::pos() 直接就可以得到了 QAction *QMenu::exec(const QPoint p, QAction *action nullptr);1.2 代碼實(shí)現(xiàn)在頭文件中添加要重寫的鼠標(biāo)事件處理器函數(shù)聲明, 這里使用的是 mousePressEvent()// mainwindow.h #include QMainWindow namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent 0); ~MainWindow(); protected: // 鼠標(biāo)按下, 該函數(shù)被Qt框架調(diào)用, 需要重寫該函數(shù) void mousePressEvent(QMouseEvent *event); private: Ui::MainWindow *ui; };在源文件中重寫從父類繼承的虛函數(shù)mousePressEvent()// mainwindow.cpp void MainWindow::mousePressEvent(QMouseEvent *event) { // 判斷用戶按下的是哪一個(gè)鼠標(biāo)鍵 if(event-button() Qt::RightButton) { // 彈出一個(gè)菜單, 菜單項(xiàng)是 QAction 類型 QMenu menu; QAction* act menu.addAction(C); connect(act, QAction::triggered, this, []() { QMessageBox::information(this, title, 您選擇的是C...); }); menu.addAction(Java); menu.addAction(Python); menu.exec(QCursor::pos()); // 右鍵菜單被模態(tài)顯示出來了 } }2. 基于窗口的菜單策略實(shí)現(xiàn)這種方式是使用 Qt 中 QWidget類中的右鍵菜單函數(shù) QWidget::setContextMenuPolicy(Qt::ContextMenuPolicy policy) 來實(shí)現(xiàn), 因?yàn)檫@個(gè)函數(shù)的參數(shù)可以指定不同的值, 因此不同參數(shù)對(duì)應(yīng)的具體的實(shí)現(xiàn)方式也不同。這個(gè)函數(shù)的函數(shù)原型如下// 函數(shù)原型: void QWidget::setContextMenuPolicy(Qt::ContextMenuPolicy policy); 參數(shù): - Qt::NoContextMenu -- 不能實(shí)現(xiàn)右鍵菜單 - Qt::PreventContextMenu -- 不能實(shí)現(xiàn)右鍵菜單 - Qt::DefaultContextMenu -- 基于事件處理器函數(shù) QWidget::contextMenuEvent() 實(shí)現(xiàn) - Qt::ActionsContextMenu -- 添加到當(dāng)前窗口中所有 QAction 都會(huì)作為右鍵菜單項(xiàng)顯示出來 - Qt::CustomContextMenu -- 基于 QWidget::customContextMenuRequested() 信號(hào)實(shí)現(xiàn)2.1 Qt::DefaultContextMenu使用這個(gè)策略實(shí)現(xiàn)右鍵菜單, 需要借助窗口類從父類繼承的虛函數(shù)QWidget::contextMenuEvent()并重寫它來實(shí)現(xiàn)。要做的第一步是在窗口類的頭文件中添加這個(gè)函數(shù)的聲明// mainwindow.h #include QMainWindow namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent 0); ~MainWindow(); protected: // 如果窗口設(shè)置了 Qt::DefaultContextMenu 策略, // 點(diǎn)擊鼠標(biāo)右鍵該函數(shù)被Qt框架調(diào)用 void contextMenuEvent(QContextMenuEvent *event); private: Ui::MainWindow *ui; };第二步在這個(gè)窗口類的構(gòu)造函數(shù)設(shè)置右鍵菜單策略// mainwindow.cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui-setupUi(this); // 給窗口設(shè)置策略: Qt::DefaultContextMenu // 在窗口中按下鼠標(biāo)右鍵, 這個(gè)事件處理器函數(shù)被qt框架調(diào)用 QWidget::contextMenuEvent() setContextMenuPolicy(Qt::DefaultContextMenu); }第三步在這個(gè)窗口類的源文件中重寫事件處理器函數(shù) contextMenuEvent()// mainwindow.cpp void MainWindow::contextMenuEvent(QContextMenuEvent *event) { // 彈出一個(gè)菜單, 菜單項(xiàng)是 QAction 類型 QMenu menu; QAction* act menu.addAction(C); connect(act, QAction::triggered, this, []() { QMessageBox::information(this, title, 您選擇的是C...); }); menu.addAction(Java); menu.addAction(Python); menu.exec(QCursor::pos()); // 右鍵菜單被模態(tài)顯示出來了 }2.2 Qt::ActionsContextMenu使用這個(gè)策略實(shí)現(xiàn)右鍵菜單, 是最簡(jiǎn)單的一種, 我們只需要?jiǎng)?chuàng)建一些 QAction類型的對(duì)象并且將他們添加到當(dāng)前的窗口中, 當(dāng)我們?cè)诖翱谥悬c(diǎn)擊鼠標(biāo)右鍵這些QAction類型的菜單項(xiàng)就可以顯示出來了。雖然這種方法比較簡(jiǎn)單但是它有一定的局限性就是在一個(gè)窗口中不能根據(jù)不同的需求制作不同的右鍵菜單這種方式只能得到一個(gè)唯一的右鍵菜單。相關(guān)的處理代碼如下// mainwindow.cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui-setupUi(this); // 只要將某個(gè)QAction添加給對(duì)應(yīng)的窗口, 這個(gè)action就是這個(gè)窗口右鍵菜單中的一個(gè)菜單項(xiàng)了 // 在窗口中點(diǎn)擊鼠標(biāo)右鍵, 就可以顯示這個(gè)菜單 setContextMenuPolicy(Qt::ActionsContextMenu); // 給當(dāng)前窗口添加QAction對(duì)象 QAction* act1 new QAction(C); QAction* act2 new QAction(Java); QAction* act3 new QAction(Python); this-addAction(act1); this-addAction(act2); this-addAction(act3); connect(act1, QAction::triggered, this, []() { QMessageBox::information(this, title, 您選擇的是C...); }); }2.3 Qt::CustomContextMenu使用這個(gè)策略實(shí)現(xiàn)右鍵菜單, 當(dāng)點(diǎn)擊鼠標(biāo)右鍵窗口會(huì)產(chǎn)生一個(gè) QWidget::customContextMenuRequested() 信號(hào)注意僅僅只是發(fā)射信號(hào)意味著要自己寫顯示右鍵菜單的槽函數(shù)slot這個(gè)信號(hào)是QWidget唯一與右鍵菜單有關(guān)的信號(hào)。我們先來看一下這個(gè)信號(hào)的函數(shù)原型:// 注意: 信號(hào)中的參數(shù)pos為當(dāng)前窗口的坐標(biāo)并非屏幕坐標(biāo)右鍵菜單顯示需要使用屏幕坐標(biāo) [signal] void QWidget::customContextMenuRequested(const QPoint pos)代碼實(shí)現(xiàn)也比較簡(jiǎn)單, 如下所示:// mainwindow.cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui-setupUi(this); // 策略 Qt::CustomContextMenu // 當(dāng)在窗口中點(diǎn)擊鼠標(biāo)右鍵, 窗口會(huì)發(fā)出一個(gè)信號(hào): QWidget::customContextMenuRequested() // 對(duì)應(yīng)發(fā)射出的這個(gè)信號(hào), 需要添加一個(gè)槽函數(shù), 用來顯示右鍵菜單 this-setContextMenuPolicy(Qt::CustomContextMenu); connect(this, MainWindow::customContextMenuRequested, this, [](const QPoint pos) { // 參數(shù) pos 是鼠標(biāo)按下的位置, 但是不能直接使用, 這個(gè)坐標(biāo)不是屏幕坐標(biāo), 是當(dāng)前窗口的坐標(biāo) // 如果要使用這個(gè)坐標(biāo)需要將其轉(zhuǎn)換為屏幕坐標(biāo) QMenu menu; QAction* act menu.addAction(C); connect(act, QAction::triggered, this, []() { QMessageBox::information(this, title, 您選擇的是C...); }); menu.addAction(Java); menu.addAction(Python); // menu.exec(QCursor::pos()); // 將窗口坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo) QPoint newpt this-mapToGlobal(pos); menu.exec(newpt); }); }在上邊的程序中, 我們通過窗口發(fā)射的信號(hào)得到了一個(gè)坐標(biāo)類型的參數(shù), 大家一定要注意這個(gè)坐標(biāo)是當(dāng)前窗口的窗口坐標(biāo), 不是屏幕坐標(biāo), 顯示右鍵菜單需要使用屏幕坐標(biāo)。對(duì)應(yīng)這個(gè)坐標(biāo)的處理可以有兩種方式棄用選擇使用 QCursor::pos() 得到光標(biāo)在屏幕的坐標(biāo)位置坐標(biāo)轉(zhuǎn)換, 將窗口坐標(biāo)轉(zhuǎn)換為屏幕坐標(biāo), 這里用到了一個(gè)函數(shù) mapToGlobal// 參數(shù)是當(dāng)前窗口坐標(biāo), 返回值為屏幕坐標(biāo) QPoint QWidget::mapToGlobal(const QPoint pos) const;不管使用以上哪種方式顯示右鍵菜單, 顯示出來之后的效果是一樣的最后如果想要讓自己的右鍵菜單項(xiàng)顯示圖標(biāo), 可以調(diào)用這個(gè)函數(shù)// 只顯示文本字符串 QAction *QMenu::addAction(const QString text); // 可以顯示圖標(biāo) 文本字符串 QAction *QMenu::addAction(const QIcon icon, const QString text);