窗口翻转动画(仿QQ)

This commit is contained in:
Irony 2019-05-15 22:19:29 +08:00
parent 756f4fd0f1
commit e68853c536
8 changed files with 262 additions and 1 deletions

View file

@ -35,6 +35,7 @@ encoding//QProgressBar/MetroCircleProgress.py=utf-8
encoding//QProgressBar/PercentProgressBar.py=utf-8 encoding//QProgressBar/PercentProgressBar.py=utf-8
encoding//QProgressBar/SimpleStyle.py=utf-8 encoding//QProgressBar/SimpleStyle.py=utf-8
encoding//QProgressBar/WaterProgressBar.py=utf-8 encoding//QProgressBar/WaterProgressBar.py=utf-8
encoding//QPropertyAnimation/FlipWidgetAnimation.py=utf-8
encoding//QPropertyAnimation/Lib/SlidingStackedWidget.py=utf-8 encoding//QPropertyAnimation/Lib/SlidingStackedWidget.py=utf-8
encoding//QPropertyAnimation/MenuAnimation.py=utf-8 encoding//QPropertyAnimation/MenuAnimation.py=utf-8
encoding//QPropertyAnimation/ShakeWindow.py=utf-8 encoding//QPropertyAnimation/ShakeWindow.py=utf-8

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -0,0 +1,127 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2019年5月15日
@author: Irony
@site: https://pyqt5.com https://github.com/892768447
@email: 892768447@qq.com
@file: 翻转动画
@description:
"""
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QStackedWidget, QLabel
from Lib.FlipWidget import FlipWidget
__Author__ = 'Irony'
__Copyright__ = 'Copyright (c) 2019 Irony'
__Version__ = 1.0
class LoginWidget(QLabel):
# 只是显示登录界面截图
windowClosed = pyqtSignal()
windowChanged = pyqtSignal()
def __init__(self, *args, **kwargs):
super(LoginWidget, self).__init__(*args, **kwargs)
self.setPixmap(QPixmap('Data/1.png'))
def mousePressEvent(self, event):
super(LoginWidget, self).mousePressEvent(event)
pos = event.pos()
if pos.y() <= 40:
if pos.x() > self.width() - 30:
# 点击关闭按钮的地方
self.windowClosed.emit()
elif self.width() - 90 <= pos.x() <= self.width() - 60:
# 点击切换按钮
self.windowChanged.emit()
class SettingWidget(QLabel):
# 只是显示设置界面截图
windowClosed = pyqtSignal()
windowChanged = pyqtSignal()
def __init__(self, *args, **kwargs):
super(SettingWidget, self).__init__(*args, **kwargs)
self.setPixmap(QPixmap('Data/2.png'))
def mousePressEvent(self, event):
super(SettingWidget, self).mousePressEvent(event)
pos = event.pos()
if pos.y() >= self.height() - 30:
if self.width() - 95 <= pos.x() <= self.width() - 10:
# 点击切换按钮
self.windowChanged.emit()
elif pos.y() <= 40:
if pos.x() > self.width() - 30:
# 点击关闭按钮的地方
self.windowClosed.emit()
class Window(QStackedWidget):
# 主窗口
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
self.resize(428, 329)
self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
# 这个是动画窗口,先创建不显示
self.flipWidget = FlipWidget()
self.flipWidget.finished.connect(self.showWidget)
# 登录窗口
self.loginWidget = LoginWidget(self)
self.loginWidget.windowClosed.connect(self.close)
self.loginWidget.windowChanged.connect(self.jumpSettingWidget)
self.addWidget(self.loginWidget)
# 设置窗口
self.settingWidget = SettingWidget(self)
self.settingWidget.windowClosed.connect(self.close)
self.settingWidget.windowChanged.connect(self.jumpLoginWidget)
self.addWidget(self.settingWidget)
def showWidget(self):
# 显示主窗口隐藏动画窗口
self.setWindowOpacity(1)
QTimer.singleShot(100, self.flipWidget.hide)
def jumpLoginWidget(self):
# 翻转到登录界面
self.setWindowOpacity(0) # 类似隐藏,但是保留了任务栏
self.setCurrentWidget(self.loginWidget) # 很重要,一定要先切换过去,不然会导致第一次截图有误
image1 = self.loginWidget.grab() # 截图1
image2 = self.settingWidget.grab() # 截图2
padding = 100 # 扩大边距 @UnusedVariable
self.flipWidget.setGeometry(self.geometry())
# .adjusted(-padding, -padding, padding, padding))
self.flipWidget.updateImages(FlipWidget.Right, image2, image1)
def jumpSettingWidget(self):
# 翻转到设置界面
self.setWindowOpacity(0) # 类似隐藏,但是保留了任务栏
self.setCurrentWidget(self.settingWidget) # 很重要,一定要先切换过去,不然会导致第一次截图有误
image1 = self.loginWidget.grab() # 截图1
image2 = self.settingWidget.grab() # 截图2
padding = 100 # 扩大边距 @UnusedVariable
self.flipWidget.setGeometry(self.geometry())
# .adjusted(-padding, -padding, padding, padding))
self.flipWidget.updateImages(FlipWidget.Left, image1, image2)
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())

View file

@ -0,0 +1,121 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2019年5月15日
@author: Irony
@site: https://pyqt5.com https://github.com/892768447
@email: 892768447@qq.com
@file: FlipWidget
@description: 动画翻转窗口
"""
from PyQt5.QtCore import pyqtSignal, Qt, QPropertyAnimation, QEasingCurve,\
pyqtProperty, QPointF
from PyQt5.QtGui import QPainter, QTransform
from PyQt5.QtWidgets import QWidget
__Author__ = 'Irony'
__Copyright__ = 'Copyright (c) 2019'
class FlipWidget(QWidget):
Left = 0 # 从右往左
Right = 1 # 从左往右
Scale = 3 # 图片缩放比例
finished = pyqtSignal()
def __init__(self, *args, **kwargs):
super(FlipWidget, self).__init__(*args, **kwargs)
# 无边框无任务栏
self.setWindowFlags(self.windowFlags() |
Qt.FramelessWindowHint | Qt.SubWindow)
# 背景透明
self.setAttribute(Qt.WA_TranslucentBackground, True)
# 翻转角度
self._angle = 0
# 属性动画针对自定义属性`angle`
self._animation = QPropertyAnimation(self, b'angle', self)
self._animation.setDuration(550)
self._animation.setEasingCurve(QEasingCurve.OutInQuad)
self._animation.finished.connect(self.finished.emit)
@pyqtProperty(int)
def angle(self):
return self._angle
@angle.setter
def angle(self, angle):
self._angle = angle
self.update()
def updateImages(self, direction, image1, image2):
"""设置两张切换图
:param direction: 方向
:param image1: 图片1
:param image2: 图片2
"""
self.image1 = image1
self.image2 = image2
self.show()
self._angle = 0
# 根据方向设置动画的初始和结束值
if direction == self.Right:
self._animation.setStartValue(1)
self._animation.setEndValue(-180)
elif direction == self.Left:
self._animation.setStartValue(1)
self._animation.setEndValue(180)
self._animation.start()
def paintEvent(self, event):
super(FlipWidget, self).paintEvent(event)
if hasattr(self, 'image1') and hasattr(self, 'image2') and self.isVisible():
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
# 变换
transform = QTransform()
# 把圆心设置为矩形中心
transform.translate(self.width() / 2, self.height() / 2)
if self._angle >= -90 and self._angle <= 90:
# 当翻转角度在90范围内显示第一张图且从大图缩放到小图的过程
painter.save()
# 设置翻转角度
transform.rotate(self._angle, Qt.YAxis)
painter.setTransform(transform)
# 缩放图片高度
width = self.image1.width() / 2
height = int(self.image1.height() *
(1 - abs(self._angle / self.Scale) / 100))
image = self.image1.scaled(
self.image1.width(), height,
Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
painter.drawPixmap(
QPointF(-width, -height / 2), image)
painter.restore()
else:
# 当翻转角度在90范围内显示第二张图且从小图缩放到原图的过程
painter.save()
if self._angle > 0:
angle = 180 + self._angle
else:
angle = self._angle - 180
# 设置翻转角度, 注意这里角度有差异
transform.rotate(angle, Qt.YAxis)
painter.setTransform(transform)
# 缩放图片高度
width = self.image2.width() / 2
height = int(self.image2.height() *
(1 - ((360 - abs(angle)) / self.Scale / 100)))
image = self.image2.scaled(
self.image2.width(), height,
Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
painter.drawPixmap(
QPointF(-width, -height / 2), image)
painter.restore()

View file

@ -125,3 +125,14 @@ def findClose(points):
通过`QPropertyAnimation`对控件的pos属性进行死去活来的修改 通过`QPropertyAnimation`对控件的pos属性进行死去活来的修改
![ShakeWindow](ScreenShot/ShakeWindow.gif) ![ShakeWindow](ScreenShot/ShakeWindow.gif)
## 6、窗口翻转动画仿QQ
[运行 FlipWidgetAnimation.py](FlipWidgetAnimation.py)
1. 用了两个`QLabel`来显示模拟的图片界面,并实现鼠标点击模拟真实的窗口对应位置点击
2. 用了`QStackedWidget`来存放上面的两个界面`QLabel`
3. 点击切换时主要是对上面的两个界面进行截图并传递给翻转动画窗口
4. 通过`setWindowOpacity`控制主窗口的显示隐藏(保留任务栏),当然也可以用`hide`
5. 动画窗口`FlipWidget.py`主要实现两张图片的翻转显示考虑到0-90和90-180之前的情况以及图片的缩放动画
![FlipWidgetAnimation](ScreenShot/FlipWidgetAnimation.gif)

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 KiB

View file

@ -152,6 +152,7 @@ https://pyqt5.com 社区是专门针对PyQt5学习和提升开设的博客网站
- [点阵特效](QPropertyAnimation/RlatticeEffect.py) - [点阵特效](QPropertyAnimation/RlatticeEffect.py)
- [页面切换/图片轮播动画](QPropertyAnimation/PageSwitching.py) - [页面切换/图片轮播动画](QPropertyAnimation/PageSwitching.py)
- [窗口抖动](QPropertyAnimation/ShakeWindow.py) - [窗口抖动](QPropertyAnimation/ShakeWindow.py)
- [窗口翻转动画仿QQ](QPropertyAnimation/FlipWidgetAnimation.py)
- [折叠动画](Test/partner_625781186/2.折叠控件) - [折叠动画](Test/partner_625781186/2.折叠控件)
- Others - Others