1 需求描述
需求就很簡明了,Qt自帶的QToolBox同時只能展開一個頁面,客戶要求可同時展開多個,這種只好自定義實現了。網上也能找到很多實現,但還是感覺親力親為的好,畢竟自己動手豐衣足食嘛。
2 設計思路
主要有兩部分,分別是ToolPage和ToolBox,ToolBox可包含多個ToolPage,ToolPage分為標題欄(QPushButton)和內容區(QWidget),設計簡單明了。點擊QPushButton后,循環展開/折疊內容區。
3 代碼實現
3.1 ToolPage
這個就沒啥說的了,主要完成標題欄和內容區的布局,點擊標題欄按鈕將內容區隱藏,再次點擊展示內容區,代碼如下:
#ifndef TOOLPAGE_H
#define TOOLPAGE_H
#include <QWidget>
namespace 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 <QDebug>
#include <QFormLayout>
#include <QDebug>
#include <QHBoxLayout>
#include <QLabel>
#include <QFile>
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
#include <QWidget>
namespace 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"
#include <QVBoxLayout>
ToolBox::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基本控件的使用搞清楚了,結合一些小技巧,實現復雜的自定義控件是一件很輕松的事情,熟能生巧,萬事皆如此。