qt编写自定义控件:左上角圆形菜单控件(代码片段)

友善啊,朋友 友善啊,朋友     2023-03-01     677

关键词:

代码:

#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 widgetStateState::Shrink;
    State lastWidgetStateState::Shrink;
    QRect homeBtnRect;
    QTimer timer;
    int Length0;
    int radius0;
    int outSideRadius0;
    QList<QPixmap> imgList;
    QList<QRect> menuRectList;
    int pressIndexInMenuRectList-1;
    QPoint pressPos0,0;
    QPainterPath arcAreaPath;
    int allBeforeAngleOffset0;
    int currentOffset0;
;
#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 mouseInAbtnZonefalse;
    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左上角圆形菜单展开收缩特效 

qt编写自定义控件20-自定义饼图(代码片段)

前言上次在写可视化数据大屏电子看板项目的时候,为了逐步移除对QChart的依赖(主要是因为QChart真的太垃圾了,是所有Qt的模块中源码最烂的一个,看过源码的人没有一个不吐槽,不仅不支持10W级别的数据量曲线展示,居然一... 查看详情

qt编写自定义控件24-图片轮播控件(代码片段)

一、前言上一篇文章写的广告轮播控件,采用的传统widget堆积设置样式表做的,这次必须要用到更高级的QPainter来绘制了,这个才是最高效的办法,本控件参考雨田哥的轮播控件,经过大规模的改造而成,相比于原来的广告轮播... 查看详情

qt编写自定义控件23-广告轮播控件(代码片段)

一、前言广告轮播这个控件做的比较早,是很早以前定制一个电信客户端时候用到的,该客户端需要在首页展示轮播预先设定好的图片,图片的路径可以自由设定,然后轮播的间隔速度可以自由控制,同时该控件还需要提供两种... 查看详情

qt编写自定义控件25-自定义qcustomplot(代码片段)

一、前言上次在写大屏数据可视化电子看板系统时候,提到过改造QCustomPlot来实现柱状分组图、横向柱状图、横向分组图、鼠标悬停提示等。这次单独列出来描述,有很多人疑问为啥不用QChart,或者echart等形式,其实这两种方式... 查看详情

qt编写自定义控件13-多态进度条(代码片段)

前言多态进度条,顾名思义,有多重状态,其实本控件主要是用来表示百分比进度的,由于之前已经存在了百分比进度条控件,名字被霸占了,按照先来先得原则,只好另外取个别名叫做多态进度条,应用场景是,某种任务有三... 查看详情

qt编写自定义控件22-蚂蚁线(代码片段)

一、前言关于蚂蚁线控件,相信很多用过PS的人都知道,在选中某个区域以后,边上的线条会有一种动态流动的效果,这种效果就叫做蚂蚁线,百科的解释是:动物的一种本能现象,领头的蚂蚁以随机的路线走向食物或洞穴,第... 查看详情

qt编写自定义控件14-环形进度条(代码片段)

前言环形进度条,用来展示当前进度,为了满足大屏UI的需要特意定制,以前有个叫圆环进度条,不能满足项目需要,只能重新定做,以前的进度间距不能自适应分辨率,而且当前进度对应的反的进度不能单独设置颜色,即当前... 查看详情

qt编写自定义控件15-百分比仪表盘(代码片段)

前言百分比仪表盘,主要的应用场景是展示销售完成率、产品合格率等,也可以作为一个进度百分比展示,可以独立设置对应的标题文字,标题文字的颜色和整体的颜色都可以单独设置,建议设置成统一的风格,这样会显得更加... 查看详情

android自定义控件篇圆形倒计时(代码片段)

一、效果图二、自定义样式attrs.xml<declare-styleablename="AdCountDownView"><!--控制广告时间--><attrname="AD_Time"format="integer"/> 查看详情

android自定义控件篇圆形进度条(代码片段)

一、效果图二、代码逻辑/***funcation:圆形进度条控件*/publicclassCircleProgressViewextendsViewprivatePaintmBackPaint,mProgPaint;//绘制画笔privateRectFmRectF;//绘制区域privateint[]mColorArray;//圆环渐变色privateintmProgress;//圆环进度(0-100)publicCircleProgressView(Co... 查看详情

qt自定义控件(代码片段)

一,首先新建一个功能,例如:spprogressbar  spprogressbar.proCONFIG+=plugindebug_and_releaseTARGET=$$qtLibraryTarget(spprogressbarplugin)TEMPLATE=libDESTDIR=$$PWD/../libHEADER_PATH=$$PWD/../../includeSOURCE_PATH=$$P 查看详情

wpf自定义控件の重写原生控件样式模板(代码片段)

原文:WPF自定义控件(二)の重写原生控件样式模板    话外篇: 要写一个圆形控件,用Clip,重写模板,去除样式引用圆形图片可以有这三种方式。  开发过程中,我们有时候用WPF原生的控件就能实现自己的... 查看详情

qt+自定义控件-spin+slider(代码片段)

动手实现自定义控件:1、首先在ui界面中添加一个(Widget)容器类。如图中的1所示2、在项目中添加一个SmallWidget类,如下:             3、接着在程序编辑界面进行程序编辑如下:#include"smallwidget.h"/*... 查看详情

qt编写自定义控件插件开放动态库dll使用(永久免费)

...想要使用其中一个控件,必须包含所有的代码。全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.12的任何Qt版本,支持mingw、msvc、gcc等编译器,不乱码,可直接集成到QtCreator中,和自带的控件一样使用,大部分效果只要设置几个... 查看详情

qt编写自定义控件68-ip地址输入框(代码片段)

一、前言这个IP地址输入框控件,估计写烂了,网上随便一搜索,保证一大堆,估计也是因为这个控件太容易了,非常适合新手练手,一般的思路都是用4个qlineedit控件拼起来,然后每个输入框设置正则表达式过滤只能输入3位数... 查看详情

qt编写自定义控件属性设计器

以前做.NET开发中,.NET直接就集成了属性设计器,VS不愧是宇宙第一IDE,你能够想到的都给你封装好了,用起来不要太爽!因为项目需要自从全面转Qt开发已经6年有余,在工业控制领域,有一些应用场景需要自定义绘制一些控件... 查看详情

qt编写自定义控件70-扁平化flatui(代码片段)

一、前言对于现在做前端开发人员来说,FlatUI肯定不陌生,最近几年扁平化的设计越来越流行,大概由于现在PC端和移动端的设备的分辨率越来越高,扁平化反而看起来更让人愉悦,而通过渐变色产生的质感色彩反而没有扁平化... 查看详情

qt编写导航按钮

...或者导航菜单,参照过各种各样的主界面导航布局,特意编写导航按钮自定义控件,结合各种情况,继承自QPushButton。已集成在QUC自定义控件中。/***导航按钮控件作者:feiyangqingyun(QQ:517216493)2017-12-19*1:可设置文字的左侧+右侧+顶部+... 查看详情