模仿富途做一个水平导航栏。原理就是在QButtonGroup中加入QPushbutton,加上一定的动画和样式。
代码如下:
.h
#ifndef CHORIZONTALNAVBAR_H
#define CHORIZONTALNAVBAR_H
/*************************************/
/**功能:水平导航栏 **/
/**作者:hao **/
/**日期:2020-04-27 **/
/*************************************/
#include <QWidget>
#include <QButtonGroup>
#include <QPropertyAnimation>
#include <QPaintEvent>
#include <QPushButton>
class CHorizontalNavBar : public QWidget
{
Q_OBJECT
public:
explicit CHorizontalNavBar(QWidget *parent = nullptr);
~CHorizontalNavBar();
void addButton(QPushButton* btn, int id);
void addHorStretch();//在最后布局加一个弹簧
signals:
void signal_currIndex(int);
protected:
void paintEvent(QPaintEvent *e);
private slots:
void onValueChanged(QVariant variant);
void onButtonClicked(int index);
private:
void deleteLayout();
int m_curIndex;
int m_preIndex;
int m_offset;
int m_lineHeight;
QColor m_lineColor;
QSize m_btnSize; //按钮的尺寸
QButtonGroup *m_btnGroup;
QPropertyAnimation *m_animation;
QList<QAbstractButton *> m_buttonList; //按钮集合
};
#endif // CHORIZONTALNAVBAR_H
.cpp
#include "chorizontalnavbar.h"
#include <QLayoutItem>
#include <QVBoxLayout>
#include <QPainter>
CHorizontalNavBar::CHorizontalNavBar(QWidget *parent) :
QWidget(parent)
, m_curIndex(0)
, m_preIndex(0)
, m_offset(0)
, m_lineHeight(1)
, m_lineColor(QColor( 255,215,0))
, m_btnSize(QSize(120,30))
{
m_btnGroup = new QButtonGroup(this);
connect(m_btnGroup, SIGNAL(buttonClicked(int)), SLOT(onButtonClicked(int)));
m_animation = new QPropertyAnimation(this, "");
m_animation->setDuration(200);
connect(m_animation, SIGNAL(valueChanged(QVariant)), SLOT(onValueChanged(QVariant)));
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, m_lineHeight);
layout->setSpacing(0);
setLayout(layout);
}
CHorizontalNavBar::~CHorizontalNavBar()
{
}
void CHorizontalNavBar::addButton(QPushButton *btn, int id)
{
m_btnGroup->addButton(btn, id);
m_buttonList.append(btn);
layout()->addWidget(btn);
m_btnSize = btn->size();
QString style = QString("QPushButton{border:none;}"
"QPushButton:hover{color:rgb(%1, %2, %3);}"
"QPushButton:pressed, QPushButton:checked{color:rgba(%1, %2, %3, 150);}").arg(m_lineColor.red()).arg(m_lineColor.green()).arg(m_lineColor.blue());
btn->setStyleSheet(style);
}
void CHorizontalNavBar::addHorStretch()
{
static_cast<QHBoxLayout*>(layout())->addStretch();
}
void CHorizontalNavBar::paintEvent(QPaintEvent *e)
{
QWidget::paintEvent(e);
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing);
painter.save();
QPen pen;
pen.setColor(QColor(169,169,169));
pen.setWidth(1);
painter.setPen(pen);
painter.drawLine(0,height()-1,width(),height()-1);
painter.restore();
painter.save();
painter.setPen(Qt::NoPen);
painter.setBrush(m_lineColor);
//画下边的线
painter.drawRect(m_offset, this->height() - m_lineHeight, m_btnSize.width(), m_lineHeight);
painter.restore();
}
void CHorizontalNavBar::onValueChanged(QVariant variant)
{
m_offset = variant.toInt();
update();
}
void CHorizontalNavBar::onButtonClicked(int index)
{
m_btnGroup->button(index)->setChecked(true);
m_preIndex = m_curIndex;
m_curIndex = index;
m_animation->setStartValue(m_preIndex * m_btnSize.width());
m_animation->setEndValue(index * m_btnSize.width());
m_animation->start();
emit signal_currIndex(m_curIndex);
}
void CHorizontalNavBar::deleteLayout()
{
//清除布局,包括布局内控件
if (this->layout() != nullptr)
{
QLayoutItem *child;
while ((child = this->layout()->takeAt(0)) != 0) {
delete child->widget();
delete child;
child = nullptr;
}
m_buttonList.clear();
delete this->layout();
this->setLayout(nullptr);
}
}
调用地方:
for (int index = 0; index < 5; ++index)
{
QPushButton *btn = new QPushButton;
btn->setCheckable(true);
QString keyStr = QString("界面_%1").arg(index);
btn->setText(keyStr);
btn->setFixedWidth(120);
ui->widget_nav->addButton(btn, index);
}
ui->widget_nav->addHorStretch();