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

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

实现代码:
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;
}
侧边菜单栏页面设置

侧边栏采用的是这种竖直方向的排布 (按钮图标及文字仅供参考)
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)));

浙公网安备 33010602011771号