窗口翻转动画(仿QQ)
This commit is contained in:
parent
756f4fd0f1
commit
e68853c536
8 changed files with 262 additions and 1 deletions
|
@ -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
|
||||||
|
|
BIN
QPropertyAnimation/Data/1.png
Normal file
BIN
QPropertyAnimation/Data/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
BIN
QPropertyAnimation/Data/2.png
Normal file
BIN
QPropertyAnimation/Data/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
127
QPropertyAnimation/FlipWidgetAnimation.py
Normal file
127
QPropertyAnimation/FlipWidgetAnimation.py
Normal 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_())
|
121
QPropertyAnimation/Lib/FlipWidget.py
Normal file
121
QPropertyAnimation/Lib/FlipWidget.py
Normal 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()
|
|
@ -124,4 +124,15 @@ 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)
|
BIN
QPropertyAnimation/ScreenShot/FlipWidgetAnimation.gif
Normal file
BIN
QPropertyAnimation/ScreenShot/FlipWidgetAnimation.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 587 KiB |
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue