Qt编写自定义控件:左上角圆形菜单控件

代码:

#ifndef ROUNDMMENUINUPPERLEFTCORNERWIDGET_H
#define ROUNDMMENUINUPPERLEFTCORNERWIDGET_H

#include <QWidget>
#include <QTimer>
#include <QPainterPath>

class RoundMmenuInUpperLeftCornerWidget : public QWidget
{
    Q_OBJECT

public:
    RoundMmenuInUpperLeftCornerWidget(QWidget *parent = nullptr);
    ~RoundMmenuInUpperLeftCornerWidget()override;

protected:
    void paintEvent(QPaintEvent *event)override;
    void mousePressEvent(QMouseEvent *event)override;
    void resizeEvent(QResizeEvent *event)override;
    void mouseReleaseEvent(QMouseEvent *event)override;
    void mouseMoveEvent(QMouseEvent *event)override;

private:
    void onTimer();
    enum class State
    {
        Shrink,//收缩
        Popped,//已弹出
        Popping//正在弹出
    };
    State widgetState{State::Shrink};
    State lastWidgetState{State::Shrink};
    QRect homeBtnRect;
    QTimer timer;
    int Length{0};
    int radius{0};
    int outSideRadius{0};
    QList<QPixmap> imgList;
    QList<QRect> menuRectList;
    int pressIndexInMenuRectList{-1};
    QPoint pressPos{0,0};
    QPainterPath arcAreaPath;
    int allBeforeAngleOffset{0};
    int currentOffset{0};
};
#endif // ROUNDMMENUINUPPERLEFTCORNERWIDGET_H
#include "roundmmenuinupperleftcornerwidget.h"
#include <QPainter>
#include <QPaintEvent>
#include <QDebug>

RoundMmenuInUpperLeftCornerWidget::RoundMmenuInUpperLeftCornerWidget(QWidget *parent)
    : QWidget(parent)
{
    setPalette(Qt::white);
    setMouseTracking(true);

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

    imgList << QPixmap(":/img/F1.png");
    imgList << QPixmap(":/img/F2.png");
    imgList << QPixmap(":/img/F3.png");
    imgList << QPixmap(":/img/F4.png");
    imgList << QPixmap(":/img/F5.png");
    imgList << QPixmap(":/img/F6.png");
    imgList << QPixmap(":/img/F7.png");
    imgList << QPixmap(":/img/F8.png");
    imgList << QPixmap(":/img/F9.png");
    imgList << QPixmap(":/img/F10.png");
    imgList << QPixmap(":/img/F11.png");
    imgList << QPixmap(":/img/F12.png");

    auto it = std::inserter(menuRectList,menuRectList.begin());
    for(int i = 0;i < imgList.size();++i,++it)
    {
        *it = QRect();
    }
}

RoundMmenuInUpperLeftCornerWidget::~RoundMmenuInUpperLeftCornerWidget()
{
}

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

    const auto rect = event->rect();

    auto width = rect.width();
    auto height = rect.height();
    Length = std::min(width,height);
    if(widgetState == State::Shrink)
    {
        radius = 0.33 * Length / 1.2;
    }

    auto ellipseCenter = QPointF(radius*0.2,radius*0.2);
    painter.save();
    QRadialGradient radialGradient;
    radialGradient.setCenter(ellipseCenter);
    radialGradient.setRadius(radius * 1.2);
    radialGradient.setFocalPoint(ellipseCenter);
    radialGradient.setColorAt(0.0,QColor("#EAEAEA"));
    radialGradient.setColorAt(1.0,QColor("#AFAFAF"));
    painter.setBrush(radialGradient);
    painter.setPen(QColor("#808080"));
    painter.drawEllipse(ellipseCenter,radius,radius);
    painter.restore();

    homeBtnRect = QRect(radius*0.05,radius*0.05,radius*0.8,radius*0.8);
    painter.drawPixmap(homeBtnRect,QPixmap(":/img/home.png"));

    if(widgetState != State::Shrink)
    {
        QPainterPath p1;
        p1.addEllipse(ellipseCenter,outSideRadius,outSideRadius);
        QPainterPath p2;
        p2.addEllipse(ellipseCenter,radius,radius);
        arcAreaPath = p1 - p2;

        painter.setBrush(QColor("#E2E2D0"));
        painter.setPen(Qt::transparent);
        painter.drawPath(arcAreaPath);
    }

    if(widgetState != State::Shrink)
    {
        int cha = outSideRadius  - radius;
        int imgX = (1.2 * radius) + (cha - radius*0.8) / 2;
        int imgY = 0.2 *radius;

        QRect imgRect;
        if(widgetState == State::Popping)
            imgRect = QRect(imgX,imgY,cha * 0.6,cha * 0.6);
        else
            imgRect = QRect(imgX,imgY,radius*0.8,radius*0.8);

        int size = imgList.size();
        QTransform transform;
        QPoint temp(static_cast<int>(radius*0.4),static_cast<int>(radius*0.4));
        for (int i = 0;i < size;++i)
        {
            auto angle = 360 / size * i + allBeforeAngleOffset + currentOffset;
            painter.save();
            painter.rotate(angle);
            painter.drawPixmap(imgRect,imgList.at(i));
            painter.restore();

            transform.reset();
            transform.rotate(angle);
            QPoint transform_p = transform.map(imgRect.center());
            menuRectList[i] = QRect(transform_p - temp,transform_p + temp);
        }

        if(pressIndexInMenuRectList >= 0)
        {
            QColor slightlyOpaqueBlack(0, 0, 0, 63);
            painter.setBrush(slightlyOpaqueBlack);
            painter.drawEllipse(menuRectList.at(pressIndexInMenuRectList));
        }
    }
}

void RoundMmenuInUpperLeftCornerWidget::mousePressEvent(QMouseEvent *event)
{
    QRegion ellipseRegion(homeBtnRect, QRegion::Ellipse);
    auto pos = event->pos();
    if(ellipseRegion.contains(pos))
    {
        if(widgetState == State::Shrink)
        {
            lastWidgetState = State::Shrink;
            radius = 0.5 * Length / 1.2;
            outSideRadius = radius;
            widgetState = State::Popping;
        }
        else if(widgetState == State::Popped)
        {
            lastWidgetState = State::Popped;
            radius = 0.33 * Length / 1.2;
            widgetState = State::Popping;
        }
        timer.start();
    }
    else
    {
        pressIndexInMenuRectList = -1;
        if(widgetState == State::Popped)
        {
            for(int i = 0;i < menuRectList.size();++i)
            {
                if(menuRectList.at(i).contains(pos))
                {
                    pressIndexInMenuRectList = i;
                    break;
                }
            }

            if(pressIndexInMenuRectList == -1)
            {
                if(arcAreaPath.contains(pos))
                {
                    pressPos = pos;
                    setCursor(Qt::OpenHandCursor);
                }
            }
        }
    }
    update();

    QWidget::mousePressEvent(event);
}

void RoundMmenuInUpperLeftCornerWidget::onTimer()
{
    if(widgetState == State::Popping)
    {
        if(lastWidgetState == State::Shrink)
        {
            outSideRadius += Length * 0.1;
            if(outSideRadius >= (Length - radius * 0.2))
            {
                timer.stop();
                widgetState = State::Popped;
                outSideRadius = Length - radius * 0.2;
            }
        }
        else if(lastWidgetState == State::Popped)
        {
            outSideRadius -= Length * 0.1;
            if(outSideRadius < radius)
            {
                timer.stop();
                widgetState = State::Shrink;
                outSideRadius = radius;
            }
        }
        update();
    }
}

void RoundMmenuInUpperLeftCornerWidget::resizeEvent(QResizeEvent *event)
{
    widgetState = State::Shrink;

    update();
    QWidget::resizeEvent(event);
}

void RoundMmenuInUpperLeftCornerWidget::mouseReleaseEvent(QMouseEvent *event)
{
    if(widgetState == State::Popped)
    {
        pressIndexInMenuRectList = -1;
        pressPos = QPoint(0,0);
        allBeforeAngleOffset += currentOffset;
        currentOffset = 0;
        setCursor(Qt::ArrowCursor);
        update();
    }
    QWidget::mouseReleaseEvent(event);
}

void RoundMmenuInUpperLeftCornerWidget::mouseMoveEvent(QMouseEvent *event)
{
    auto pos = event->pos();
    bool mouseInAbtnZone{false};
    QRegion ellipseRegion(homeBtnRect, QRegion::Ellipse);

    if(ellipseRegion.contains(pos))
    {
        mouseInAbtnZone = true;
    }
    else
    {
        if(widgetState == State::Popped)
        {
            for(const auto & rect : menuRectList)
            {
                QRegion ellipseRegion(rect, QRegion::Ellipse);
                if(ellipseRegion.contains(pos))
                {
                    mouseInAbtnZone = true;
                    break;
                }
            }
        }
    }

    if(pressPos.isNull())
    {
        setCursor(mouseInAbtnZone ? Qt::PointingHandCursor : Qt::ArrowCursor);
    }
    else
    {
        QLineF line1(QPoint(radius*0.2,radius*0.2),pressPos);
        QLineF line2(QPoint(radius*0.2,radius*0.2),pos);
        int angle = line2.angleTo(line1);
        if(angle > 200)
        {
            if(pos.x() > 0 && pos.y() > 0)
            {
                angle = -(360 - angle);
            }
        }

        currentOffset = angle;
        setCursor(Qt::OpenHandCursor);
        update();
    }

    QWidget::mouseMoveEvent(event);
}

效果:

放在主窗口左上角:

#include "roundmmenuinupperleftcornerwidget.h"
#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QPushButton>
#include <QVBoxLayout>

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

    QMainWindow mainWindow;
    mainWindow.resize(1000,600);
    QVBoxLayout * vb = new QVBoxLayout;
    for(int i = 0;i < 5;++i)
    {
        QHBoxLayout * hb = new QHBoxLayout;
        hb->addWidget(new QPushButton);
        hb->addWidget(new QPushButton);
        hb->addWidget(new QPushButton);
        hb->addWidget(new QPushButton);
        vb->addLayout(hb);
    }
    QWidget * widget = new QWidget;
    widget->setLayout(vb);
    mainWindow.setCentralWidget(widget);
    RoundMmenuInUpperLeftCornerWidget w(&mainWindow);
    w.setFixedSize(300,300);
    mainWindow.show();
    return a.exec();
}

UI参考:jQuery左上角圆形菜单展开收缩特效 

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>