视觉和交互参考前端element组件,使用Qt实现
element的Tabs效果
打算使用最简单的方式实现可滑动的Tabs,继承于QTabWidget,加入些动画效果绘制下划线就搞定了,是不是很简单。
没有截动态效果,可自己调试
但是其中也有些注意点,这里也是阅读qtabwidget.cpp和qstylesheetstyle.cpp源码解决
.h文件
#include <QTabWidget>
#include <QVariantAnimation>
class TabBarAnimation;
class QSimpleSliderNavigation : public QTabWidget
{
Q_OBJECT
public:
QSimpleSliderNavigation(QWidget *parent = Q_NULLPTR);
~QSimpleSliderNavigation();
void setAnimationCurrentValue(int value);
protected:
void paintEvent(QPaintEvent *);
bool eventFilter(QObject *o, QEvent *e);
private:
void startAnimation(int beginX,int endX,int duration); // 先只考虑横向的
private:
TabBarAnimation *animation;
int m_animationX;
};
.cpp部分
#include "QSimpleSliderNavigation.h"
#include <QStyleOptionTabWidgetFrame>
#include <QStylePainter>
#include <QMouseEvent>
struct TabBarAnimation : public QVariantAnimation {
TabBarAnimation(QSimpleSliderNavigation* t) : tabs(t)
{
setEasingCurve(QEasingCurve::InOutQuad);
}
void updateCurrentValue(const QVariant ¤t) Q_DECL_OVERRIDE;
private:
QSimpleSliderNavigation* tabs;
};
void TabBarAnimation::updateCurrentValue(const QVariant ¤t)
{
if (tabs)
{
tabs->setAnimationCurrentValue(current.toInt());
}
}
//这里的 QTabWidget::pane {border: none;position: relative;top:2px;} 很重要,将pane的位置下移,这样绘制的下划线才能显示
QSimpleSliderNavigation::QSimpleSliderNavigation(QWidget *parent)
: QTabWidget(parent)
{
setStyleSheet("QTabWidget {background-color: rgb(238, 243, 250);} \
QTabWidget::pane {border: none;position: relative;top:2px;} \
QTabWidget::tab-bar {border: none;} \
QTabBar::tab {border: none;min-height: 28px;min-width: 85px;} \
QTabBar::tab:hover,QTabBar::tab:selected {color: rgb(88, 187, 228);} \
QTabBar::tab:!enabled {background-color: rgb(180, 180, 180);}");
tabBar()->installEventFilter(this);
animation = nullptr;
m_animationX = -1;
}
QSimpleSliderNavigation::~QSimpleSliderNavigation()
{
if (animation)
{
delete animation;
animation = nullptr;
}
}
bool QSimpleSliderNavigation::eventFilter(QObject *obj, QEvent *event)
{
if (obj == tabBar() && event->type() == QEvent::MouseButtonPress)
{
QMouseEvent *pMouseEvent = (QMouseEvent *)event;
if (pMouseEvent->button() == Qt::LeftButton)
{
const QPoint pos = pMouseEvent->pos();
int index = tabBar()->tabAt(pos);
if (index >= 0)
{
int curIndex = tabBar()->currentIndex();
if (index != curIndex)
{
startAnimation(tabBar()->tabRect(curIndex).x(), tabBar()->tabRect(index).x(), 250);
}
}
}
}
return false;
}
void QSimpleSliderNavigation::startAnimation(int beginX,int endX,int duration)
{
if (!animation)
animation = new TabBarAnimation(this);
animation->setStartValue(beginX);
animation->setEndValue(endX);
animation->setDuration(duration);
animation->start();
}
void QSimpleSliderNavigation::setAnimationCurrentValue(int value)
{
m_animationX = value;
update();
}
//绘制背景下划线和当前Index的下划线
void QSimpleSliderNavigation::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
int index = tabBar()->currentIndex();
QRect rect = tabBar()->tabRect(index);
QStyleOptionTabWidgetFrame option;
initStyleOption(&option);
option.lineWidth = 0;
QStylePainter p(this);
option.rect = style()->subElementRect(QStyle::SE_TabWidgetTabPane, &option, this);
p.drawPrimitive(QStyle::PE_FrameTabWidget, option);
p.fillRect(QRect(option.rect.x(), rect.y() + rect.height(),option.rect.width(),1),QColor(228,231,237));
int x = (animation && animation->state() == QAbstractAnimation::Running) ? m_animationX : rect.x();
p.fillRect(QRect(x, rect.y() + rect.height(), rect.width(), 2), QColor(88, 187, 228));
}