diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index 125a828..3229c5e 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -35,6 +35,7 @@ encoding//QProgressBar/MetroCircleProgress.py=utf-8 encoding//QProgressBar/PercentProgressBar.py=utf-8 encoding//QProgressBar/SimpleStyle.py=utf-8 encoding//QProgressBar/WaterProgressBar.py=utf-8 +encoding//QPropertyAnimation/FlipWidgetAnimation.py=utf-8 encoding//QPropertyAnimation/Lib/SlidingStackedWidget.py=utf-8 encoding//QPropertyAnimation/MenuAnimation.py=utf-8 encoding//QPropertyAnimation/ShakeWindow.py=utf-8 diff --git a/QPropertyAnimation/Data/1.png b/QPropertyAnimation/Data/1.png new file mode 100644 index 0000000..f53f32a Binary files /dev/null and b/QPropertyAnimation/Data/1.png differ diff --git a/QPropertyAnimation/Data/2.png b/QPropertyAnimation/Data/2.png new file mode 100644 index 0000000..b6a9226 Binary files /dev/null and b/QPropertyAnimation/Data/2.png differ diff --git a/QPropertyAnimation/FlipWidgetAnimation.py b/QPropertyAnimation/FlipWidgetAnimation.py new file mode 100644 index 0000000..c41947b --- /dev/null +++ b/QPropertyAnimation/FlipWidgetAnimation.py @@ -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_()) diff --git a/QPropertyAnimation/Lib/FlipWidget.py b/QPropertyAnimation/Lib/FlipWidget.py new file mode 100644 index 0000000..25ed75c --- /dev/null +++ b/QPropertyAnimation/Lib/FlipWidget.py @@ -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() diff --git a/QPropertyAnimation/README.md b/QPropertyAnimation/README.md index f01cf88..0db2497 100644 --- a/QPropertyAnimation/README.md +++ b/QPropertyAnimation/README.md @@ -124,4 +124,15 @@ def findClose(points): 通过`QPropertyAnimation`对控件的pos属性进行死去活来的修改 -![ShakeWindow](ScreenShot/ShakeWindow.gif) \ No newline at end of file +![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) \ No newline at end of file diff --git a/QPropertyAnimation/ScreenShot/FlipWidgetAnimation.gif b/QPropertyAnimation/ScreenShot/FlipWidgetAnimation.gif new file mode 100644 index 0000000..106f901 Binary files /dev/null and b/QPropertyAnimation/ScreenShot/FlipWidgetAnimation.gif differ diff --git a/README.md b/README.md index 9b8d1ce..5ba83e2 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,7 @@ https://pyqt5.com 社区是专门针对PyQt5学习和提升开设的博客网站 - [点阵特效](QPropertyAnimation/RlatticeEffect.py) - [页面切换/图片轮播动画](QPropertyAnimation/PageSwitching.py) - [窗口抖动](QPropertyAnimation/ShakeWindow.py) + - [窗口翻转动画(仿QQ)](QPropertyAnimation/FlipWidgetAnimation.py) - [折叠动画](Test/partner_625781186/2.折叠控件) - Others