Qt编写自定义控件:高亮滑动导航菜单

代码:

#ifndef HIGHLIGHTSLIDINGNAVIGATIONMENUWIDGET_H
#define HIGHLIGHTSLIDINGNAVIGATIONMENUWIDGET_H

#include <QWidget>

class HighlightSlidingNavigationMenuWidget : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QRect sliderRect READ getSliderRect WRITE setSliderRect MEMBER sliderRect)

public:
    HighlightSlidingNavigationMenuWidget(QWidget *parent = nullptr);
    ~HighlightSlidingNavigationMenuWidget();
    void setTitle(const QStringList & list);

    const QRect &getSliderRect() const;
    void setSliderRect(const QRect &newSliderRect);

signals:
    void currIndexChange(int index);

protected:
    void paintEvent(QPaintEvent *event) override;
    QSize sizeHint() const override;
    void resizeEvent(QResizeEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;

private:
    void updateEachArea();

    QStringList titleList;
    QList<int> widthOfEachAreaList;
    int currIndex{0};
    QList<QRect> eachAreaList;
    QRect sliderRect;//滑块的位置
};
#endif // HIGHLIGHTSLIDINGNAVIGATIONMENUWIDGET_H
#include "highlightslidingnavigationmenuwidget.h"
#include <QPainter>
#include <QPaintEvent>
#include <QPropertyAnimation>

HighlightSlidingNavigationMenuWidget::HighlightSlidingNavigationMenuWidget(QWidget *parent)
    : QWidget(parent)
{
    setMouseTracking(true);

    auto font = this->font();
    font.setPixelSize(22);
    font.setBold(true);
    setFont(font);

    setTitle(QStringList() << "Home" << "Blog" << "More About My Portfolio" << "Contact");
}

HighlightSlidingNavigationMenuWidget::~HighlightSlidingNavigationMenuWidget()
{
}

void HighlightSlidingNavigationMenuWidget::setTitle(const QStringList &list)
{
    if(list.isEmpty())
        return;

    titleList = list;
    widthOfEachAreaList.clear();
    auto fontMetics = this->fontMetrics();
    int width{0};
    for(const auto & title : titleList)
    {
        width += (fontMetics.size(Qt::AlignCenter,title).width() + 60);
        widthOfEachAreaList << width;
    }
    updateEachArea();
    update();
}

void HighlightSlidingNavigationMenuWidget::paintEvent(QPaintEvent *event)
{
    const auto drawRect = event->rect();
    const auto drawHeight = drawRect.height();
    QPainter painter(this);
    painter.fillRect(drawRect.adjusted(0,10,0,-10),QColor(0x292929));
    painter.setRenderHint(QPainter::Antialiasing,true);

    painter.setPen(QPen(QColor(0x444444),2));
    for(int i = 0;i < widthOfEachAreaList.size();++i)
    {
        painter.drawLine(QPoint(widthOfEachAreaList.at(i),12),QPoint(widthOfEachAreaList.at(i),drawHeight - 12));
    }

    QLinearGradient linearGradient(sliderRect.topLeft(),sliderRect.bottomLeft());
    linearGradient.setColorAt(0.0,QColor(0x0b2b62));
    linearGradient.setColorAt(1.0,QColor(0x1153bf));
    painter.setBrush(linearGradient);
    painter.drawRoundedRect(sliderRect,6,6);

    painter.setFont(this->font());
    painter.setPen(Qt::white);
    for(int i = 0;i < eachAreaList.size();++i)
    {
        painter.drawText(eachAreaList.at(i),Qt::AlignCenter,titleList.at(i));
    }
}

QSize HighlightSlidingNavigationMenuWidget::sizeHint() const
{
    auto fontMetics = this->fontMetrics();
    int width{0};
    for(const auto & title : titleList)
    {
        width += (fontMetics.size(Qt::AlignCenter,title).width() + 60);
    }
    return QSize(width,100);
}

void HighlightSlidingNavigationMenuWidget::resizeEvent(QResizeEvent *event)
{
    updateEachArea();
    QWidget::resizeEvent(event);
}

void HighlightSlidingNavigationMenuWidget::mouseMoveEvent(QMouseEvent *event)
{
    auto nowPos = event->pos();
    int lastIndex = currIndex;
    for(int i = 0;i < widthOfEachAreaList.size();++i)
    {
        if(eachAreaList.at(i).contains(nowPos))
        {
            currIndex = i;
            break;
        }
    }
    if(lastIndex != currIndex)
    {
        auto animationSliderRect = new QPropertyAnimation(this, "sliderRect");
        animationSliderRect->setStartValue(sliderRect);
        animationSliderRect->setEndValue(eachAreaList.at(currIndex));
        animationSliderRect->setDuration(200);
        emit currIndexChange(currIndex);
        connect(animationSliderRect,&QPropertyAnimation::valueChanged,this,QOverload<>::of(&QWidget::update));
        animationSliderRect->start(QAbstractAnimation::DeleteWhenStopped);
    }
    QWidget::mouseMoveEvent(event);
}

void HighlightSlidingNavigationMenuWidget::updateEachArea()
{
    eachAreaList.clear();
    auto height = this->height();
    for(int i = 0;i < widthOfEachAreaList.size();++i)
    {
        QRect rect{i == 0 ? 0 : widthOfEachAreaList.at(i - 1),
                   0,
                   i == 0 ? widthOfEachAreaList.at(i) : widthOfEachAreaList.at(i) - widthOfEachAreaList.at(i - 1),
                   height};
        eachAreaList << rect;
    }
    sliderRect = eachAreaList.first();
    currIndex = 0;
    emit currIndexChange(currIndex);
}

const QRect &HighlightSlidingNavigationMenuWidget::getSliderRect() const
{
    return sliderRect;
}

void HighlightSlidingNavigationMenuWidget::setSliderRect(const QRect &newSliderRect)
{
    sliderRect = newSliderRect;
}

效果:

使用:

#include "highlightslidingnavigationmenuwidget.h"
#include <QApplication>
#include <QLabel>
#include <QVBoxLayout>
#include <QStackedLayout>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget widget;
    QVBoxLayout * vb = new QVBoxLayout(&widget);
    HighlightSlidingNavigationMenuWidget * w = new HighlightSlidingNavigationMenuWidget;
    vb->addWidget(w);
    QStackedLayout * stackedLayout = new QStackedLayout;
    stackedLayout->addWidget(new QLabel("第1页"));
    stackedLayout->addWidget(new QLabel("第2页"));
    stackedLayout->addWidget(new QLabel("第3页"));
    stackedLayout->addWidget(new QLabel("第4页"));
    vb->addLayout(stackedLayout);
    QWidget::connect(w,&HighlightSlidingNavigationMenuWidget::currIndexChange,[stackedLayout](int currIndex)
    {
        stackedLayout->setCurrentIndex(currIndex);
    });
    widget.show();

    return a.exec();
}

UI参考:jquery高亮滑动导航菜单 

  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值