引言
步骤条用于用户操作引导是必不可少的,能够为用户植入相关的操作步骤,避免大段的说明文档以及后期的相关培训,是一种成本较低效果较好的交互语言。
针对上述需求进行实现,实现效果如下图所示:
代码实现
最小的单元是StepIconLabel 控制item左侧的数字显示,重写paintEvent进行绘制,背景通过椭圆而成,文字应为需要控制选中状态,所以没有使用样式表,也是通过自绘完成。目前没有对外开发设置颜色接口,使用中可更具需求进行添加。
再者是StepItemWidget列表中的排布的item,由左侧数字和按钮组成,对外接口有设置setNumber和setName,顾名思义就是设置左侧数字以及按钮名称,其中按钮名称代表各步骤名称。
最后则是StepListWidget,通过setStepList填充每一步的名称,item中的按钮点击后也会触发当前选中步骤切换,也可通过函数进行切换,setCurrentStep主要用于需要初始化当前选中状态的情况。setMaxVisibleItems可设置最大显示数量,默认最大显示数量为6个。
#include <QWidget>
#include <QLabel>
class QPushButton;
class QHBoxLayout;
class StepIconLabel : public QLabel
{
Q_OBJECT
public:
explicit StepIconLabel(QWidget *parent = nullptr);
void setChecked(bool checked);
void setFontSize(int pixelSize);
protected:
void paintEvent(QPaintEvent *event) override;
private:
bool m_checked;
int m_fontSize;
};
class StepItemWidget : public QWidget
{
Q_OBJECT
public:
explicit StepItemWidget(QWidget *parent = nullptr);
void setNumber(quint32 number);
void setName(const QString& nameStr);
// 设置选中状态
void setChecked(bool checked);
signals:
void sig_btnClicked(quint32 number);
private:
StepIconLabel* m_numberLabel;
QPushButton* m_itemBtn;
quint32 m_number;
};
class StepListWidget : public QWidget
{
Q_OBJECT
public:
explicit StepListWidget(QWidget *parent = nullptr);
void setStepList(const QStringList strList);
void setCurrentStep(int number);
void setMaxVisibleItems(int maxItems);
signals:
void sig_btnClicked(quint32 number);
private slots:
void slot_toLeft();
void slot_toRigit();
void slot_btnClicked(quint32 number);
private:
void refreshVisible();
private:
QList<StepItemWidget*> m_itemList;
QList<QWidget*> m_lineList;
QPushButton* m_leftBtn;
QPushButton* m_rightBtn;
int m_maxItems;
int m_currentIndex;
QHBoxLayout* m_itemLayout;
};
cpp实现
#include <QPushButton>
#include <QHBoxLayout>
#include <QPainter>
#include <QPaintEvent>
///
StepIconLabel::StepIconLabel(QWidget *parent)
: QLabel(parent)
, m_checked(false)
, m_fontSize(12)
{
}
void StepIconLabel::setChecked(bool checked)
{
if (m_checked != checked) {
m_checked = checked;
update();
}
}
void StepIconLabel::setFontSize(int pixelSize)
{
if (m_fontSize != pixelSize) {
m_fontSize = pixelSize;
update();
}
}
void StepIconLabel::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// 绘制背景
painter.save();
if (m_checked) {
painter.setBrush(QColor(0,186,218));
painter.setPen(QColor(0,186,218));
}
else {
painter.setBrush(Qt::NoBrush);
painter.setPen(QColor(93,93,93));
}
painter.drawEllipse(event->rect().marginsAdded(QMargins(-1, -1, -1, -1)));
painter.restore();
// 绘制文字
painter.save();
auto tmpFont = painter.font();
tmpFont.setPixelSize(m_fontSize);
painter.setFont(tmpFont);
if (m_checked) {
painter.setPen(QColor(255,255,255,200));
}
else {
painter.setPen(QColor(93,93,93));
}
painter.drawText(event->rect(), Qt::AlignCenter, text());
painter.restore();
}
///
StepItemWidget::StepItemWidget(QWidget *parent)
: QWidget(parent)
, m_number(0)
{
m_numberLabel = new StepIconLabel(this);
m_numberLabel->setFixedSize(16, 16);
m_itemBtn = new QPushButton(this);
m_itemBtn->setObjectName("btn_only_word_white");
m_itemBtn->setStyleSheet("QPushButton#btn_only_word_white {\
color: rgba(255,255,255,0.80);\
background: transparent;\
border-radius: 0px;\
padding-left: 0px; \
padding-right: 0px;\
}\
QPushButton#btn_only_word_white:hover {\
color: rgb(37,207,230);\
}\
QPushButton#btn_only_word_white:pressed {\
color: rgb(0,146,179);\
}\
QPushButton#btn_only_word_white:disabled {\
color: rgb(22,74,86);\
}");
connect(m_itemBtn, &QPushButton::clicked, this, [this]{
emit sig_btnClicked(m_number);
});
auto mainLayout = new QHBoxLayout(this);
mainLayout->setSpacing(8);
mainLayout->addWidget(m_numberLabel);
mainLayout->addWidget(m_itemBtn);
}
void StepItemWidget::setNumber(quint32 number)
{
m_number = number;
m_numberLabel->setText(QString::number(number + 1));
}
void StepItemWidget::setName(const QString &nameStr)
{
m_itemBtn->setText(nameStr);
}
void StepItemWidget::setChecked(bool checked)
{
m_numberLabel->setChecked(checked);
}
///
StepListWidget::StepListWidget(QWidget *parent)
: QWidget(parent)
, m_maxItems(6)
, m_currentIndex(0)
{
setAttribute(Qt::WA_StyledBackground);
setStyleSheet("StepListWidget{background-color: rgb(32,32,34);}");
m_itemLayout = new QHBoxLayout;
m_itemLayout->setSpacing(8);
m_leftBtn = new QPushButton("<", this);
m_leftBtn->setFixedSize(16, 16);
m_leftBtn->setVisible(false);
connect(m_leftBtn, &QPushButton::clicked, this, &StepListWidget::slot_toLeft);
m_rightBtn = new QPushButton(">", this);
m_rightBtn->setFixedSize(16, 16);
m_rightBtn->setVisible(false);
connect(m_rightBtn, &QPushButton::clicked, this, &StepListWidget::slot_toRigit);
auto mainLayout = new QHBoxLayout(this);
mainLayout->setSpacing(8);
mainLayout->addSpacing(15);
mainLayout->addWidget(m_leftBtn);
mainLayout->addLayout(m_itemLayout);
mainLayout->addWidget(m_rightBtn);
mainLayout->addSpacing(15);
mainLayout->addStretch();
}
void StepListWidget::setStepList(const QStringList strList)
{
// 清空原控件
QLayoutItem *child;
while ((child = m_itemLayout->takeAt(0)) != 0) {
delete child->widget();
delete child;
}
m_itemList.clear();
m_lineList.clear();
for(QString itemStr : strList){
auto itemWidget = new StepItemWidget(this);
itemWidget->setName(itemStr);
itemWidget->setNumber(m_itemList.count());
connect(itemWidget, &StepItemWidget::sig_btnClicked, this, &StepListWidget::slot_btnClicked);
m_itemList << itemWidget;
m_itemLayout->addWidget(itemWidget);
if(itemStr != strList.last()){
auto lineWidget = new QLabel(this);
lineWidget->setStyleSheet(QString("QLabel{background: transparent; border: 1px solid rgb(93,93,93);}"));
lineWidget->setFixedSize(20, 1);
m_lineList << lineWidget;
m_itemLayout->addWidget(lineWidget);
}
}
refreshVisible();
}
void StepListWidget::setCurrentStep(int number)
{
for (int i = 0; i < m_itemList.count(); i++) {
m_itemList.at(i)->setChecked(number == i);
}
}
void StepListWidget::setMaxVisibleItems(int maxItems)
{
m_maxItems = maxItems;
refreshVisible();
}
void StepListWidget::slot_toLeft()
{
m_currentIndex--;
refreshVisible();
}
void StepListWidget::slot_toRigit()
{
m_currentIndex++;
refreshVisible();
}
void StepListWidget::slot_btnClicked(quint32 number)
{
setCurrentStep(number);
emit sig_btnClicked(number);
}
void StepListWidget::refreshVisible()
{
if(m_itemList.count() < m_maxItems){
m_leftBtn->setVisible(false);
m_rightBtn->setVisible(false);
}
else{
m_leftBtn->setVisible(m_currentIndex != 0);
m_rightBtn->setVisible(m_currentIndex != m_itemList.count() - m_maxItems);
}
// item的显示隐藏
for(int i=0; i<m_itemList.count(); i++){
if(i >= m_currentIndex && i < m_currentIndex + m_maxItems){
m_itemList.at(i)->setVisible(true);
}
else{
m_itemList.at(i)->setVisible(false);
}
}
// 分割线的显示隐藏
for(int i=0; i<m_lineList.count(); i++){
if(m_itemList.count() > 1 && i >= m_currentIndex && i < m_currentIndex + m_maxItems - 1){
m_lineList.at(i)->setVisible(true);
}
else{
m_lineList.at(i)->setVisible(false);
}
}
}
外部调用示例
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto listWidget = new StepListWidget(this);
listWidget->setStepList(QStringList() << "step1" << "step2" << "step3" << "step4" << "step5" << "step6" << "step7" << "step8");
setCentralWidget(listWidget);
}