You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 09:27:02