• Qt 之悬浮球菜单


    朝十晚八

    Qt 之悬浮球菜单

    目录

    原文链接:Qt 之悬浮球菜单

    一、概述

    最近想做一个炫酷的悬浮式菜单,考虑到菜单展开和美观,所以考虑学习下 Qt 的动画系统和状态机内容,打开 QtCreator 的示例教程浏览了下,大致发现教程中 2D Painting 程序和 Animated Tiles 程序有所帮助,如下图所示,这两个 demo 讲述了怎么做一个展开动画,感兴趣的同学也可以直接参考

    有了这两个 demo 之后,就可以开始动工写咱们自己的程序。

    二、效果展示

    如下两幅图就是作者失效的两个悬浮菜单效果图,展示图 1 代码已上传至 CSDN,不需要积分即可下载,效果图 2 代码暂时不开源,有需要的朋友可以进一步咨询

    基础圆形菜单功能,代码已上传 CSDN - Qt 失效的 PC 端环形菜单、悬浮球菜单、展开动画

    高级悬浮球菜单、支持二级菜单打开

    三、实现代码

    实现文件比较简单,只有头文件和实现文件,这里先主要放出头文件,然后讲解实现思路,具体实现细节可以通过下载源码进行具体了解

    1、菜单项

    PopRingItem 为菜单展开项、可以通过绑定外部 QAction 实现与普通菜单相同功能

    1. class PopRingItem : public QLabel
    2. {
    3. Q_OBJECT
    4. public:
    5. PopRingItem(QWidget *parent = 0);
    6. ~PopRingItem();
    7. void SetRadius(int radius);
    8. int GetRadius() const;
    9. void BindAction(QAction * action);
    10. signals:
    11. void MouseEvent(bool);
    12. protected:
    13. virtual void enterEvent(QEvent * event) override;
    14. virtual void leaveEvent(QEvent * event) override;
    15. virtual void paintEvent(QPaintEvent * event) override;
    16. protected:
    17. int m_iRadius = 50;
    18. QAction * m_actAction = nullptr;
    19. };

    2、悬浮球

    悬浮球为菜单入口,继承自菜单项,与菜单项有相似功能

    1. class QVariantAnimation;
    2. class QPropertyAnimation;
    3. class PopRingMenu : public PopRingItem
    4. {
    5. Q_OBJECT
    6. public:
    7. PopRingMenu(QWidget *parent = 0);
    8. ~PopRingMenu();
    9. signals:
    10. void DoubleClicked();
    11. public:
    12. void SetActions(const QVector & acts);
    13. void SetIcons(const QVector & icons);
    14. void SetAnimationEnabled(bool enabled);
    15. bool IsAnimationEnabled() const;
    16. void SetSlowlyFade(bool enabled);
    17. bool IsSlowlyFade() const;
    18. void SetDistanced(int distance);
    19. int GetDistanced() const;
    20. void SetStartAngle(int angle);
    21. int GetStartAngle() const;
    22. void SetStepAngle(int angle);
    23. int GetStepAngle() const;
    24. void SetNormalMenuSize(int size);
    25. int GetNormalMenuSize() const;
    26. void SetNormalItemSize(int size);
    27. int GetNormalItemSize() const;
    28. protected:
    29. virtual void enterEvent(QEvent * event) override;
    30. virtual void leaveEvent(QEvent * event) override;
    31. virtual void mouseDoubleClickEvent(QMouseEvent * event) override;
    32. virtual void timerEvent(QTimerEvent * event) override;
    33. virtual bool event(QEvent * event) override;
    34. private slots:
    35. void OnMouseEvent(bool);
    36. private:
    37. void UpdateActions(int msecond);
    38. void ExpandMenu();
    39. void CollapseMenu();
    40. void SlowlyFade();
    41. void QuicklyLighter();
    42. bool IsUnderMouse() const;
    43. void TryCollapseMenu();
    44. void KillHideTimer();
    45. private:
    46. int m_iDistance = 70;
    47. int m_iStartAngle = 0;
    48. int m_iStepAngle = 60;
    49. int m_iMenuSize = 70;
    50. int m_iItemSize = 60;
    51. int m_iTimerID = -1;
    52. QPropertyAnimation * m_pOpacityAnimation = nullptr;
    53. QVariantAnimation * m_pItemAnimation = nullptr;
    54. QVector m_items;
    55. };

    3、关键点

    初始化动画对象,指定动画时长和动画起始、终止值

    动画具体实现函数未 UpdateAction,根据当前动画进度值在动画起始值和终止值所占比例,进行计算当前动画时刻菜单项的位置和大小

    1. m_pItemAnimation = new QVariantAnimation(this);
    2. m_pItemAnimation->setEasingCurve(QEasingCurve::InCubic);
    3. m_pItemAnimation->setStartValue(ShowMenuStartValue);
    4. m_pItemAnimation->setEndValue(ShowMenuEndValue);
    5. m_pItemAnimation->setDuration(ShowMenuDuration);
    6. connect(m_pItemAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant & v){
    7. UpdateActions(v.toInt());
    8. });

    鼠标进入悬浮球时,执行展开动画

    1. void PopRingMenu::ExpandMenu()
    2. {
    3. if (m_pItemAnimation)
    4. {
    5. if (m_pItemAnimation->state() != QAbstractAnimation::Running
    6. && m_pItemAnimation->currentValue().toInt() != ShowMenuEndValue)
    7. {
    8. m_pItemAnimation->setDirection(QVariantAnimation::Forward);
    9. m_pItemAnimation->start();
    10. }
    11. }
    12. else
    13. {
    14. UpdateActions(ShowMenuEndValue);
    15. }
    16. KillHideTimer();
    17. QuicklyLighter();
    18. }
    1. 鼠标离开悬浮球时,执行收起动画,与展开动画相反方向
    2. 收起动画时有一个细节点,那就是鼠标 hover 在菜单项上时,也不能收起
    1. void PopRingMenu::CollapseMenu()
    2. {
    3. if (false == IsUnderMouse())
    4. {
    5. if (m_pItemAnimation)
    6. {
    7. m_pItemAnimation->setDirection(QVariantAnimation::Backward);
    8. m_pItemAnimation->start();
    9. }
    10. else
    11. {
    12. UpdateActions(ShowMenuStartValue);
    13. }
    14. KillHideTimer();
    15. SlowlyFade();
    16. }
    17. }

    展开和收起动画实现细节,根据动画指定帧数,按比例进行缩放和移动菜单项

    1. void PopRingMenu::UpdateActions(int msecond)
    2. {
    3. int curDistance = msecond * m_iDistance / ShowMenuEndValue;
    4. for (int i = 0; i < m_items.size(); ++i)
    5. {
    6. PopRingItem * item = m_items.at(i);
    7. double radians = qDegreesToRadians(m_iStepAngle * i * 1.0 + m_iStartAngle);
    8. int offx = curDistance * qCos(radians);
    9. int offy = curDistance * qSin(radians);
    10. item->move(pos() + QPoint(offx, offy));
    11. int curSize = msecond * m_iItemSize / ShowMenuEndValue;
    12. item->SetRadius(curSize);
    13. item->setVisible(ShowMenuStartValue != msecond);
    14. };
    15. ::SetWindowPos(HWND(winId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    16. }

    悬浮球指定时间未激活时,淡出,减少对用户视觉冲击

    1. void PopRingMenu::SetSlowlyFade(bool enabled)
    2. {
    3. if (enabled)
    4. {
    5. if (nullptr == m_pOpacityAnimation)
    6. {
    7. m_pOpacityAnimation = new QPropertyAnimation(this, "opacity");
    8. m_pOpacityAnimation->setEasingCurve(QEasingCurve::OutCubic);
    9. m_pOpacityAnimation->setStartValue(SlowlyStartValue);
    10. m_pOpacityAnimation->setEndValue(SlowLyEndValue);
    11. m_pOpacityAnimation->setDuration(SlowlyFadeDuration);
    12. }
    13. }
    14. else
    15. {
    16. if (m_pOpacityAnimation)
    17. {
    18. delete m_pOpacityAnimation;
    19. m_pOpacityAnimation = nullptr;
    20. }
    21. }
    22. }

    四、相关文章

    1. qt 之菜单项定制
    2. Qt 之 QAbstractItemView 右键菜单
    3. Qt 弹出式菜单阴影
    4. Qt 之自定义 QLineEdit 右键菜单
    5. Qt 之股票组件 - 自选股 -- 列表可以拖拽、右键常用菜单

    值得一看的优秀文章:

    1. 财联社 - 产品展示
    2. 广联达 - 产品展示
    3. Qt 定制控件列表
    4. 牛逼哄哄的 Qt 库

    如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!!
     


    很重要 -- 转载声明

    1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords

    2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。


    奋斗中的无名小卒。。。

    分类: qt 项目案例 , qt 经典文章 , qt 学习案例 , 定制控件

  • 相关阅读:
    如何做架构设计?
    【Java八股文总结】之消息队列
    Matlab 如何计算正弦信号的幅值和初始相角
    【恒源智享云】conda虚拟环境的操作指令
    MDC、ThreadLocal、InheritableThreadLocal的区别和联系
    NV040D语音芯片丨助力空气净化器语音功能
    分账系统二清解决方案如何助力电商平台合规经营?
    序列化进阶2-常见序列化框架
    (三)带权重和ignore_index的交叉熵损失函数
    SQL SERVER中XML查询:FOR XML指定RAW
  • 原文地址:https://blog.csdn.net/qq_30392343/article/details/127582384