QMainWindow 動態切換菜單欄

QMainWindow 動態切換菜單欄

因爲種種原因,需要根據情況動態切換菜單欄。可以手動編碼,也可以使用 UI 類。使用 UI 類來實現的話更清晰些,每個菜單的功能代碼寫到各自的文件裏,主界面只負責切換就行,非常簡潔。

沒時間,就只貼代碼,不上圖了,腦補一下吧。示例工程樹如下:

  • Demo.pro
    • main.cpp
    • MainWindow.ui
    • MainWindow.h
    • MainWindow.cpp
      • MenuA.ui
      • MenuA.h
      • MenuA.cpp
      • MenuB.ui
      • MenuB.h
      • MenuB.cpp

MainWindow 中設置了兩個按鈕 pushButtonA 和 pushButtonB,分別與兩個槽關聯用於展示切換菜單功能。

MenuA 和 MenuB 是直接繼承於 QMenuBar 的界面類(別忘了修改 MenuA.ui 和 MenuB.ui)。在 MenuA 和 MenuB 中實現不同的菜單項和功能(可參考 附錄A 和 附錄B)。

基礎篇

MainWindow 中使用:

void QMainWindow::setMenuBar(QMenuBar *menuBar)

方法可以設置主窗口菜單欄。當爲主窗口設置新菜單欄時,會自動隱藏並刪除舊的菜單欄。因此最基本的動態切換菜單的方法如下:

/**
 @file MainWindow.cpp
 */

#include "MainWindow.h"
#include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButtonA_clicked()
{
    setMenuBar(new MenuA());
}

void MainWindow::on_pushButtonB_clicked()
{
    setMenuBar(new MenuB());
}

高級篇

上面每次切換菜單都會自動刪除上次菜單欄對象,然後再重新分配一個。但是有的項目需要這些對象從一開始就分配出來,並且不再被釋放。例如菜單有各自的狀態,在不同狀態下某些項目是禁能的,如果每次重新創建,就需要在其他地方記錄狀態,這使代碼變得複雜。有沒有辦法不進行重新分配呢?這樣每個菜單欄自己就可以記錄狀態。

通過分析 setMenuBar 方法,發現其會調用 oldMenuBar->deleteLater() 方法釋放舊的菜單欄對象。而 deleteLater() 主要是給自己發送 DeferredDelete 事件,然後在事件循環中釋放自己。因此我們可以重寫 MenuA 和 MenuB 的 event() 方法,來拒絕刪除操作,這樣每次 setMenuBar() 的時候都不會刪除舊的菜單欄,因此下次使用的時候也就不需要再重新分配了。參考代碼如下:

/**
 @file MenuA.h
 */
#ifndef MENUA_H
#define MENUA_H

#include <QMenuBar>

namespace Ui {
class MenuA;
}

class MenuA : public QMenuBar
{
    Q_OBJECT

public:
    explicit MenuA(QWidget *parent = 0);
    ~MenuA();

protected:
    bool event(QEvent *e) override;

private:
    Ui::MenuA *ui;
};

#endif // MENUA_H

看看 MenuA.cpp

/**
 @file MenuA.cpp
 */
#include "MenuA.h"
#include "ui_MenuA.h"

MenuA::MenuA(QWidget *parent) :
    QMenuBar(parent),
    ui(new Ui::MenuA)
{
    ui->setupUi(this);
}

MenuA::~MenuA()
{
    delete ui;
}

bool MenuA::event(QEvent *e)
{
    if(QEvent::DeferredDelete != e->type())
        return QMenuBar::event(e);

    return true;
}

MenuB 與 MenuA 這部分的處理一致,不再貼出了。MainWindow.h 中主要聲明瞭 MenuA 和 MenuB 的指針,用於效果展示。

/**
 @file MainWindow.h
 */
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "MenuA.h"
#include "MenuB.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButtonA_clicked();
    void on_pushButtonB_clicked();

private:
    Ui::MainWindow *ui;
    MenuA* MA;
    MenuB* MB;

};

#endif // MAINWINDOW_H

MainWindow.cpp 如下:

/**
 @file MainWindow.cpp
 */

#include "MainWindow.h"
#include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    MA = new MenuA();
    MB = new MenuB();
    setMenuBar(MA);
}

MainWindow::~MainWindow()
{
    delete MA;
    delete MB;
    delete ui;
}

void MainWindow::on_pushButtonA_clicked()
{
    setMenuBar(MA);
    MA->show();
}

void MainWindow::on_pushButtonB_clicked()
{
    setMenuBar(MB);
    MB->show();
}

注意:show() 方法一定要被調用,並且放在 setMenuBar() 方法之後。這是因爲 setMenuBar() 中還調用了 oldMenuBar 的 hide() 方法,如果不調用 show() 方法,菜單欄就會“消失不見”。

附錄

附錄A:MenuA.ui

MenuA.ui 實現了一個菜單 MenuA:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MenuA</class>
 <widget class="QMenuBar" name="MenuA">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="QMenu" name="menuA">
   <property name="title">
    <string>MenuA</string>
   </property>
  </widget>
  <addaction name="menuA"/>
 </widget>
 <resources/>
 <connections/>
</ui>

附錄B:MenuB.ui

MenuA.ui 實現了菜單 MenuB:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MenuB</class>
 <widget class="QMenuBar" name="MenuB">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="QMenu" name="menuB">
   <property name="title">
    <string>MenuB</string>
   </property>
  </widget>
  <addaction name="menuB"/>
 </widget>
 <resources/>
 <connections/>
</ui>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章