这是一个使用PyQt5框架创建图形界面的烟花秀程序,采用面向对象设计,包含三个主要类:Particle(粒子)、Firework(烟花)和FireworkWindow(主窗口)。鼠标点击创建烟花,自动随机生成烟花(每600ms),采用粒子运动物理模拟(重力、阻力),并有粒子轨迹效果(带透明度渐变),实现烟花粒子的生命周期管理。
Particle类(粒子)
class Particle:
def __init__(self, x, y):
# 初始化粒子位置、速度、颜色等属性
self.x = x
self.y = y
self.angle = random.uniform(0, 2 * math.pi) # 随机运动方向
self.velocity = random.uniform(3, 12) # 随机速度
# 粒子颜色 - 使用RGB值创建更鲜艳的颜色
bright_colors = [
(255, 0, 0), # 红
(0, 255, 0), # 绿
(0, 0, 255), # 蓝
(255, 255, 0), # 黄
(255, 0, 255), # 紫
(0, 255, 255), # 青
(255, 165, 0), # 橙
(255, 255, 255), # 白
]
color = random.choice(bright_colors)
self.color = QColor(*color)
self.life = 100 # 生命周期
self.trail = [QPoint(int(x), int(y))] # 粒子轨迹
def update(self):
"""更新粒子位置和状态"""
# 应用重力和阻力
self.velocity *= 0.97
dx = math.cos(self.angle) * self.velocity
dy = math.sin(self.angle) * self.velocity + 0.15 # 轻微重力
# 更新位置
self.x += dx
self.y += dy
# 添加到轨迹
self.trail.append(QPoint(int(self.x), int(self.y)))
if len(self.trail) > self.max_trail_length:
self.trail.pop(0)
# 减少生命值
self.life -= 1.5
# 返回粒子是否还活着
return self.life > 0
def draw(self, painter):
"""绘制粒子"""
# 设置颜色和透明度
color = QColor(self.color)
color.setAlpha(int(self.life * 2.5)) # 增加亮度
# 绘制轨迹
if len(self.trail) > 1:
for i in range(len(self.trail) - 1):
# 轨迹渐变效果
alpha = int((i / len(self.trail)) * self.life * 2)
trail_color = QColor(self.color)
trail_color.setAlpha(alpha)
pen = QPen(trail_color, 2) # 增加线宽
painter.setPen(pen)
painter.drawLine(self.trail[i], self.trail[i + 1])
# 绘制粒子
painter.setPen(Qt.NoPen)
painter.setBrush(QBrush(color))
painter.drawEllipse(int(self.x - self.size/2),
int(self.y - self.size/2),
self.size, self.size)
Firework类(烟花)
class Firework:
"""烟花类"""
def __init__(self, x, y):
self.particles = []
# 创建多个粒子
for _ in range(150): # 增加粒子数量
self.particles.append(Particle(x, y))
print(f"创建烟花 at ({x}, {y}) 包含 {len(self.particles)} 个粒子")
def update(self):
"""更新所有粒子"""
# 过滤掉已经消失的粒子
old_count = len(self.particles)
self.particles = [p for p in self.particles if p.update()]
new_count = len(self.particles)
if old_count > 0 and new_count == 0:
print("烟花消失")
return new_count > 0 # 如果还有粒子存活,返回True
def draw(self, painter):
"""绘制所有粒子"""
for particle in self.particles:
particle.draw(painter)
FireworkWindow类(主窗口)
class FireworkWindow(QMainWindow):
"""烟花窗口类"""
def __init__(self):
super().__init__()
print("初始化烟花窗口")
self.initUI()
def initUI(self):
"""初始化UI"""
# 设置窗口
self.setWindowTitle('绚丽烟花秀')
# 居中显示
self.center()
# 设置窗口大小
self.resize(1000, 800) # 增加窗口大小
# 设置黑色背景
self.setStyleSheet("background-color: black;")
# 烟花列表
self.fireworks = []
# 设置定时器
self.timer = QTimer(self)
self.timer.timeout.connect(self.updateFireworks)
self.timer.start(16) # 约60FPS
# 自动生成烟花的定时器
self.auto_timer = QTimer(self)
self.auto_timer.timeout.connect(self.createRandomFirework)
self.auto_timer.start(600) # 每600毫秒生成一个随机烟花
# 显示窗口
self.show()
self.raise_() # 将窗口提升到前台
self.activateWindow() # 激活窗口
print(f"窗口大小: {self.width()}x{self.height()}")
print("窗口已显示")
# 创建初始烟花
self.createRandomFirework()
def center(self):
"""将窗口居中显示"""
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
print(f"窗口居中位置: {qr.topLeft().x()}, {qr.topLeft().y()}")
def createRandomFirework(self):
"""在随机位置创建烟花"""
x = random.randint(100, self.width() - 100)
y = random.randint(100, self.height() - 100)
self.fireworks.append(Firework(x, y))
def updateFireworks(self):
"""更新所有烟花"""
# 更新并过滤掉已经消失的烟花
old_count = len(self.fireworks)
self.fireworks = [fw for fw in self.fireworks if fw.update()]
new_count = len(self.fireworks)
if old_count != new_count:
print(f"当前烟花数量: {new_count}")
# 重绘窗口
self.update()
def mousePressEvent(self, event):
"""鼠标点击事件处理"""
if event.button() == Qt.LeftButton:
# 在鼠标点击位置创建烟花
self.fireworks.append(Firework(event.x(), event.y()))
print(f"鼠标点击创建烟花 at ({event.x()}, {event.y()})")
def paintEvent(self, event):
"""绘制事件处理"""
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# 绘制所有烟花
for firework in self.fireworks:
firework.draw(painter)
def main():
"""主函数"""
print("启动烟花程序")
app = QApplication(sys.argv)
window = FireworkWindow()
print("进入应用主循环")
sys.exit(app.exec_())
完整代码如下:
import sys
import random
import math
from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget
from PyQt5.QtGui import QPainter, QColor, QPen, QBrush
from PyQt5.QtCore import Qt, QTimer, QPoint
class Particle:
"""烟花粒子类"""
def __init__(self, x, y):
# 粒子初始位置
self.x = x
self.y = y
# 随机角度和速度
self.angle = random.uniform(0, 2 * math.pi)
self.velocity = random.uniform(3, 12) # 增加速度范围
# 粒子颜色 - 使用RGB值创建更鲜艳的颜色
bright_colors = [
(255, 0, 0), # 红
(0, 255, 0), # 绿
(0, 0, 255), # 蓝
(255, 255, 0), # 黄
(255, 0, 255), # 紫
(0, 255, 255), # 青
(255, 165, 0), # 橙
(255, 255, 255), # 白
]
color = random.choice(bright_colors)
self.color = QColor(*color)
# 粒子生命周期和大小
self.life = 100
self.size = random.randint(3, 8) # 增加粒子大小
# 存储粒子轨迹
self.trail = [QPoint(int(x), int(y))]
self.max_trail_length = 8 # 增加轨迹长度
def update(self):
"""更新粒子位置和状态"""
# 应用重力和阻力
self.velocity *= 0.97
dx = math.cos(self.angle) * self.velocity
dy = math.sin(self.angle) * self.velocity + 0.15 # 轻微重力
# 更新位置
self.x += dx
self.y += dy
# 添加到轨迹
self.trail.append(QPoint(int(self.x), int(self.y)))
if len(self.trail) > self.max_trail_length:
self.trail.pop(0)
# 减少生命值
self.life -= 1.5
# 返回粒子是否还活着
return self.life > 0
def draw(self, painter):
"""绘制粒子"""
# 设置颜色和透明度
color = QColor(self.color)
color.setAlpha(int(self.life * 2.5)) # 增加亮度
# 绘制轨迹
if len(self.trail) > 1:
for i in range(len(self.trail) - 1):
# 轨迹渐变效果
alpha = int((i / len(self.trail)) * self.life * 2)
trail_color = QColor(self.color)
trail_color.setAlpha(alpha)
pen = QPen(trail_color, 2) # 增加线宽
painter.setPen(pen)
painter.drawLine(self.trail[i], self.trail[i + 1])
# 绘制粒子
painter.setPen(Qt.NoPen)
painter.setBrush(QBrush(color))
painter.drawEllipse(int(self.x - self.size/2),
int(self.y - self.size/2),
self.size, self.size)
class Firework:
"""烟花类"""
def __init__(self, x, y):
self.particles = []
# 创建多个粒子
for _ in range(150): # 增加粒子数量
self.particles.append(Particle(x, y))
print(f"创建烟花 at ({x}, {y}) 包含 {len(self.particles)} 个粒子")
def update(self):
"""更新所有粒子"""
# 过滤掉已经消失的粒子
old_count = len(self.particles)
self.particles = [p for p in self.particles if p.update()]
new_count = len(self.particles)
if old_count > 0 and new_count == 0:
print("烟花消失")
return new_count > 0 # 如果还有粒子存活,返回True
def draw(self, painter):
"""绘制所有粒子"""
for particle in self.particles:
particle.draw(painter)
class FireworkWindow(QMainWindow):
"""烟花窗口类"""
def __init__(self):
super().__init__()
print("初始化烟花窗口")
self.initUI()
def initUI(self):
"""初始化UI"""
# 设置窗口
self.setWindowTitle('绚丽烟花秀')
# 居中显示
self.center()
# 设置窗口大小
self.resize(1000, 800) # 增加窗口大小
# 设置黑色背景
self.setStyleSheet("background-color: black;")
# 烟花列表
self.fireworks = []
# 设置定时器
self.timer = QTimer(self)
self.timer.timeout.connect(self.updateFireworks)
self.timer.start(16) # 约60FPS
# 自动生成烟花的定时器
self.auto_timer = QTimer(self)
self.auto_timer.timeout.connect(self.createRandomFirework)
self.auto_timer.start(600) # 每600毫秒生成一个随机烟花
# 显示窗口
self.show()
self.raise_() # 将窗口提升到前台
self.activateWindow() # 激活窗口
print(f"窗口大小: {self.width()}x{self.height()}")
print("窗口已显示")
# 创建初始烟花
self.createRandomFirework()
def center(self):
"""将窗口居中显示"""
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
print(f"窗口居中位置: {qr.topLeft().x()}, {qr.topLeft().y()}")
def createRandomFirework(self):
"""在随机位置创建烟花"""
x = random.randint(100, self.width() - 100)
y = random.randint(100, self.height() - 100)
self.fireworks.append(Firework(x, y))
def updateFireworks(self):
"""更新所有烟花"""
# 更新并过滤掉已经消失的烟花
old_count = len(self.fireworks)
self.fireworks = [fw for fw in self.fireworks if fw.update()]
new_count = len(self.fireworks)
if old_count != new_count:
print(f"当前烟花数量: {new_count}")
# 重绘窗口
self.update()
def mousePressEvent(self, event):
"""鼠标点击事件处理"""
if event.button() == Qt.LeftButton:
# 在鼠标点击位置创建烟花
self.fireworks.append(Firework(event.x(), event.y()))
print(f"鼠标点击创建烟花 at ({event.x()}, {event.y()})")
def paintEvent(self, event):
"""绘制事件处理"""
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# 绘制所有烟花
for firework in self.fireworks:
firework.draw(painter)
def main():
"""主函数"""
print("启动烟花程序")
app = QApplication(sys.argv)
window = FireworkWindow()
print("进入应用主循环")
sys.exit(app.exec_())
if __name__ == '__main__':
main()