Qt编写自定义控件:滑动弹出按钮组

代码:

#ifndef CLICKTOSWIPEWIDGET_H
#define CLICKTOSWIPEWIDGET_H

#include <QWidget>
#include <QTimer>

class ClickToSwipeWidget : public QWidget
{
    Q_OBJECT

public:
    ClickToSwipeWidget(QWidget *parent = nullptr);
    ~ClickToSwipeWidget();

signals:
    void clicked(int index);

protected:
    void paintEvent(QPaintEvent *event)override;
    QSize sizeHint() const override;
    void mousePressEvent(QMouseEvent *event)override;
    void mouseReleaseEvent(QMouseEvent *event)override;

private:
    enum class state
    {
        UnPressed,//未按下
        StretchingWidth_addWidth,//正在伸长宽度
        iconShowing,//图标正在显示
        iconShowed,//图标已显示
        iconHiding,//图标正在隐藏
        StretchingWidth_reduce//正在缩短宽度
    };
    state widgetState{state::UnPressed};
    QList<QPixmap> imgList;
    QList<QRect> imgRect;
    int widthChangeValue{0};//宽度变化值
    QTimer timer;
    void onTimer();
    int angle{0};
    int pressIconIndex{-1};//按下的图标的索引
};
#endif // CLICKTOSWIPEWIDGET_H
#include "clicktoswipewidget.h"
#include <QPainter>
#include <QPaintEvent>
#include <QPainterPath>

const int normalStatusSize = 60;
const int iconSize = 28;//图标宽度
const int iconShowDstY = (normalStatusSize - iconSize) / 2;//图标显示最终位置的Y值 16 = (60 - 图标高度28)/ 2
const int iconHideY = normalStatusSize + 10;//图标隐藏最终位置的Y值

ClickToSwipeWidget::ClickToSwipeWidget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowFlags(Qt::FramelessWindowHint);
    this->setAttribute(Qt::WA_TranslucentBackground, true);

    setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);

    connect(&timer,&QTimer::timeout,this,&ClickToSwipeWidget::onTimer);
    timer.setInterval(40);

    imgList << QPixmap(":/img/1.png");
    imgList << QPixmap(":/img/1p.png");
    imgList << QPixmap(":/img/2.png");
    imgList << QPixmap(":/img/2p.png");
    imgList << QPixmap(":/img/3.png");
    imgList << QPixmap(":/img/3p.png");

    assert((!imgList.isEmpty()) && (imgList.size() % 2 == 0));
    for(int i = 0;i < imgList.size() / 2;++i)
    {
        imgRect << QRect(normalStatusSize + i * (normalStatusSize - 10) + (normalStatusSize - 10 - iconSize) / 2,
                         iconHideY,iconSize,iconSize);
    }
}

ClickToSwipeWidget::~ClickToSwipeWidget()
{
}

void ClickToSwipeWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing,true);
    painter.setRenderHint(QPainter::SmoothPixmapTransform,true);

    auto rect = event->rect();
    QPainterPath path;
    path.addRoundedRect(rect.adjusted(5,5,-5,-5),normalStatusSize / 2,normalStatusSize / 2);
    painter.setClipPath(path);
    painter.fillRect(rect,Qt::white);

    QPen pen(QColor(0x22a74c),5,Qt::SolidLine,Qt::RoundCap,Qt::RoundJoin);
    painter.setPen(pen);

    painter.drawRoundedRect(rect.adjusted(5,5,-5,-5),normalStatusSize / 2,normalStatusSize / 2);

    auto radiu = normalStatusSize / 2 - 6;
    painter.save();
    painter.drawRoundedRect(rect.adjusted(5,5,-5,-5),normalStatusSize / 2,normalStatusSize / 2);
    painter.translate(QPoint(normalStatusSize / 2,normalStatusSize / 2));
    auto lineWidth = radiu/3.0f;

    if(widgetState == state::StretchingWidth_addWidth ||
       widgetState == state::iconShowing ||
       widgetState == state::iconShowed ||
       widgetState == state::iconHiding ||
       widgetState == state::StretchingWidth_reduce)
    {
        painter.rotate(angle);
    }

    painter.drawLine(QPoint(-lineWidth,0),QPoint(lineWidth,0));
    painter.drawLine(QPoint(0,-lineWidth),QPoint(0,lineWidth));

    painter.restore();

    if(widgetState == state::iconShowing ||
       widgetState == state::iconShowed ||
       widgetState == state::iconHiding)
    {
        for(int i = 0;i < imgRect.size();++i)
        {
            painter.drawPixmap(imgRect.at(i),imgList.at(i*2));
        }
    }

    if(widgetState == state::iconShowed && pressIconIndex != -1)
    {
        painter.drawPixmap(imgRect.at(pressIconIndex),imgList.at(pressIconIndex*2+1));
    }
}

QSize ClickToSwipeWidget::sizeHint() const
{
    if(widgetState == state::UnPressed)
    {
        return QSize(normalStatusSize, normalStatusSize);
    }
    else
    {
        return QSize(normalStatusSize + widthChangeValue, normalStatusSize);
    }
}

void ClickToSwipeWidget::mousePressEvent(QMouseEvent *event)
{
    if(widgetState == state::UnPressed)
    {
        widgetState = state::StretchingWidth_addWidth;
        widthChangeValue = 0;
        angle = 0;
        timer.start();
    }
    else if(widgetState == state::iconShowed)
    {
        auto pos = event->pos();
        for (int var = 0; var < imgRect.size(); ++var)
        {
            if(imgRect.at(var).contains(pos))
            {
                pressIconIndex = var;
                break;
            }
        }
        if(pressIconIndex != -1)
        {
            update();
            emit clicked(pressIconIndex);
        }
        else
        {
            if(QRect(10,10,normalStatusSize - 20,normalStatusSize - 20).contains(pos))
            {
                widgetState = state::iconHiding;
                timer.start();
            }
        }
    }
}

void ClickToSwipeWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if(widgetState == state::iconShowed)
    {
        if(pressIconIndex != -1)
        {
            pressIconIndex = -1;
            update();
        }
    }
}

void ClickToSwipeWidget::onTimer()
{
    if(widgetState == state::StretchingWidth_addWidth)
    {
        auto thisIsInLayout = testAttribute(Qt::WA_LaidOut);//控件是否在布局中
        if(thisIsInLayout)
            setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed);//Minimum:sizeHint() 提供的大小为最小大小,可拉伸(布局中)

        angle += 5;
        auto temp = (imgList.size() / 2 * (normalStatusSize - 10));

        widthChangeValue += (temp / 10);
        if(widthChangeValue > temp)
        {
            widgetState = state::iconShowing;
        }

        if(!thisIsInLayout)
            adjustSize();//控件不在布局中时调整大小(不在布局中)
        update();

        if(thisIsInLayout)
            setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
    }
    else if(widgetState == state::iconShowing)
    {
        bool 所有图标都垂直居中{true};
        for(int i = 0;i < imgRect.size();++i)
        {
            auto rect = imgRect[i];

            auto y = rect.y();
            if(y == iconShowDstY)
            {
                continue;
            }
            所有图标都垂直居中 = false;
            y -= 7;

            if(y < iconShowDstY)
            {
                rect.moveTopLeft(QPoint(rect.x(),iconShowDstY));
            }
            else
            {
                rect.moveTop(y);
            }
            imgRect[i] = rect;

            break;
        }
        if(所有图标都垂直居中)
        {
            widgetState = state::iconShowed;
            timer.stop();
        }
        update();
    }
    else if(widgetState == state::iconHiding)
    {
        bool 所有图标都隐藏了{true};
        for(int i = imgRect.size() - 1;i >= 0;--i)
        {
            auto rect = imgRect[i];

            auto y = rect.y();
            if(y == iconHideY)
            {
                continue;
            }
            所有图标都隐藏了 = false;
            y += 7;

            if(y >= iconHideY)
            {
                rect.moveTopLeft(QPoint(rect.x(),iconHideY));
            }
            else
            {
                rect.moveTop(y);
            }
            imgRect[i] = rect;

            break;
        }
        if(所有图标都隐藏了)
        {
            widgetState = state::StretchingWidth_reduce;
        }
        update();
    }
    else if(widgetState == state::StretchingWidth_reduce)
    {
        auto thisIsInLayout = testAttribute(Qt::WA_LaidOut);
        if(thisIsInLayout)
            setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed);

        angle -= 5;
        auto temp = (imgList.size() / 2 * (normalStatusSize - 10));

        widthChangeValue -= (temp / 10);
        if(widthChangeValue <= 0)
        {
            widgetState = state::UnPressed;
            timer.stop();
        }

        if(!thisIsInLayout)
            adjustSize();//控件不在布局中时调整大小(不在布局中)
        update();

        if(thisIsInLayout)
            setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
    }
}

使用:

#include "clicktoswipewidget.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget w;
    auto btn = new ClickToSwipeWidget;
    auto hb = new QHBoxLayout(&w);
    hb->setSizeConstraint(QLayout::SetMinimumSize);
    hb->addStretch();
    hb->addWidget(btn);
    hb->addStretch();
    w.resize(800,400);
    w.show();
    QWidget::connect(btn,&ClickToSwipeWidget::clicked,[](int index)
    {
        if(index == 0)
            qDebug()<<"点赞";
        else if(index == 1)
            qDebug()<<"投币";
        else if(index == 2)
            qDebug()<<"收藏";
    });

    return a.exec();
}

控件的宽度和添加的图标个数有关,如只添加两组图标:

    imgList << QPixmap(":/img/1.png");
    imgList << QPixmap(":/img/1p.png");
    imgList << QPixmap(":/img/2.png");
    imgList << QPixmap(":/img/2p.png");
//    imgList << QPixmap(":/img/3.png");
//    imgList << QPixmap(":/img/3p.png");

要改变控件尺寸只需要配置这两个量:

如设置:

const int normalStatusSize = 100;
const int iconSize = 40;//图标宽度

这个控件适合单独使用悬浮在窗口的一侧。

UI参考:jQuery点击滑动显示分享按钮代码

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值