1 需求描述
需求就很简明了,Qt自带的QToolBox同时只能展开一个页面,客户要求可同时展开多个,这种只好自定义实现了。网上也能找到很多实现,但还是感觉亲力亲为的好,毕竟自己动手丰衣足食嘛。
2 设计思路
主要有两部分,分别是ToolPage和ToolBox,ToolBox可包含多个ToolPage,ToolPage分为标题栏(QPushButton)和内容区(QWidget),设计简单明了。点击QPushButton后,循环展开/折叠内容区。
3 代码实现
3.1 ToolPage
这个就没啥说的了,主要完成标题栏和内容区的布局,点击标题栏按钮将内容区隐藏,再次点击展示内容区,代码如下:
#ifndef TOOLPAGE_H #define TOOLPAGE_H #includenamespace Ui { class ToolPage; } class QFormLayout; class QLabel; class ToolPage : public QWidget { Q_OBJECT public: explicit ToolPage(QWidget *parent = nullptr); ~ToolPage(); public slots: void addWidget(const QString &title, QWidget *widget); void expand(); void collapse(); private slots: void onPushButtonFoldClicked(); private: Ui::ToolPage *ui; bool m_bIsExpanded; QLabel *m_pLabel; }; #endif // TOOLPAGE_H
#include "ToolPage.h" #include "ui_ToolPage.h" #include#include #include #include #include #include ToolPage::ToolPage(QWidget *parent) : QWidget(parent), ui(new Ui::ToolPage), m_bIsExpanded(true), m_pLabel(nullptr) { ui->setupUi(this); ui->widgetContent->setAttribute(Qt::WA_StyledBackground); m_pLabel = new QLabel(this); m_pLabel->setFixedSize(20, 20); m_pLabel->setPixmap(QPixmap(":/img/down-arrow.png").scaled(m_pLabel->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); QHBoxLayout *layout = new QHBoxLayout(ui->pushButtonFold); layout->setContentsMargins(0, 0, 5, 0); layout->addStretch(1); layout->addWidget(m_pLabel); QFile file(":/qss/toolpage.qss"); if (file.open(QIODevice::ReadOnly)) { setStyleSheet(file.readAll()); } file.close(); connect(ui->pushButtonFold, &QPushButton::clicked, this, &ToolPage::onPushButtonFoldClicked); } ToolPage::~ToolPage() { delete ui; } void ToolPage::addWidget(const QString &title, QWidget *widget) { ui->pushButtonFold->setText(title); ui->verticalLayoutContent->addWidget(widget); } void ToolPage::expand() { ui->widgetContent->show(); m_bIsExpanded = true; m_pLabel->setPixmap(QPixmap(":/img/down-arrow.png").scaled(m_pLabel->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } void ToolPage::collapse() { ui->widgetContent->hide(); m_bIsExpanded = false; m_pLabel->setPixmap(QPixmap(":/img/left-arrow.png").scaled(m_pLabel->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } void ToolPage::onPushButtonFoldClicked() { if (m_bIsExpanded) { collapse(); } else { expand(); } }
需要提示一点,QPushButton文字可以通过QSS进行对齐方式设置,但是图标的对齐方式貌似不能设置,这里直接用一个水平布局将QLabel设置到按钮上,简单可靠,轻松达成目标。
3.2 ToolBox
ToolBox主要给外部用,将传入的QWidget传入到ToolPage中,ToolPage自动填充到内容区,再将ToolPage添加到垂直布局中,完成布局,代码如下:
#ifndef TOOLBOX_H #define TOOLBOX_H #includenamespace Ui { class ToolBox; } class QVBoxLayout; class ToolBox : public QWidget { Q_OBJECT public: explicit ToolBox(QWidget *parent = nullptr); ~ToolBox(); void addWidget(const QString &title, QWidget *widget); private: Ui::ToolBox *ui; QVBoxLayout *m_pContentVBoxLayout; }; #endif // TOOLBOX_H
#include "ToolBox.h" #include "ui_ToolBox.h" #include "ToolPage.h" #includeToolBox::ToolBox(QWidget *parent) : QWidget(parent), ui(new Ui::ToolBox), m_pContentVBoxLayout(nullptr) { ui->setupUi(this); QWidget *widget = new QWidget(this); m_pContentVBoxLayout = new QVBoxLayout; m_pContentVBoxLayout->setContentsMargins(0, 0, 0, 0); m_pContentVBoxLayout->setSpacing(2); QVBoxLayout *vBoxLayout = new QVBoxLayout(widget); vBoxLayout->setContentsMargins(0, 0, 0, 0); vBoxLayout->addLayout(m_pContentVBoxLayout); vBoxLayout->addStretch(1); ui->scrollArea->setWidget(widget); } ToolBox::~ToolBox() { delete ui; } void ToolBox::addWidget(const QString &title, QWidget *widget) { ToolPage *page = new ToolPage(this); page->addWidget(title, widget); m_pContentVBoxLayout->addWidget(page); }
3.3 简单使用
使用很简单了,只需要调用ToolBox唯一的一个接口即可:
void addWidget(const QString &title, QWidget *widget);
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle(QStringLiteral("自定义ToolBox演示 Qt小罗"));
ToolBox *toolBox = new ToolBox(this);
toolBox->addWidget(QStringLiteral("Qt小罗"), new Form());
toolBox->addWidget(QStringLiteral("Qt小罗"), new Form());
toolBox->addWidget(QStringLiteral("Qt小罗"), new Form());
toolBox->addWidget(QStringLiteral("Qt小罗"), new Form());
setCentralWidget(toolBox);
}
到此,自定义ToolBox就实现了,更多功能可自行拓展。
4 总结
Qt基本控件的使用搞清楚了,结合一些小技巧,实现复杂的自定义控件是一件很轻松的事情,熟能生巧,万事皆如此。
5 下载



