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