Qt 之悬浮球菜单

news/2024/7/9 4:59:42

朝十晚八

Qt 之悬浮球菜单

目录

  • 一、概述
  • 二、效果展示
  • 三、实现代码
    • 1、菜单项
    • 2、悬浮球
    • 3、关键点
  • 四、相关文章

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

一、概述

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

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

二、效果展示

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

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

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

三、实现代码

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

1、菜单项

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

class PopRingItem : public QLabel
{
	Q_OBJECT

public:
	PopRingItem(QWidget *parent = 0);
	~PopRingItem();

	void SetRadius(int radius);
	int GetRadius() const;

	void BindAction(QAction * action);

signals:
	void MouseEvent(bool);

protected:
	virtual void enterEvent(QEvent * event) override;
	virtual void leaveEvent(QEvent * event) override;

	virtual void paintEvent(QPaintEvent * event) override;

protected:
	int m_iRadius = 50;
	QAction * m_actAction = nullptr;
};

2、悬浮球

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

class QVariantAnimation;
class QPropertyAnimation;
class PopRingMenu : public PopRingItem
{
	Q_OBJECT

public:
	PopRingMenu(QWidget *parent = 0);
	~PopRingMenu();

signals:
	void DoubleClicked();

public:
	void SetActions(const QVector<QAction *> & acts);
	void SetIcons(const QVector<QString> & icons);

	void SetAnimationEnabled(bool enabled);
	bool IsAnimationEnabled() const;

	void SetSlowlyFade(bool enabled);
	bool IsSlowlyFade() const;

	void SetDistanced(int distance);
	int GetDistanced() const;

	void SetStartAngle(int angle);
	int GetStartAngle() const;

	void SetStepAngle(int angle);
	int GetStepAngle() const;

	void SetNormalMenuSize(int size);
	int GetNormalMenuSize() const;
	void SetNormalItemSize(int size);
	int GetNormalItemSize() const;

protected:
	virtual void enterEvent(QEvent * event) override;
	virtual void leaveEvent(QEvent * event) override;
	virtual void mouseDoubleClickEvent(QMouseEvent * event) override;

	virtual void timerEvent(QTimerEvent * event) override;
	virtual bool event(QEvent * event) override;

private slots:
	void OnMouseEvent(bool);

private:
	void UpdateActions(int msecond);

	void ExpandMenu();
	void CollapseMenu();

	void SlowlyFade();
	void QuicklyLighter();

	bool IsUnderMouse() const;

	void TryCollapseMenu();
	void KillHideTimer();

private:
	int m_iDistance = 70;
	int m_iStartAngle = 0;
	int m_iStepAngle = 60;

	int m_iMenuSize = 70;
	int m_iItemSize = 60;

	int m_iTimerID = -1;

	QPropertyAnimation * m_pOpacityAnimation = nullptr;
	QVariantAnimation * m_pItemAnimation = nullptr;
	QVector<PopRingItem *> m_items;
};

3、关键点

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

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

m_pItemAnimation = new QVariantAnimation(this);

m_pItemAnimation->setEasingCurve(QEasingCurve::InCubic);
m_pItemAnimation->setStartValue(ShowMenuStartValue);
m_pItemAnimation->setEndValue(ShowMenuEndValue);
m_pItemAnimation->setDuration(ShowMenuDuration);

connect(m_pItemAnimation, &QVariantAnimation::valueChanged, this, [this](const QVariant & v){
	UpdateActions(v.toInt());
});

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

void PopRingMenu::ExpandMenu()
{
	if (m_pItemAnimation)
	{
		if (m_pItemAnimation->state() != QAbstractAnimation::Running
			&& m_pItemAnimation->currentValue().toInt() != ShowMenuEndValue)
		{
			m_pItemAnimation->setDirection(QVariantAnimation::Forward);
			m_pItemAnimation->start();
		}
	}
	else
	{
		UpdateActions(ShowMenuEndValue);
	}

	KillHideTimer();
	QuicklyLighter();
}
  1. 鼠标离开悬浮球时,执行收起动画,与展开动画相反方向
  2. 收起动画时有一个细节点,那就是鼠标 hover 在菜单项上时,也不能收起
void PopRingMenu::CollapseMenu()
{
	if (false == IsUnderMouse())
	{
		if (m_pItemAnimation)
		{
			m_pItemAnimation->setDirection(QVariantAnimation::Backward);
			m_pItemAnimation->start();
		}
		else
		{
			UpdateActions(ShowMenuStartValue);
		}

		KillHideTimer();
		SlowlyFade();
	}
}

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

void PopRingMenu::UpdateActions(int msecond)
{
	int curDistance = msecond * m_iDistance / ShowMenuEndValue;
	for (int i = 0; i < m_items.size(); ++i)
	{
		PopRingItem * item = m_items.at(i);
		
		double radians = qDegreesToRadians(m_iStepAngle * i * 1.0 + m_iStartAngle);
		int offx = curDistance * qCos(radians);
		int offy = curDistance * qSin(radians);
		item->move(pos() + QPoint(offx, offy));

		int curSize = msecond * m_iItemSize / ShowMenuEndValue;
		item->SetRadius(curSize);

		item->setVisible(ShowMenuStartValue != msecond);
	};

	::SetWindowPos(HWND(winId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}

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

void PopRingMenu::SetSlowlyFade(bool enabled)
{
	if (enabled)
	{
		if (nullptr == m_pOpacityAnimation)
		{
			m_pOpacityAnimation = new QPropertyAnimation(this, "opacity");
			m_pOpacityAnimation->setEasingCurve(QEasingCurve::OutCubic);
			m_pOpacityAnimation->setStartValue(SlowlyStartValue);
			m_pOpacityAnimation->setEndValue(SlowLyEndValue);
			m_pOpacityAnimation->setDuration(SlowlyFadeDuration);
		}
	}
	else
	{

		if (m_pOpacityAnimation)
		{
			delete m_pOpacityAnimation;
			m_pOpacityAnimation = nullptr;
		}
	}
}

四、相关文章

  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 学习案例 , 定制控件


http://lihuaxi.xjx100.cn/news/117751.html

相关文章

spring cloud kubernetes踩坑:Null key for a Map not allowed in JSON

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 背景 最近在做spring cloud kubernetes改造调研&#xff0c;然后在获取服务元数据的时候遇到了这个错误 Null key for a Map not allowed in JSON 项目搭建还原…

宠物赛道意外火了,行业龙头们相继奔赴IPO

如今&#xff0c;吸猫撸狗、携宠社交正逐渐成为当代年轻人新的生活方式&#xff0c;而能为宠物提供食品、用品、医疗、美容、训练、殡葬、交易等全产业链服务的宠物公司的出现&#xff0c;则大大降低了“铲屎官”养宠物的门槛。于是&#xff0c;随着年轻人喂养宠物逐渐趋于精细…

彻底理解Java并发:volatile关键字

本篇内容包括&#xff1a;volatile 关键字简介、volatile 保证可见性&#xff08;包括&#xff1a;关乎不可见性问题描述、JMM内存模型和不可见性的解决方案&#xff09;以及 volatile 其他特性&#xff08;包括&#xff1a;volatile 不保证原子性、volatile 原子性的保证操作、…

二十一、SpringBoot + Jwt + Vue 权限管理系统 (2)

&#x1f33b;&#x1f33b; 目录一、后台管理界面开发1.1 引入Element-ui布局1.2 修改页面样式1.3 左侧导航菜单填充1.4 拆分抽取Vue组件1.5 编写导航栏的路由二、 用户登录信息展示2.1 用户信息展示2.2 个人中心展示2.3 前端用户退出操作一、后台管理界面开发 1.1 引入Eleme…

ADRC/Matlab一步步实现跟踪微分器TD(附完整PLC测试代码链接)

TD微分器的主要作用:就是安排过渡过程,产生跟踪信号和微分信号,滤除噪声。 关于Adrc的理论分析不是本篇博客的重点,主要也是能力所限,相关理论大家可以看韩京清教授的论文,专栏有简单的学习笔记,感兴趣的同学可以看看,链接如下: ADRC自抗扰的基本框架学习笔记_RXXW_…

deepstream中Gst-nvmsgconv和Gst-nvmsgbroker两个插件的作用和关系

deepstream中Gst-nvmsgconv和Gst-nvmsgbroker两个插件的作用和关系 整体理解:细节讲解: nvmsgconv插件细节讲解:nvmsgbroker插件整体理解: **Gst-nvmsgconv:**是用来将元数据转换为schema ,其中包括两种schema,一种是数据比较全的schema数据,一种是简化的数据。最后转换…

【Spark NLP】第 7 章:分类和回归

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

安卓终端神器Termux (后面还有Termux常用的快捷键,妥妥干货分享,记得点赞收藏哦!)

最近在网上找到一款安卓平台的linux终端模拟器&#xff0c;使用pkg(apt)进行软件包管理&#xff0c;最终要的是&#xff0c;他无需root权限&#xff0c;因此市面上大部分安卓平台手机都可以运行。也就是说以后小编不但可以坐着敲代码&#xff0c;还可以敲着代码入睡啦&#xff…