Skip to content

Commit 8135d21

Browse files
committed
背景连线动画
1 parent 4207ec8 commit 8135d21

File tree

6 files changed

+482
-1
lines changed

6 files changed

+482
-1
lines changed

.settings/org.eclipse.core.resources.prefs

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
eclipse.preferences.version=1
22
encoding//Demo/AutoRestart.py=utf-8
3+
encoding//Demo/CircleLine.py=utf-8
34
encoding//Demo/EmbedWindow.py=utf-8
45
encoding//Demo/FacePoints.py=utf-8
56
encoding//Demo/FollowWindow.py=utf-8
@@ -20,6 +21,7 @@ encoding//QChart/LineChart.py=utf-8
2021
encoding//QFont/AwesomeFont.py=utf-8
2122
encoding//QFont/Lib/FontAwesome.py=utf-8
2223
encoding//QGraphicsDropShadowEffect/ShadowEffect.py=utf-8
24+
encoding//QGraphicsView/WorldMap.py=utf-8
2325
encoding//QListView/CustomWidgetSortItem.py=utf-8
2426
encoding//QListView/SortItemByRole.py=utf-8
2527
encoding//QMessageBox/CustomColorIcon.py=utf-8

Demo/CircleLine.py

+262
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
Created on 2019年3月19日
6+
@author: Irony
7+
@site: https://pyqt5.com https://github.com/892768447
8+
@email: 892768447@qq.com
9+
@file: CircleLine
10+
@description:
11+
"""
12+
13+
from math import floor, pi, cos, sin
14+
from random import random, randint
15+
from time import time
16+
17+
from PyQt5.QtCore import QTimer, Qt
18+
from PyQt5.QtGui import QColor, QPainter, QPainterPath, QPen
19+
from PyQt5.QtWidgets import QWidget
20+
21+
22+
__Author__ = 'Irony'
23+
__Copyright__ = 'Copyright (c) 2019'
24+
25+
# 最小和最大半径、半径阈值和填充圆的百分比
26+
radMin = 10
27+
radMax = 80
28+
filledCircle = 30 # 填充圆的百分比
29+
concentricCircle = 60 # 同心圆百分比
30+
radThreshold = 25 # IFF special, over this radius concentric, otherwise filled
31+
# 最小和最大移动速度
32+
speedMin = 0.3
33+
speedMax = 0.6
34+
# 每个圆和模糊效果的最大透明度
35+
maxOpacity = 0.6
36+
37+
colors = [
38+
QColor(52, 168, 83),
39+
QColor(117, 95, 147),
40+
QColor(199, 108, 23),
41+
QColor(194, 62, 55),
42+
QColor(0, 172, 212),
43+
QColor(120, 120, 120)
44+
]
45+
circleBorder = 10
46+
backgroundLine = colors[0]
47+
backgroundColor = QColor(38, 43, 46)
48+
backgroundMlt = 0.85
49+
50+
lineBorder = 2.5
51+
52+
# 最重要的是:包含它们的整个圆和数组的数目
53+
maxCircles = 8
54+
points = []
55+
56+
# 实验变量
57+
circleExp = 1
58+
circleExpMax = 1.003
59+
circleExpMin = 0.997
60+
circleExpSp = 0.00004
61+
circlePulse = False
62+
63+
# 生成随机整数 a<=x<=b
64+
65+
66+
def randint(a, b):
67+
return floor(random() * (b - a + 1) + a)
68+
69+
# 生成随机小数
70+
71+
72+
def randRange(a, b):
73+
return random() * (b - a) + a
74+
75+
# 生成接近a的随机小数
76+
77+
78+
def hyperRange(a, b):
79+
return random() * random() * random() * (b - a) + a
80+
81+
82+
class Circle:
83+
84+
def __init__(self, background, width, height):
85+
self.background = background
86+
self.x = randRange(-width / 2, width / 2)
87+
self.y = randRange(-height / 2, height / 2)
88+
self.radius = hyperRange(radMin, radMax)
89+
self.filled = (False if randint(
90+
0, 100) > concentricCircle else 'full') if self.radius < radThreshold else (
91+
False if randint(0, 100) > concentricCircle else 'concentric')
92+
self.color = colors[randint(0, len(colors) - 1)]
93+
self.borderColor = colors[randint(0, len(colors) - 1)]
94+
self.opacity = 0.05
95+
self.speed = randRange(speedMin, speedMax) # * (radMin / self.radius)
96+
self.speedAngle = random() * 2 * pi
97+
self.speedx = cos(self.speedAngle) * self.speed
98+
self.speedy = sin(self.speedAngle) * self.speed
99+
spacex = abs((self.x - (-1 if self.speedx < 0 else 1) *
100+
(width / 2 + self.radius)) / self.speedx)
101+
spacey = abs((self.y - (-1 if self.speedy < 0 else 1) *
102+
(height / 2 + self.radius)) / self.speedy)
103+
self.ttl = min(spacex, spacey)
104+
105+
106+
class CircleLineWindow(QWidget):
107+
108+
def __init__(self, *args, **kwargs):
109+
super(CircleLineWindow, self).__init__(*args, **kwargs)
110+
geometry = QApplication.instance().desktop().availableGeometry()
111+
self.screenWidth = geometry.width()
112+
self.screenHeight = geometry.height()
113+
self._canDraw = True
114+
self._firstDraw = True
115+
self._timer = QTimer(self, timeout=self.update)
116+
117+
def init(self):
118+
points.clear()
119+
# 链接的最小距离
120+
self.linkDist = min(self.screenWidth, self.screenHeight) / 2.4
121+
# 初始化点
122+
for _ in range(maxCircles * 3):
123+
points.append(Circle('', self.screenWidth, self.screenHeight))
124+
self.update()
125+
126+
def resizeEvent(self, event):
127+
super(CircleLineWindow, self).resizeEvent(event)
128+
self.init()
129+
130+
def showEvent(self, event):
131+
super(CircleLineWindow, self).showEvent(event)
132+
self._canDraw = True
133+
134+
def hideEvent(self, event):
135+
super(CircleLineWindow, self).hideEvent(event)
136+
# 窗口最小化要停止绘制, 减少cpu占用
137+
self._canDraw = False
138+
139+
def paintEvent(self, event):
140+
super(CircleLineWindow, self).paintEvent(event)
141+
if not self._canDraw:
142+
return
143+
painter = QPainter(self)
144+
painter.setRenderHint(QPainter.Antialiasing)
145+
painter.setRenderHint(QPainter.SmoothPixmapTransform)
146+
painter.save()
147+
painter.fillRect(self.rect(), backgroundColor)
148+
painter.restore()
149+
self.draw(painter)
150+
151+
def draw(self, painter):
152+
if circlePulse:
153+
if circleExp < circleExpMin or circleExp > circleExpMax:
154+
circleExpSp *= -1
155+
circleExp += circleExpSp
156+
157+
painter.translate(self.screenWidth / 2, self.screenHeight / 2)
158+
159+
if self._firstDraw:
160+
t = time()
161+
self.renderPoints(painter, points)
162+
if self._firstDraw:
163+
self._firstDraw = False
164+
# 此处有个比例关系用于设置timer的时间,如果初始窗口很小,没有比例会导致动画很快
165+
t = (time() - t) * 1000
166+
# 比例最大不能超过1920/800
167+
t = int(min(2.4, self.screenHeight / self.height()) * t) - 1
168+
print('start timer(%d msec)' % t)
169+
# 开启定时器
170+
self._timer.start(t)
171+
172+
def drawCircle(self, painter, circle):
173+
# circle.radius *= circleExp
174+
if circle.background:
175+
circle.radius *= circleExp
176+
else:
177+
circle.radius /= circleExp
178+
radius = circle.radius
179+
180+
r = radius * circleExp
181+
# 边框颜色设置透明度
182+
c = QColor(circle.borderColor)
183+
c.setAlphaF(circle.opacity)
184+
185+
painter.save()
186+
if circle.filled == 'full':
187+
# 设置背景刷
188+
painter.setBrush(c)
189+
painter.setPen(Qt.NoPen)
190+
else:
191+
# 设置画笔
192+
painter.setPen(
193+
QPen(c, max(1, circleBorder * (radMin - circle.radius) / (radMin - radMax))))
194+
195+
# 画实心圆或者圆圈
196+
painter.drawEllipse(circle.x - r, circle.y - r, 2 * r, 2 * r)
197+
painter.restore()
198+
199+
if circle.filled == 'concentric':
200+
r = radius / 2
201+
# 画圆圈
202+
painter.save()
203+
painter.setBrush(Qt.NoBrush)
204+
painter.setPen(
205+
QPen(c, max(1, circleBorder * (radMin - circle.radius) / (radMin - radMax))))
206+
painter.drawEllipse(circle.x - r, circle.y - r, 2 * r, 2 * r)
207+
painter.restore()
208+
209+
circle.x += circle.speedx
210+
circle.y += circle.speedy
211+
if (circle.opacity < maxOpacity):
212+
circle.opacity += 0.01
213+
circle.ttl -= 1
214+
215+
def renderPoints(self, painter, circles):
216+
for i, circle in enumerate(circles):
217+
if circle.ttl < -20:
218+
# 重新初始化一个
219+
circle = Circle('', self.screenWidth, self.screenHeight)
220+
circles[i] = circle
221+
self.drawCircle(painter, circle)
222+
223+
circles_len = len(circles)
224+
for i in range(circles_len - 1):
225+
for j in range(i + 1, circles_len):
226+
deltax = circles[i].x - circles[j].x
227+
deltay = circles[i].y - circles[j].y
228+
dist = pow(pow(deltax, 2) + pow(deltay, 2), 0.5)
229+
# if the circles are overlapping, no laser connecting them
230+
if dist <= circles[i].radius + circles[j].radius:
231+
continue
232+
# otherwise we connect them only if the dist is < linkDist
233+
if dist < self.linkDist:
234+
xi = (1 if circles[i].x < circles[j].x else -
235+
1) * abs(circles[i].radius * deltax / dist)
236+
yi = (1 if circles[i].y < circles[j].y else -
237+
1) * abs(circles[i].radius * deltay / dist)
238+
xj = (-1 if circles[i].x < circles[j].x else 1) * \
239+
abs(circles[j].radius * deltax / dist)
240+
yj = (-1 if circles[i].y < circles[j].y else 1) * \
241+
abs(circles[j].radius * deltay / dist)
242+
path = QPainterPath()
243+
path.moveTo(circles[i].x + xi, circles[i].y + yi)
244+
path.lineTo(circles[j].x + xj, circles[j].y + yj)
245+
# samecolor = circles[i].color == circles[j].color
246+
c = QColor(circles[i].borderColor)
247+
c.setAlphaF(min(circles[i].opacity, circles[j].opacity)
248+
* ((self.linkDist - dist) / self.linkDist))
249+
painter.setPen(QPen(c, (
250+
lineBorder * backgroundMlt if circles[i].background else lineBorder) * (
251+
(self.linkDist - dist) / self.linkDist)))
252+
painter.drawPath(path)
253+
254+
255+
if __name__ == '__main__':
256+
import sys
257+
from PyQt5.QtWidgets import QApplication
258+
app = QApplication(sys.argv)
259+
w = CircleLineWindow()
260+
w.resize(800, 600)
261+
w.show()
262+
sys.exit(app.exec_())

0 commit comments

Comments
 (0)