如何在PyQt5的Pixmap中移动像素列实现屏幕溶解特效?
实现思路
- 将加载的原图转为可读写的
QImage对象,支持逐像素修改操作 - 初始化与图片宽度等长的偏移量数组,记录每列像素的向下偏移值,初始全部为0
- 采用
QTimer驱动逐帧动画,避免阻塞Qt主事件循环导致界面卡顿 - 每帧随机选择若干未完全移出屏幕的像素列,增加其偏移量;按偏移量重新绘制所有列的像素,偏移后顶部空缺位置填充黑色
- 所有像素列完全移出屏幕后停止计时器,动画结束
完整修改后代码
# -*- coding: utf-8 -*- import sys, os, random from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * class Ui(QMainWindow): def __init__(self): # 修正父类初始化调用 super().__init__() # 文件路径处理 folder_path = os.path.dirname(os.path.abspath(__file__)) self.picture_path = os.path.join(folder_path, 'solar_wallpaper.jpg') self.icon_path = os.path.join(folder_path, 'solar_icon.ico') # 窗口配置,合并重复的标志设置 self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint & ~Qt.WindowMinimizeButtonHint & ~Qt.WindowMaximizeButtonHint) self.setWindowTitle('Solar') self.setWindowIcon(QIcon(self.icon_path)) self.setStyleSheet("background-color: black;") self.init_components() self.init_layout() self.showFullScreen() # 启动溶解动画 self.start_dissolve() def init_components(self): self.setCentralWidget(QGroupBox()) self.picture = QLabel(self) self.picture.setAlignment(Qt.AlignCenter) # 加载原图并适配全屏尺寸 screen_geo = QApplication.primaryScreen().geometry() original_pix = QPixmap(self.picture_path) # 缩放为全屏尺寸,转为可读写的QImage self.original_img = original_pix.scaled( screen_geo.width(), screen_geo.height(), Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation ).toImage() # 初始显示原图 self.picture.setPixmap(QPixmap.fromImage(self.original_img)) # 初始化每列的偏移量数组 self.col_offsets = [0] * self.original_img.width() def init_layout(self): self.layout = QVBoxLayout() self.layout.setContentsMargins(0,0,0,0) self.layout.addWidget(self.picture) self.centralWidget().setLayout(self.layout) def start_dissolve(self): # 计时器每15ms刷新一帧,可调整数值改变动画速度 self.timer = QTimer(self) self.timer.timeout.connect(self.update_dissolve_frame) self.timer.start(15) def update_dissolve_frame(self): img_width = self.original_img.width() img_height = self.original_img.height() # 每帧随机选择30列增加偏移,可调整数值改变溶解速度 for _ in range(30): col = random.randint(0, img_width - 1) if self.col_offsets[col] < img_height: # 每次偏移1-3像素,效果更自然 self.col_offsets[col] += random.randint(1, 3) # 生成新的帧图片 new_img = QImage(img_width, img_height, QImage.Format_RGB32) new_img.fill(Qt.black) for x in range(img_width): offset = self.col_offsets[x] if offset >= img_height: continue # 复制原列像素到新图的偏移位置 for y in range(img_height - offset): new_img.setPixelColor(x, y + offset, self.original_img.pixelColor(x, y)) # 更新界面显示 self.picture.setPixmap(QPixmap.fromImage(new_img)) # 所有列完全移出屏幕后停止动画 if all(offset >= img_height for offset in self.col_offsets): self.timer.stop() if __name__ == '__main__': app = QApplication.instance() or QApplication(sys.argv) ui = Ui() sys.exit(app.exec())
参数调整说明
- 调整
QTimer.start(15)里的数值,数值越小动画帧率越高、整体速度越快 - 调整
update_dissolve_frame里每帧处理的列数(当前为30),数值越大溶解速度越快 - 调整
self.col_offsets[col] += random.randint(1, 3)里的随机范围,数值越大每列下落的步长越大、动画越粗犷
内容的提问来源于stack exchange,提问作者Solar
相关产品推荐
相关产品推荐

