无边框窗口移动到桌面边缘动画

本文介绍如何在Qt中实现无边框窗口移动至屏幕边缘时的平滑动画效果,通过自定义透明窗口和使用QPropertyAnimation实现窗口变化过程中的动画。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Qt 之无边框窗口移动到桌面边缘动画

说明

无边框窗口在移动到桌面边缘时不会自动全屏或者半屏,网上有些资料能实现全屏或者半屏,但是窗口变化过程中没有动画。所以我想实践下能不能实现windows原生的效果。

实现思路

以一个透明有边框的窗口进行变换为基准。需要用到继承QWidget, 自绘(paintEvent), 动画(QPropertyAnimation)等知识

透明窗口

MoveResizeWidget.h
目的是画出一个透明的 带边框的窗口

#include <QWidget>
#include <QPropertyAnimation>

class QMoveResizeWidget : public QWidget
{
	Q_OBJECT
public:
	//开始动画
	void startAnimation(const QVariant& startV, const QVariant& endV);
	//停止动画
	void stopAnimation();
protected:
	void paintEvent(QPaintEvent *event);
	//显示事件
	void showEvent(QShowEvent *event);
	//隐藏事件
	void hideEvent(QHideEvent *event);
private:
	画阴影
	void drawShadow(QPainter* painter);
public:
	bool m_bHelpWidhetShow;				//窗口是否显示
	QRect m_endRect;							//目标位置
private:
	QPropertyAnimation* x_pAnimation;		//动画框架
};

MoveResizeWidget.cpp

#include "MoveResizWidget.h"

#include <QPainter>

QMoveResizeWidget::QMoveResizeWidget(QWidget* parent /*= nullptr*/)
	:QWidget(parent)
	, x_pAnimation(nullptr)
{
	//设置为无边框 工具
	setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
	//设置背景透明
	setAttribute(Qt::WA_TranslucentBackground);
	//默认不显示
	m_bHelpWidhetShow = false;
	//动画框架
	x_pAnimation = new QPropertyAnimation(this, "geometry");
	x_pAnimation->setDuration(100);
}
QMoveResizeWidget::~QBaseWidget()
{
}

void QMoveResizeWidget::startAnimation(const QVariant& startV, const QVariant& endV)
{
	//将辅助窗口移动到发起窗口相同的位置
	this->setGeometry(startV.toRect());
	//存储目的位置
	m_endRect = endV.toRect();
	//将辅助窗口显示出来
	show();
	//设置动画的起止值
	x_pAnimation->setStartValue(startV);
	x_pAnimation->setEndValue(endV);
	//开始动画
	x_pAnimation->start();
}
void QMoveResizeWidget::stopAnimation()
{
	//停止动画并隐藏辅助窗口
	x_pAnimation->stop();
	hide();
}
void QMoveResizeWidget::paintEvent(QPaintEvent *event)
{
	Q_UNUSED(event);
	//画图
	QPainter painter(this);
	//反锯齿
	painter.setRenderHint(QPainter::Antialiasing);
	//画阴影
	drawShadow(&painter);
}

void QMoveResizeWidget::showEvent(QShowEvent *event)
{
	Q_UNUSED(event);

	m_bHelpWidhetShow = true;
}

void QMoveResizeWidget::hideEvent(QHideEvent *event)
{
	Q_UNUSED(event);

	m_bHelpWidhetShow = false;
}

void QMoveResizeWidget::drawShadow(QPainter* painter)
{
	//画阴影
	painter->save();

	QPainterPath path;
	path.setFillRule(Qt::WindingFill);
	path.addRoundedRect(10, 10, this->width() - 20, this->height() - 20, 5, 5);

	painter->setRenderHint(QPainter::Antialiasing, true);
//	painter->fillPath(path, QBrush(Qt::red));
//	QColor color(92, 93, 95, 50);
	QColor color(Qt::red);			//阴影颜色  这里为了显眼使用红色

	int arr[10] = { 150, 120, 80, 50, 40, 30, 20, 10, 5, 5 };
	for (int i = 0; i < 10; i++)
	{
		QPainterPath path;
		path.setFillRule(Qt::WindingFill);
		if (i == 5)
			path.addRect(10 - i - 1, 10 - i - 1, this->width() - (10 - i) * 2, this->height() - (10 - i) * 2);
		else
			path.addRoundedRect(10 - i - 1, 10 - i - 1, this->width() - (10 - i) * 2, this->height() - (10 - i) * 2, 5, 5);

		color.setAlpha(arr[i]);
		painter->setPen(color);
		painter->drawPath(path);
	}

	painter->restore();
}
		

帮助类

MoveResizeHelper.h

#include <QObject>
#include <QMap>

#include "MoveResizWidget.h"

class QMoveReSizeHeler : public QObject
{
	Q_OBJECT

public:
	QReSizeHeler(QObject *parent = nullptr);
	~QReSizeHeler();

	void activeOn(QWidget* widget);

	void removeFrom(QWidget* widget);

	bool eventFilter(QObject *watched, QEvent *event);

private:
	QMoveResizeWidget* x_pBaseWidget;
	QMap<QWidget*, bool> x_widgetMap;
};

MoveResizeHelper.cpp

#include "MoveResizeHelper.h"

QMoveResizeHelper::QMoveResizeHelper(QObject *parent /*= nullptr*/)
	:QObject(parent)
{
	x_pBaseWidget = new QMoveResizeWidget();
	x_pBaseWidget ->hide();
}

QReSizeHeler::~QReSizeHeler()
{
	if (x_pBaseWidget)
	{
		delete x_pBaseWidget;
		x_pBaseWidget = nullptr;
	}
}

void QMoveResizeHelper::activeOn(QWidget* widget)
{
	x_widgetMap.insert(widget, false);
	//安装事件监视器
	widget->installEventFilter(this);
}

void QMoveResizeHelper::removeFrom(QWidget* widget)
{
	x_widgetMap.remove(widget);
}

bool QMoveResizeHelper::eventFilter(QObject *watched, QEvent *event)
{
	QWidget* _pWidget = (QWidget*)(watched);

	if (x_widgetMap.contains(_pWidget))
	{
		if (event->type() == QEvent::MouseButtonPress)
		{
			x_widgetMap[_pWidget] = true;
		}
		else if (event->type() == QEvent::MouseMove)
		{
			if (x_widgetMap[_pWidget] == true)
			{
				QMouseEvent* _pEvent = (QMouseEvent*)(event);

				QPoint _pos = _pEvent->globalPos();

				QRect _rect = QApplication::desktop()->availableGeometry();

				if (_rect.width() - _pos.x() < 10)
				{
					//移动到最右边
					if (!x_pBaseWidget->m_bHelpWidhetShow)
					{
						//辅助窗口未显示, 开始动画
						x_pBaseWidget->startAnimation(_pWidget->geometry(), QRect(_rect.width() / 2, 0, _rect.width() / 2, _rect.height()));
					}
				}
				else if (_pos.x() < 10)
				{
					//移动到最左边
					if (!x_pBaseWidget->m_bHelpWidhetShow)
					{
						x_pBaseWidget->startAnimation(_pWidget->geometry(), QRect(0, 0, _rect.width() / 2, _rect.height()));
					}
				}
				else if (_pos.y() < 10)
				{
					//移动到顶部
					if (!x_pBaseWidget->m_bHelpWidhetShow)
					{
						x_pBaseWidget->startAnimation(_pWidget->geometry(), QRect(0, 0, _rect.width(), _rect.height()));
					}
				}
				else
				{
					//隐藏辅助窗口
					x_pBaseWidget->hide();
				}
			}
		}
		else if (event->type() == QEvent::MouseButtonRelease)
		{
			x_widgetMap[_pWidget] = false;
			if (x_pBaseWidget->m_bHelpWidhetShow)
			{
				//辅助窗口显示, 将窗口置为目标位置
				_pWidget->setGeometry(x_pBaseWidget->m_endRect);
			}
			//停止动画
			x_pBaseWidget->stopAnimation();

		}
	}
	
	return QObject::eventFilter(watched, event);
}

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码分享

Qt无边框窗口模仿windows原生窗口桌面边缘移动动画

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值