赞
踩
一如既往,先上图
动画效果参考下面的是视频
20220316-182247
摘要描述:
1、支持嵌入面板和弹出按钮两种,目前仅完成嵌入面板,后期会实现弹出实现
2、支持非常多的自定义功能,有关自定义功能定义参考下面的风格数据结构体代码,结构体中的功能均支持自定义
风格数据结构体代码如下:
- /// 圆形菜单控件风格样式数据结构
- ///
- typedef struct LNCFROUNDMENU_STYLE_{
- QList<DGRADIENTCOLOR_DATA> vMenuCtlBkgClr; //菜单渐变背景颜色集合列表
- QColor cMenuCtlBkgClr = QColor(88,88,88,44); //菜单控件背景颜色
- QColor cMenuBtnBkgClr = QColor(77,77,77,44); //菜单按钮默认背景色
- QColor cMenuBtnHovers = QColor(192,192,192,144);//菜单按钮悬停背景色
- QColor cMenuBtnTxtClr = QColor(202,202,202); //菜单按钮文字颜色
- QColor cMenuTextHover = QColor(255,255,255); //菜单按钮文字悬停颜色
- QColor cSwicthBnColor = QColor(144,133,227); //切换按钮默认颜色
- QColor cSwicthExpands = QColor(250,142,85); //切换按钮菜单展开时背景颜色
- QColor cSwicthBnHover = QColor(250,85,101); //切换按钮鼠标悬停颜色
- QColor cBkgBorderClrs = QColor(11,11,21,99); //背景边框颜色
- QColor cItemBorderClr = QColor(11,11,21,99); //菜单项边框颜色
-
- qreal dFrameOutScale = 0.75; //菜单外边框距离窗口边界比例
- qreal dFrameInnScale = 0.40; //菜单内边框距离窗口边界比例
- qreal dCenterBnScale = 1.5; //菜单中心按钮大小比例,相对于菜单窗口大小的缩小比例
- qreal dItemsBtnScale = 2.0; //菜单按钮图标大小比例,相对于菜单按钮扇形区域大小缩放比例
- qreal dItemsBkgScale = 1.25; //菜单按钮圆形背景大小比例,相对于菜单按钮扇形区域大小缩放比例
- qreal dItemBorderWid = 1; //菜单按钮边框宽度
- qreal dBnRoundRadius = 0.5; //菜单按钮圆角比例,0-0.5之间
- qreal dBkgBordersWid = 1; //菜单背景宽度
-
- qreal dStartDrawAngle = 180.0; //起始绘制角度
-
- uint uCenterBtnSize = 64; //菜单中心按钮绝对大小尺寸
- uint uAnimatedTimer = 400; //菜单展开和关闭动画周期时长
-
- bool bShowCtrlBkgnd = false; //是否显示控件背景
- bool bShowItemsLine = false; //是否绘制分割线
- bool bRoundMenuItem = true; //是否绘制圆形菜单项,默认是,否则显示扇形
- bool bDrawCenterBtn = true; //绘制中心按钮
- bool bMenuBtnsScale = true; //中心按钮大小比例类型,true表示绝对比例,false绝对大小
- bool bHasRandomClrs = false; //是否使用随机按钮背景颜色
- bool bRotateAnimate = true; //是否启用旋转动画,如果使用旋转动画至少将菜单展开和关闭周期设置到400或以上
- bool bShowBkgBorder = false; //是否显示背景边框
- bool bHasItemBorder = false; //是否显示菜单按钮边框
- bool bNoIcoFullName = true; //无图标按钮是否显示菜单全名
-
- bool operator == (const LNCFROUNDMENU_STYLE_& rhs) // == 操作运算符重载
- {
- if(vMenuCtlBkgClr.count()!= rhs.vMenuCtlBkgClr.count())
- return false;
-
- if(vMenuCtlBkgClr.count()== rhs.vMenuCtlBkgClr.count()&&rhs.vMenuCtlBkgClr.count()>0){
- for(int i=0;i<rhs.vMenuCtlBkgClr.count();i++)
- {
- if(QString("%1").arg(vMenuCtlBkgClr[i].fBkgndAngleVal) !=QString("%1").arg(rhs.vMenuCtlBkgClr[i].fBkgndAngleVal))
- return false;
- if(vMenuCtlBkgClr[i].cBkgndAngleClr != rhs.vMenuCtlBkgClr[i].cBkgndAngleClr)
- return false;
- }
- }
-
- return (cMenuCtlBkgClr == rhs.cMenuCtlBkgClr)
- && (cMenuBtnBkgClr == rhs.cMenuBtnBkgClr)
- && (cMenuBtnHovers == rhs.cMenuBtnHovers)
- && (cMenuBtnTxtClr == rhs.cMenuBtnTxtClr)
- && (bHasRandomClrs == rhs.bHasRandomClrs)
- && (cMenuTextHover == rhs.cMenuTextHover)
- && (cSwicthBnColor == rhs.cSwicthBnColor)
- && (cSwicthExpands == rhs.cSwicthExpands)
- && (cSwicthBnHover == rhs.cSwicthBnHover)
- && (QString("%1").arg(dFrameOutScale) == QString("%1").arg(rhs.dFrameOutScale))
- && (QString("%1").arg(dFrameInnScale) == QString("%1").arg(rhs.dFrameInnScale))
- && (QString("%1").arg(dCenterBnScale) == QString("%1").arg(rhs.dCenterBnScale))
- && (QString("%1").arg(dItemsBtnScale) == QString("%1").arg(rhs.dItemsBtnScale))
- && (QString("%1").arg(dItemsBkgScale) == QString("%1").arg(rhs.dItemsBkgScale))
- && (QString("%1").arg(dStartDrawAngle) == QString("%1").arg(rhs.dStartDrawAngle))
- && (uCenterBtnSize == rhs.uCenterBtnSize)
- && (uAnimatedTimer == rhs.uAnimatedTimer)
- && (bShowCtrlBkgnd == rhs.bShowCtrlBkgnd)
- && (bShowItemsLine == rhs.bShowItemsLine)
- && (bRoundMenuItem == rhs.bRoundMenuItem)
- && (bDrawCenterBtn == rhs.bDrawCenterBtn)
- && (bMenuBtnsScale == rhs.bMenuBtnsScale)
- && (bHasRandomClrs == rhs.bHasRandomClrs)
- && (bRotateAnimate == rhs.bRotateAnimate)
- && (cBkgBorderClrs == rhs.cBkgBorderClrs)
- && (bShowBkgBorder == rhs.bShowBkgBorder)
- && (cItemBorderClr == rhs.cItemBorderClr)
- && (QString("%1").arg(dItemBorderWid) == QString("%1").arg(rhs.dItemBorderWid))
- && (bHasItemBorder == rhs.bHasItemBorder)
- && (dBnRoundRadius == rhs.dBnRoundRadius)
- && (QString("%1").arg(dBkgBordersWid) == QString("%1").arg(rhs.dBkgBordersWid))
- && (bNoIcoFullName == rhs.bNoIcoFullName); //无图标按钮是否显示菜单全名
- }
-
- bool operator != (const LNCFROUNDMENU_STYLE_& rhs) // != 操作运算符重载
- {
- return !(*this == rhs);
- }
- }LNCFROUNDMENU_STYLE,*PLNCFROUNDMENU_STYLE;
除了风格自定义还支持自定义图标等功能,参考下面的变量
- ///菜单展开图标路径
- std::u16string sExpandImgPath;
-
- ///菜单闭合图标路径
- std::u16string sClosedImgPath;
头文件主要代码
- //默认构造函数
- explicit Lncf_QRoundMenuCtl(QWidget *parent = nullptr);
-
- /// 标准构造函数
- /// \brief Lncf_QRoundMenuCtl
- /// \param bPopup :是否为popup模式
- /// \param uBtnSize :中心按钮尺寸
- /// \param uItemType :菜单项类型,0圆角矩形,1扇形
- /// \param parent :父窗口句柄
- ///
- explicit Lncf_QRoundMenuCtl(bool bPopup,uint uBtnSize,uint uItemType = 0,QWidget *parent = nullptr);
-
- //标准析构
- ~Lncf_QRoundMenuCtl();
- private:
- /// 初始化圆形菜单控件
- /// \brief InitRoundMenuCtl
- ///
- void InitRoundMenuCtl();
- protected:
- // 重写系统事件
- bool event(QEvent *ev) override;
- // 重写系统绘制事件
- void paintEvent(QPaintEvent *event) override;
-
- /// 绘制控件圆形背景
- /// \brief DrawBackgroundCtl
- /// \param painter
- ///
- void DrawBackgroundCtl(QPainter *painter);
-
- /// 绘制菜单项圆形外边框
- /// \brief DrawItemOutBorder
- /// \param painter
- ///
- void DrawItemOutBorder(QPainter *painter);
-
- /// 绘制菜单项圆形内边框
- /// \brief DrawItemsInBorder
- /// \param painter
- ///
- void DrawItemsInBorder(QPainter *painter);
-
- /// 绘制菜单中心按钮
- /// \brief DrawSwitchsButton
- /// \param painter
- ///
- void DrawSwitchsButton(QPainter *painter);
-
- /// 绘制菜单项按钮
- /// \brief DrawMenuCtlButton
- /// \param painter
- ///
- void DrawMenuCtlButton(QPainter *painter);
-
- // 重写系统鼠标松开事件
- void mouseReleaseEvent(QMouseEvent *event) override;
- private:
- /// 初始化菜单动画
- /// \brief InitMenuAnimation
- ///
- void InitMenuAnimation();
-
- /// 获取菜单项外圆半径
- /// \brief GetItemsOutRadius
- /// \return
- ///
- qreal GetItemsOutRadius();
-
- /// 获取菜单项内圆半径
- /// \brief GetItemsInnRadius
- /// \return
- ///
- qreal GetItemsInnRadius();
-
- /// 获取菜单项目绘制开始角度
- /// \brief GetItemStartAngle
- /// \return
- ///
- qreal GetItemStartAngle();
-
- /// 获取菜单控件绘制弧度
- /// \brief GetFrmStartRadian
- /// \return
- ///
- qreal GetFrmStartRadian();
-
- /// 获取菜单切换按钮菜单绘图路径
- /// \brief GetSwitchBtnsPath
- /// \return
- ///
- QPainterPath GetSwitchBtnsPath();
-
- /// 获取菜单按钮绘图路径
- /// \brief GetMenuButtonPath
- /// \param index
- /// \param hover
- /// \return
- ///
- QPainterPath GetMenuButtonPath(int index, bool hover = false);
- private slots:
- /// 切换菜单按钮单击
- /// \brief MenuSwitchClicked
- ///
- void MenuSwitchClicked();
-
- /// 菜单项展开或收起
- /// \brief MenuItemBtnExpand
- /// \param bExpand
- ///
- void MenuItemBtnExpand(const bool& bExpand);
-
- /// 菜单项单击槽函数
- /// \brief MenuItemsBtnClick
- /// \param uIndex
- ///
- void MenuItemsBtnClick(const uint& uIndex);
- public:
- /// 添加菜单按钮项
- /// \brief AddMenuButtonItem
- /// \param tMenuItem
- /// 注意在插入和添加菜单时图标和title必须提供一个
- ///
- void AddMenuButtonItem(const LQROUNDMENUBTN_ITEM& tMenuItem);
-
- void AddMenuButtonItem(const QPixmap &icon, const QString &title, const QString &tooltip);
-
- void AddMenuButtonItem(const QPixmap &icon, const QString &title, const QString &tooltip,
- const QColor &background);
-
- void AddMenuButtonItem(const QPixmap &icon, const std::u16string &title, const std::u16string &tooltip,
- const QColor &background);
-
- /// 插入一个菜单按钮
- /// \brief InsertMenuBtnItem
- /// \param index
- /// \param tMenuItem
- ///
- void InsertMenuBtnItem(int index,LQROUNDMENUBTN_ITEM tMenuItem);
-
- /// 插入一个按钮项目
- /// \brief InsertMenuBtnItem
- /// \param index
- /// \param icon
- /// \param title
- /// \param tooltip
- /// \param background
- ///
- void InsertMenuBtnItem(int index, const QPixmap &icon, const QString &title, const QString &tooltip,
- const QColor &background = QColor());
-
- void InsertMenuBtnItem(int index, const QPixmap &icon, const std::u16string &title, const std::u16string &tooltip,
- const QColor &background = QColor());
-
- /// 获取菜单展开图标路径
- /// \brief GetExpandImgPath
- /// \return
- ///
- std::u16string GetExpandImgPath() const;
-
- /// 获取菜单闭合图标路径
- /// \brief GetClosedImgPath
- /// \return
- ///
- std::u16string GetClosedImgPath() const;
-
- /// 设置菜单展开图标路径
- /// \brief SetExpandImgPath
- /// \param sImage
- ///
- void SetExpandImgPath(const std::u16string& sImage);
-
- /// 设置菜单闭合图标路径
- /// \brief SetClosedImgPath
- /// \param sImage
- ///
- void SetClosedImgPath(const std::u16string& sImage);
核心绘图代码如下
- // 重写系统绘制事件
- void Lncf_QRoundMenuCtl::paintEvent(QPaintEvent *event)
- {
- QWidget::paintEvent(event);
-
- QPainter painter(this);
- painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
-
- //绘制背景
- if(this->tMenuCtrlStyles.bShowCtrlBkgnd)
- DrawBackgroundCtl(&painter);
-
- //绘制菜单按钮
- DrawMenuCtlButton(&painter);
-
- //绘制中心按钮
- if(this->tMenuCtrlStyles.bDrawCenterBtn)
- DrawSwitchsButton(&painter);
- }
-
- /// 绘制控件圆形背景
- /// \brief DrawBackgroundCtl
- /// \param painter
- ///
- void Lncf_QRoundMenuCtl::DrawBackgroundCtl(QPainter *painter)
- {
- painter->setPen(this->tMenuCtrlStyles.bShowBkgBorder?QPen(tMenuCtrlStyles.cBkgBorderClrs,tMenuCtrlStyles.dBkgBordersWid):Qt::NoPen);
- if(this->tMenuCtrlStyles.vMenuCtlBkgClr.count()>0){
- QLinearGradient gradient(QPoint(0, 0), QPoint(width(), height()));
- for(int i=0;i<tMenuCtrlStyles.vMenuCtlBkgClr.count();i++)
- gradient.setColorAt(tMenuCtrlStyles.vMenuCtlBkgClr[i].fBkgndAngleVal, tMenuCtrlStyles.vMenuCtlBkgClr[i].cBkgndAngleClr);
- painter->setBrush(gradient);
- }
- else{
- painter->setBrush(this->tMenuCtrlStyles.cMenuCtlBkgClr);
- }
- QRectF rect = this->rect();
- uint uRectMinVal = qMin(this->width(),this->height());
- rect.setSize(QSize(uRectMinVal*tMenuCtrlStyles.dFrameOutScale,uRectMinVal*tMenuCtrlStyles.dFrameOutScale));
- rect.moveCenter(QPointF(width() / 2.0, height() / 2.0));
- painter->drawEllipse(rect);
- }
-
- /// 绘制菜单项圆形外边框
- /// \brief DrawItemOutBorder
- /// \param painter
- ///
- void Lncf_QRoundMenuCtl::DrawItemOutBorder(QPainter *painter)
- {
- QRectF rect(0.0, 0.0, 2.0 * GetItemsOutRadius(), 2.0 * GetItemsOutRadius());
- rect.moveCenter(QPointF(width() / 2.0, height() / 2.0));
-
- painter->save();
- painter->setPen(QPen(QBrush(this->tMenuCtrlStyles.cItemBorderClr), tMenuCtrlStyles.dItemBorderWid));
- painter->drawEllipse(rect);
- painter->restore();
- }
-
- /// 绘制菜单项圆形内边框
- /// \brief DrawItemsInBorder
- /// \param painter
- ///
- void Lncf_QRoundMenuCtl::DrawItemsInBorder(QPainter *painter)
- {
- QRectF rect(0.0, 0.0, 2.0 * GetItemsInnRadius(), 2.0 * GetItemsInnRadius());
- rect.moveCenter(QPointF(width() / 2.0, height() / 2.0));
-
- painter->save();
- painter->setPen(QPen(QBrush(this->tMenuCtrlStyles.cItemBorderClr), tMenuCtrlStyles.dItemBorderWid));
- painter->drawEllipse(rect);
- painter->restore();
- }
-
- int imageRotate =0;
- /// 绘制菜单中心按钮
- /// \brief DrawSwitchsButton
- /// \param painter
- ///
- void Lncf_QRoundMenuCtl::DrawSwitchsButton(QPainter *painter)
- {
- auto path = GetSwitchBtnsPath();
-
- painter->setBrush(bSwitchBnHover?tMenuCtrlStyles.cSwicthBnHover:(bHasExpandMenu ? tMenuCtrlStyles.cSwicthExpands : tMenuCtrlStyles.cSwicthBnColor));
- painter->setPen(tMenuCtrlStyles.bHasItemBorder?QPen(tMenuCtrlStyles.cItemBorderClr,tMenuCtrlStyles.dItemBorderWid):Qt::NoPen);
-
- painter->drawPath(path);
-
- auto pixmap = bHasExpandMenu ? QPixmap(QString::fromStdU16String(sClosedImgPath)) :
- QPixmap(QString::fromStdU16String(sExpandImgPath));
- auto rect = path.boundingRect();
-
- if(!pixmap.isNull()){
- rect = rect.marginsRemoved(QMargins(rect.width() / 4.0,
- rect.height() / 4.0,
- rect.width() / 4.0,
- rect.height() / 4.0));
-
- painter->drawPixmap(rect, pixmap, pixmap.rect());
- }
- else{
- rect = rect.marginsRemoved(QMargins(rect.width() / 4.0,
- rect.height() / 4.0,
- rect.width() / 4.0,
- rect.height() / 4.0));
-
- std::u16string sSwicthText = bHasExpandMenu ? u"MENU":
- u"CLOSE";
-
- QFont fontObj = this->font();
- fontObj.setPointSizeF(rect.height()/4.0);
- painter->setFont(fontObj);
-
- painter->setPen(bSwitchBnHover?tMenuCtrlStyles.cMenuBtnTxtClr:tMenuCtrlStyles.cMenuTextHover);
-
- painter->drawText(rect, Qt::AlignCenter|Qt::TextWordWrap,QString::fromStdU16String(sSwicthText));
- }
- }
-
- /// 绘制菜单项按钮
- /// \brief DrawMenuCtlButton
- /// \param painter
- ///
- void Lncf_QRoundMenuCtl::DrawMenuCtlButton(QPainter *painter)
- {
- if(pMenuAnimeGroup->state() != QAbstractAnimation::Running){
- if(!bHasExpandMenu||vMenuButtonList.count()<=0){
- return;
- }
- }
-
- if(this->tMenuCtrlStyles.bShowItemsLine&&!this->tMenuCtrlStyles.bRoundMenuItem){
- DrawItemOutBorder(painter);
- DrawItemsInBorder(painter);
- }
-
- auto count = vMenuButtonList.count();
- if(count == 0) return;
-
- auto radian = 2 * PI / count;
- auto outer_radius = GetItemsOutRadius();
- auto inner_radius = GetItemsInnRadius();
-
- QFont fontObj = this->font();
-
- for (int i = 0 ; i< count; ++i)
- {
- auto path = GetMenuButtonPath(i);
-
- //绘制背景
- auto bgColor = this->tMenuCtrlStyles.bHasRandomClrs?QColor::fromHsl(rand()%360,rand()%256,rand()%200):vMenuButtonList.at(i)->cCustomBkgClr;
- if(!bgColor.isValid()){
- bgColor = this->tMenuCtrlStyles.cMenuBtnBkgClr;
- }
-
- auto iconRectWidth = outer_radius - inner_radius;
-
- if(!this->tMenuCtrlStyles.bRoundMenuItem){
- painter->fillPath(path,vMenuButtonList.at(i)->bIsHoverState?this->tMenuCtrlStyles.cMenuBtnHovers:bgColor);
- }
- else{
- QRectF rectBtnBkg(0, 0, iconRectWidth / this->tMenuCtrlStyles.dItemsBkgScale, iconRectWidth / this->tMenuCtrlStyles.dItemsBkgScale);
- rectBtnBkg.moveCenter(path.boundingRect().center());
-
- painter->setBrush(vMenuButtonList.at(i)->bIsHoverState?this->tMenuCtrlStyles.cMenuBtnHovers:bgColor);
- painter->setPen(tMenuCtrlStyles.bHasItemBorder?QPen(tMenuCtrlStyles.cItemBorderClr,tMenuCtrlStyles.dItemBorderWid):Qt::NoPen);
- painter->drawRoundedRect(rectBtnBkg,rectBtnBkg.width()*tMenuCtrlStyles.dBnRoundRadius,rectBtnBkg.height()*tMenuCtrlStyles.dBnRoundRadius);
- }
-
- auto pixmapIcon = vMenuButtonList.at(i)->pMenuItemIcon;
- if(!pixmapIcon.isNull()){
- QRectF rectIcon(0, 0, iconRectWidth / this->tMenuCtrlStyles.dItemsBtnScale, iconRectWidth / this->tMenuCtrlStyles.dItemsBtnScale);
- rectIcon.moveCenter(path.boundingRect().center());
-
- painter->drawPixmap(rectIcon, pixmapIcon, pixmapIcon.rect());
- }
- else{
- QRectF rectText(0, 0, iconRectWidth / this->tMenuCtrlStyles.dItemsBtnScale*0.95, iconRectWidth / this->tMenuCtrlStyles.dItemsBtnScale*0.95);
- rectText.moveCenter(path.boundingRect().center());
- fontObj.setPointSizeF(rectText.height()/4.0);
- painter->setFont(fontObj);
- painter->setPen(vMenuButtonList.at(i)->bIsHoverState?tMenuCtrlStyles.cMenuTextHover:tMenuCtrlStyles.cMenuBtnTxtClr);
- painter->drawText(rectText, Qt::AlignCenter|Qt::TextWordWrap, QString::fromStdU16String(vMenuButtonList.at(i)->uItemTitleVal));
- }
-
- /***************************
- * draw seperator
- * */
- if(this->tMenuCtrlStyles.bShowItemsLine&&!this->tMenuCtrlStyles.bRoundMenuItem){
- QPointF point1(width() / 2.0 + outer_radius * std::cos(radian * i + GetFrmStartRadian()),
- height() / 2.0 - outer_radius * std::sin(radian * i + GetFrmStartRadian()));
- QPointF point2(width() / 2.0 + inner_radius * std::cos(radian * i + GetFrmStartRadian()),
- height() / 2.0 - inner_radius * std::sin(radian * i + GetFrmStartRadian()));
-
- painter->save();
- painter->setPen(QPen(QBrush(tMenuCtrlStyles.cItemBorderClr), tMenuCtrlStyles.dBkgBordersWid));
- painter->drawLine(point1, point2);
- painter->restore();
- }
- }
- }
大半夜刚封装完,困的实在类,先写到这。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。