编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Qt自定义QMenuBar实现Ribbon

wxchong 2024-06-14 13:25:45 开源技术 10 ℃ 0 评论

Ribbon参考了开源项目:https://github.com/martijnkoopman/Qt-Ribbon-Widget

其代码保护3个功能8文件,实现了自定义QTabWidget添加按钮分组及按钮

代码如下:

TabContentGroup

#ifndef TABCONTENTGROUP_H
#define TABCONTENTGROUP_H

#include <QWidget>
#include <QToolButton>

namespace Ui {
class TabContentGroup;
}

class TabContentGroup : public QWidget
{
    Q_OBJECT

public:
    explicit TabContentGroup(QWidget *parent = nullptr);
    virtual ~TabContentGroup();

    void setTitle(const QString& title);
    QString getTitle() const;
    int buttonCount() const;
    void addButton(QToolButton* button);
    void removeButton(QToolButton* button);

private:
    Ui::TabContentGroup *ui;
    QString m_title;
};

#endif // TABCONTENTGROUP_H


实现

#include "tabcontentgroup.h"
#include "ui_tabcontentgroup.h"

TabContentGroup::TabContentGroup(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TabContentGroup),
    m_title("")
{
    ui->setupUi(this);
}

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

void TabContentGroup::setTitle(const QString& title)
{
    m_title = title;
    ui->groupName->setText(m_title);
}

QString TabContentGroup::getTitle() const
{
    return m_title;
}

int TabContentGroup::buttonCount() const
{
    return ui->groupHorizontalLayou->count();
}

void TabContentGroup::addButton(QToolButton* button)
{
    button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    button->setMaximumSize(48, 48);
    button->setAutoRaise(true);
    button->setIconSize(QSize(32, 32));
    button->setEnabled(true);
    button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);

    ui->groupHorizontalLayou->addWidget(button);
}

void TabContentGroup::removeButton(QToolButton* button)
{
    ui->groupHorizontalLayou->removeWidget(button);
}

ui文件参考原项目

TabContent

#ifndef TABCONTENT_H
#define TABCONTENT_H

#include <QWidget>
#include <QToolButton>

namespace Ui {
class TabContent;
}

class TabContent : public QWidget
{
    Q_OBJECT

public:
    explicit TabContent(QWidget *parent = nullptr);
    virtual ~TabContent();

    void addGroup(const QString& groupName);
    void removeGroup(const QString& groupName);
    int groupCount() const;
    void addButton(const QString& groupName, QToolButton* button);
    void removeButton(const QString& groupName, QToolButton* button);

private:
    Ui::TabContent *ui;
};

#endif // TABCONTENT_H

实现

#include "tabcontent.h"
#include "ui_tabcontent.h"
#include "tabcontentgroup.h"

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

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

void TabContent::addGroup(const QString& groupName)
{
    TabContentGroup* group = new TabContentGroup(this);
    group->setTitle(groupName);

    ui->tabContentHorizontalLayout->addWidget(group);
}

void TabContent::removeGroup(const QString& groupName)
{
    // 遍历分组,根据标题获取分组
    for (int i = 0; i < ui->tabContentHorizontalLayout->count(); i++)
    {
        TabContentGroup* group = static_cast<TabContentGroup*>(ui->tabContentHorizontalLayout->itemAt(i)->widget());
        if (group->getTitle().toLower() == groupName.toLower())
        {
            ui->tabContentHorizontalLayout->removeWidget(group);
            delete group;
            break;
        }
    }
}

int TabContent::groupCount() const
{
    return ui->tabContentHorizontalLayout->count();
}

void TabContent::addButton(const QString& groupName, QToolButton* button)
{
    TabContentGroup* tabGroup = nullptr;
    // 遍历分组,根据名称获取当前分组
    for (int i = 0; i < ui->tabContentHorizontalLayout->count(); i++)
    {
        TabContentGroup* group = static_cast<TabContentGroup*>(ui->tabContentHorizontalLayout->itemAt(i)->widget());
        if (group->getTitle().toLower() == groupName.toLower())
        {
            tabGroup = group;
            break;
        }
    }

    if (tabGroup == nullptr)
    {
        // 如果没找到,先添加分组
        addGroup(groupName);
        // 再添加按钮
        addButton(groupName, button);
    }
    else
    {
        // 如果找到了,直接添加按钮到分组
        tabGroup->addButton(button);
    }
}

void TabContent::removeButton(const QString& groupName, QToolButton* button)
{
    TabContentGroup* tabGroup = nullptr;
    // 遍历分组,根据名称获取当前分组
    for (int i = 0; i < ui->tabContentHorizontalLayout->count(); i++)
    {
        TabContentGroup* group = static_cast<TabContentGroup*>(ui->tabContentHorizontalLayout->itemAt(i)->widget());
        if (group->getTitle().toLower() == groupName.toLower())
        {
            tabGroup = group;
            break;
        }
    }

    if (tabGroup != nullptr)
    {
        // 如果找到了,则移除按钮
        tabGroup->removeButton(button);
        // 如果分组没有按钮了,则移除分组
        if (tabGroup->buttonCount() == 0)
        {
            removeGroup(groupName);
        }
    }
}

ui文件参考原项目

TabWidget

#ifndef TABWIDGET_H
#define TABWIDGET_H

#include <QTableWidget>
#include <QToolButton>
class TabWidget : public QTabWidget
{
    Q_OBJECT
public:
    TabWidget(QWidget* parent);

    void addTab(const QString& tabName);
    void addTab(const QIcon& tabIcon, const QString& tabName);
    void removeTab(const QString& tabName);
    void addGroup(const QString& tabName, const QString& groupName);
    void addButton(const QString& tabName, const QString& groupName, QToolButton* button);
    void removeButton(const QString& tabName, const QString& groupName, QToolButton* button);
};

#endif // TABWIDGET_H

实现

#include "tabwidget.h"
#include "tabcontent.h"

TabWidget::TabWidget(QWidget* parent) : QTabWidget(parent)
{

}

void TabWidget::addTab(const QString& tabName)
{
    TabContent* tabContent = new TabContent(this);

    QTabWidget::addTab(tabContent, tabName);
}

void TabWidget::addTab(const QIcon& tabIcon, const QString& tabName)
{
    TabContent* tabContent = new TabContent(this);
    QTabWidget::addTab(tabContent, tabIcon, tabName);
}

void TabWidget::removeTab(const QString& tabName)
{
    for (int i = 0; i < count(); i++)
    {
        if (tabText(i).toLower() == tabName.toLower())
        {
            QWidget* tab = QTabWidget::widget(i);
            QTabWidget::removeTab(i);
            delete tab;
            break;
        }
    }
}

void TabWidget::addGroup(const QString& tabName, const QString& groupName)
{
    QWidget* tab = nullptr;
    //遍历tab,根据名称获取当前tab
    for (int i = 0; i < count(); i++)
    {
        if (tabText(i).toLower() == tabName.toLower())
        {
            tab = QTabWidget::widget(i);
            break;
        }
    }

    if (tab == nullptr)
    {
        // 如果没找到,则添加tab
        addTab(tabName);
        // 再添加group
        addGroup(tabName, groupName);
    }
    else
    {
        // 如果找到了,则添加group
        TabContent* tabContent = static_cast<TabContent*>(tab);
        tabContent->addGroup(groupName);
    }
}

void TabWidget::addButton(const QString& tabName, const QString& groupName, QToolButton* button)
{
    QWidget* tab = nullptr;
    //遍历tab,根据名称获取当前tab
    for (int i = 0; i < count(); i++)
    {
        if (tabText(i).toLower() == tabName.toLower())
        {
            tab = QTabWidget::widget(i);
            break;
        }
    }

    if (tab == nullptr)
    {
        // 如果没找到,先添加tab
        addTab(tabName);
        // 再添加button
        addButton(tabName, groupName, button);
    }
    else
    {
        // 如果找到了,添加button到当前group
        TabContent* tabContent = static_cast<TabContent*>(tab);
        tabContent->addButton(groupName, button);
    }
}

void TabWidget::removeButton(const QString& tabName, const QString& groupName, QToolButton* button)
{
    QWidget* tab = nullptr;
    //遍历tab,根据名称获取当前tab
    for (int i = 0; i < count(); i++)
    {
        if (tabText(i).toLower() == tabName.toLower())
        {
            tab = QTabWidget::widget(i);
            break;
        }
    }


    if (tab != nullptr)
    {
        // 如果找到了,则移除按钮
        TabContent* tabContent = static_cast<TabContent*>(tab);
        tabContent->removeButton(groupName, button);
        // 如果分组下没有按钮了,则移除分组
        if (tabContent->groupCount() == 0)
        {
            tabContent->removeGroup(groupName);
        }
    }
}

自定义QMenuBar时,QtCreater的没法选择QMenuBar,可以把ui做好后,使用vscode把ui的基类改为QMenuBar。这个文件很简单,就是一个QMenuBar下面添加一个QTabWidget,并提升为TabWidget。

在QMainWindow中建立菜单时需要注意,由于需要tab, gourp, button 共3级,所以添加菜单时需要添加三级,既主菜单为一级,然后是子菜单第二级, 子菜单下再添加子菜单为第三级。

菜单添加好后在自定义QMenuBar中初始化tab

QMenuBar* menuBar = window->menuBar();
    // 菜单需要建3级,分别对应tab的标题, tab内的group的标题,以及tab内的button
    if (menuBar != nullptr)
    {
        // 第一级,用于tab的标题
        for (QAction* mainMenu : menuBar->actions())
        {
            QString tabName = mainMenu->text();
            QIcon tabIcon = mainMenu->icon();
            ui->tabWidget->addTab(tabIcon, tabName);
            QMenu* secondMenus = mainMenu->menu();
            if (!secondMenus->isEmpty())
            {
                // 第二级,用于tab内的group标题
                for (QAction* secondMenu : secondMenus->actions())
                {
                    QString groupName = secondMenu->text();
                    QMenu* thirdMenus = secondMenu->menu();
                    if (!thirdMenus->isEmpty())
                    {
                        for (QAction* thirdMenu : thirdMenus->actions())
                        {
                            QString buttonName = thirdMenu->text();
                            QToolButton* button = new QToolButton;
                            button->setText(buttonName);
                            button->setToolTip(buttonName);
                            button->setDefaultAction(thirdMenu);
                            ui->tabWidget->addButton(tabName, groupName, button);
                        }
                    }
                }
            }
            menuBar->removeAction(mainMenu);
        }
    }

完了后,可能需要点效果,就是类似word那样的双击显示或隐藏tab内容

QTabBar有个信号,:

voidQTabBar::tabBarDoubleClicked(intindex)

This signal is emitted when the user double clicks on a tab at index.

通过这个可以实现双击显示或隐藏,当然,还得加点动画效果

int startHeight;
    int endHeight;
    if (ui->tabWidget->currentWidget()->isHidden())
    {
        ui->tabWidget->currentWidget()->show();
        startHeight = TAB_MIN_HEIGHT;
        endHeight = TAB_MAX_HEIGHT;
    }
    else
    {
        ui->tabWidget->currentWidget()->hide();
        startHeight = TAB_MAX_HEIGHT;
        endHeight = TAB_MIN_HEIGHT;
    }

    QPropertyAnimation *animation = new QPropertyAnimation(this, "minimumHeight");
    animation->setDuration(200);
    animation->setStartValue(startHeight);
    animation->setEndValue(endHeight);
    animation->start();


完整代码:

#ifndef MENUBAR_H
#define MENUBAR_H

#include <QMenuBar>
#include <QMainWindow>

namespace Ui {
class MenuBar;
}

class MenuBar : public QMenuBar
{
    Q_OBJECT

public:
    explicit MenuBar(QWidget *parent = nullptr);
    ~MenuBar();
    void initMenuBar(QMainWindow* window);

private slots:
    void tabBarDoubleClicked(int index);

private:
    Ui::MenuBar *ui;
};

#endif // MENUBAR_H

实现

#include "menubar.h"
#include "ui_menubar.h"
#include <QAction>
#include <QMenu>
#include <QToolButton>
#include <QTabBar>
#include <QPropertyAnimation>
const int TAB_MAX_HEIGHT = 102;
const int TAB_MIN_HEIGHT = 38;

MenuBar::MenuBar(QWidget *parent) :
    QMenuBar(parent),
    ui(new Ui::MenuBar)
{
    ui->setupUi(this);
    setMinimumHeight(TAB_MAX_HEIGHT);

    connect(ui->tabWidget->tabBar(), &QTabBar::tabBarDoubleClicked, this, &MenuBar::tabBarDoubleClicked);
}

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

void MenuBar::initMenuBar(QMainWindow* window)
{
    QMenuBar* menuBar = window->menuBar();
    // 菜单需要建3级,分别对应tab的标题, tab内的group的标题,以及tab内的button
    if (menuBar != nullptr)
    {
        // 第一级,用于tab的标题
        for (QAction* mainMenu : menuBar->actions())
        {
            QString tabName = mainMenu->text();
            QIcon tabIcon = mainMenu->icon();
            ui->tabWidget->addTab(tabIcon, tabName);
            QMenu* secondMenus = mainMenu->menu();
            if (!secondMenus->isEmpty())
            {
                // 第二级,用于tab内的group标题
                for (QAction* secondMenu : secondMenus->actions())
                {
                    QString groupName = secondMenu->text();
                    QMenu* thirdMenus = secondMenu->menu();
                    if (!thirdMenus->isEmpty())
                    {
                        for (QAction* thirdMenu : thirdMenus->actions())
                        {
                            QString buttonName = thirdMenu->text();
                            QToolButton* button = new QToolButton;
                            button->setText(buttonName);
                            button->setToolTip(buttonName);
                            button->setDefaultAction(thirdMenu);
                            ui->tabWidget->addButton(tabName, groupName, button);
                        }
                    }
                }
            }
            menuBar->removeAction(mainMenu);
        }
    }
}

void MenuBar::tabBarDoubleClicked(int index)
{
    Q_UNUSED(index);
    int startHeight;
    int endHeight;
    if (ui->tabWidget->currentWidget()->isHidden())
    {
        ui->tabWidget->currentWidget()->show();
        startHeight = TAB_MIN_HEIGHT;
        endHeight = TAB_MAX_HEIGHT;
    }
    else
    {
        ui->tabWidget->currentWidget()->hide();
        startHeight = TAB_MAX_HEIGHT;
        endHeight = TAB_MIN_HEIGHT;
    }

    QPropertyAnimation *animation = new QPropertyAnimation(this, "minimumHeight");
    animation->setDuration(200);
    animation->setStartValue(startHeight);
    animation->setEndValue(endHeight);
    animation->start();
}

使用

MenuBar *menuBar = new MenuBar(this);
    menuBar->initMenuBar(this);
    setMenuBar(menuBar);

效果

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表