C++QT侧边菜单栏

效果预览

Qt顶部菜单栏的实用性和美观上会打不小的折扣,因此需要自行写一些组件以适应项目需求。

image

主界面布局

主界面的布局采用的是aside + main 的形式,使用QT自带的splitter进行左右分割即可。
image

实现代码:

void MXGMainWindow::init()
{
    // 设置窗口最小大小为1000x700
    this->setMinimumSize(QSize(1000, 700));
    // 启用样式表对窗口背景的控制
    this->setAttribute(Qt::WA_StyledBackground, true);
    // 设置窗口标题为"musicPlayer"
    this->setWindowTitle(tr("demo_menu"));
    // 设置窗口图标
    this->setWindowIcon(QIcon(QString::fromUtf8(":/res/logo.svg")));
    // 设置窗口的样式表为蓝色背景
    QString styleSheet = QString("background-color: #2177B8");
    this->setStyleSheet(styleSheet);

    /* 侧边栏设置 */
    // 创建左侧边栏容器
    sidebarWidget = new Menu;
    // 创建透明效果SidebarWidget
    auto *opacityEffect = new QGraphicsOpacityEffect();
    // 设置透明度为0.9(90%不透明)
    opacityEffect->setOpacity(0.9);
    // 应用透明度效果
    sidebarWidget->setGraphicsEffect(opacityEffect);

    /* 主内容容器设置 */
    // 创建内容布局
    auto *contentLayout = new QVBoxLayout;

    // 创建内容容器
    content = new QWidget;
    contentLayout->addWidget(qStackedWidget);  // 添加qStackedWidget到content
    content->setLayout(contentLayout);         // 设置content的布局为contentLayout

    // 创建页面左右分割QSplitter控件,分割左侧边栏和主内容容器
    QSplitter *splitter = createVerticalSplitter(this, sidebarWidget, content,
                                                 Qt::Horizontal, 200, 600);

	auto *layout = new QVBoxLayout;
    // 将分割窗口添加到主布局中
    layout->addWidget(splitter);

    // 设置整个窗口的布局为主布局
    this->setLayout(layout);
}

QSplitter* MXGMainWindow::createVerticalSplitter(QWidget *parent, QWidget *content1, QWidget *content2,
                                        Qt::Orientation orientation, int size1, int size2) {
    // 创建右边页面的QSplitter控件
    auto *splitter = new QSplitter(orientation, parent);
    splitter->addWidget(content1);                          // 添加左侧边栏到分割窗口中
    splitter->addWidget(content2);                          // 添加内容容器到分割窗口中
    // 设置初始高度
    splitter->setSizes(QList<int>() << size1 << size2);
    // 获取分割窗口的句柄
    QSplitterHandle *splitterHandle1 = splitter->handle(1);  // 获取右侧部分的句柄
    // 设置句柄样式,并禁用拖动功能
    splitterHandle1->setEnabled(false);

    return splitter;
}

侧边菜单栏页面设置

image image
侧边栏采用的是这种竖直方向的排布 (按钮图标及文字仅供参考)

void Menu::init()
{
    auto *layout = new QVBoxLayout;

    // 设置标题
    titleLabel->setText(tr("     menu"));
    titleLabel->setAlignment(Qt::AlignCenter);
    titleLabel->setFixedHeight(40);
    titleLabel->setStyleSheet("background-color: #A0A083;"
                             "border-radius: 7px;");
    titleLabel->setStyleSheet("color: white;");
    titleLabel->setFont(QFont("Microsoft YaHei", 12, QFont::Bold));

    // 创建最小化按钮
    minimizeButton->setFixedSize(35, 35);
    minimizeButton->setStyleSheet("background-color: #A0A083;"
                                 "border-radius: 7px;");
    setPushButton(minimizeButton, QString::fromUtf8(":/res/vehicle.svg"), "");
    minimizeButton->setFlat(true);

    auto *titleLayout = new QHBoxLayout;
    titleLayout->addWidget(titleLabel);
    titleLayout->addWidget(minimizeButton);

    layout->addLayout(titleLayout);

    // 创建菜单栏按钮控件
    setPushButton(newPage1Btn, QString::fromUtf8(":/res/taxi.svg"), tr("First page"));
    setPushButton(newPage2Btn, QString::fromUtf8(":/res/RetroStingyCar.svg"), tr("Second page"));
    setPushButton(newPage3Btn, QString::fromUtf8(":/res/CartoonTaxi.svg"), tr("Third page"));

    // 创建按钮组
    buttonGroup.addButton(newPage1Btn, 1);
    buttonGroup.addButton(newPage2Btn, 2);
    buttonGroup.addButton(newPage3Btn, 3);

    // 使用样式表设置控件的背景透明和高度增加 字体设置
    QFont font("Microsoft YaHei", 10);              // 创建字体,指定字体名称和字体大小
    font.setPointSizeF(font.pointSizeF() * 1.25);                    // 将字体大小放大1.25倍

    foreach(QAbstractButton *b, buttonGroup.buttons()) {
        b->setStyleSheet("background-color: transparent;"
                             "opacity: 0;"
                             "border-radius: 7px;");
        // 设置按钮的高度和字体
        b->setFixedHeight(40);
        b->setFont(font);
    }

    // 设置第一个按钮为默认选中状态
    if (QAbstractButton *firstButton = buttonGroup.button(1)) {
        firstButton->setChecked(true);
        onButtonClicked(1);
    }

    // 创建布局
    layout->addWidget(newPage1Btn);
    layout->addWidget(newPage2Btn);
    layout->addWidget(newPage3Btn);

    // 添加一个竖直方向的额弹簧
    auto *spacer = new QSpacerItem(10, 10, QSizePolicy::Minimum, QSizePolicy::Expanding);
    layout->addItem(spacer);
    // 设置布局
    this->setLayout(layout);
}

void Menu::setPushButton(QPushButton *button, const QString& url, const QString& text)
{
    // 设置按钮的文字和图标
    button->setText(text);
    QIcon icon;
    // 图标大小设置为30*30
    icon.addFile(url, QSize());
    button->setIcon(icon);
    button->setIconSize(QSize(30, 30));

    // 设置按钮光标样式
    button->setCursor(QCursor(Qt::PointingHandCursor));
}

最小化按钮按的实现

这是菜单栏右上角的一个按钮,适用于切换侧边菜单栏的两种状态。

  • 确定按钮的点击信号函数, 以及操作函数 用于菜单栏的两种样式的区分, 主要是修改了文字的显示与否, 以及菜单栏的宽度
void Menu::onMinimizeButtonClicked()
{
    isMinimized = !isMinimized;
    setMenu(isMinimized);
}

void Menu::setMenu(bool isMini)
{
    // 最小化
    if (isMini)
    {
        // 设置最小宽度和最大宽度
        this->setMinimumWidth(50);
        this->setMaximumWidth(50);

        newPage1Btn->setText("");
        newPage2Btn->setText("");
        newPage3Btn->setText("");
        titleLabel->setText("");

        // 设置按钮的图标
        setPushButton(minimizeButton, QString::fromUtf8(":/res/RetroStingySUV.svg"), "");
    }
    // 正常
    else {
        // 设置最小宽度和最大宽度
        this->setMinimumWidth(200);
        this->setMaximumWidth(300);

        newPage1Btn->setText(tr("First page"));
        newPage2Btn->setText(tr("Second page"));
        newPage3Btn->setText(tr("Third page"));
        titleLabel->setText(tr("     menu"));

        setPushButton(minimizeButton, QString::fromUtf8(":/res/vehicle.svg"), "");
    }
}

按钮与页面之间的联动

我的解决方法是将按钮和新页面分别编组,再一一对应。

	/* menu.cpp */
	// 创建按钮组
    buttonGroup.addButton(newPage1Btn, 1);
    buttonGroup.addButton(newPage2Btn, 2);
    buttonGroup.addButton(newPage3Btn, 3);

	/* mainwindw.cpp */
    // 创建QStackedWidget控件 用于存放多个页面
    qStackedWidget = new QStackedWidget;

    auto *newPage1 = new NewPage1;
    auto *newPage2 = new NewPage2;
    auto *newPage3 = new NewPage3;

    qStackedWidget->addWidget(newPage1);
    qStackedWidget->addWidget(newPage2);
    qStackedWidget->addWidget(newPage3);

在menu的按钮控件中

void Menu::onButtonClicked(int id)
{
    // 获取选中的按钮
    auto *button = qobject_cast<QPushButton*>(buttonGroup.button(id));

    // 将所有按钮的样式表恢复到初始状态
    for(QAbstractButton *b : buttonGroup.buttons()) {
        if (b != button) {
            b->setStyleSheet("background-color: transparent;"
                                "opacity: 0;"
                                "border-radius: 7px;");
        }
    }

    // 更改选中按钮的样式
    if (button) {
        button->setStyleSheet("background-color: rgba(0, 0, 0, 0.2);"
                              "border-radius: 7px;");
		
		// 发送信号到主界面,修改主界面的页面
        emit buttonClicked(id);
    }
}

并且链接按钮点击和按钮样式的改变

    // 连接信号与槽,当按钮选中时调用自定义的槽函数
    connect(&buttonGroup, QOverload<int>::of(&QButtonGroup::idClicked), this, &Menu::onButtonClicked);

在mainwindow中

void MXGMainWindow::onButtonClicked(int buttonId)
{
    int pageIndex = buttonId - 1;                           // 索引从0开始
    qStackedWidget->setCurrentIndex(pageIndex);
}

链接按钮与主界面的页面切换

    // 绑定侧边栏按钮和主界面的控件
    connect(sidebarWidget, SIGNAL(buttonClicked(int)), this, SLOT(onButtonClicked(int)));

demo地址

gitee

posted @ 2024-03-01 16:11  yuchq  阅读(2984)  评论(0)    收藏  举报