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

PyQt6使用QTimer实现冒泡排序每次交换后延迟3秒刷新

问题原因
  • 排序逻辑写在paintEvent中:paintEvent是Qt同步执行的界面渲染事件,进入该方法后会直接跑完整个冒泡排序的双层循环,所有QTimer.singleShot几乎在同一时间被注册,3秒后会同时触发所有刷新回调,自然无法分步展示。
  • 同步循环阻塞事件循环:双层for循环是阻塞式执行的,循环运行期间Qt的事件循环无法响应界面刷新、定时任务等操作,等循环执行完成时数组已经是最终排序结果,后续触发的刷新只会绘制最终状态。
  • 存在递归触发风险:paintEvent中调用排序,排序完成后触发update()会再次进入paintEvent,重复执行排序逻辑,会导致逻辑混乱。
修正后代码
import sys
from PyQt6.QtWidgets import QWidget, QApplication
from PyQt6.QtGui import QPainter
from PyQt6.QtCore import Qt, QRect, QTimer
import random

class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.values = random.sample(range(10, 100), 20)
        self.h = 50
        self.w = len(self.values)*self.h
        self.setGeometry(300, 300, self.w, self.h)
        self.setWindowTitle('冒泡排序可视化')
        
        # 初始化排序状态变量
        self.arr_len = len(self.values)
        self.sort_i = 0
        self.sort_j = 0
        self.swapped = False
        
        self.show()
        # 启动第一步排序,延迟3秒
        QTimer.singleShot(3000, self.sortSingleStep)

    def paintEvent(self, event):
        qp = QPainter()
        qp.begin(self)
        i = 0
        for x in self.values:
            rect = QRect(i, 0, 50, 50)
            qp.drawRect(rect)
            qp.drawText(rect, Qt.AlignmentFlag.AlignCenter, str(x))
            i += 50
        qp.end()

    def sortSingleStep(self):
        # 所有排序轮次完成,直接退出
        if self.sort_i >= self.arr_len - 1:
            return
        
        # 处理当前内循环位置的对比
        if self.sort_j < self.arr_len - self.sort_i - 1:
            if self.values[self.sort_j] > self.values[self.sort_j + 1]:
                self.swapped = True
                self.values[self.sort_j], self.values[self.sort_j + 1] = self.values[self.sort_j + 1], self.values[self.sort_j]
                # 交换完成后刷新界面
                self.update()
            self.sort_j += 1
        else:
            # 当前轮次无交换,说明数组已经有序,直接终止排序
            if not self.swapped:
                return
            # 进入下一轮排序,重置内循环索引和交换标记
            self.swapped = False
            self.sort_i += 1
            self.sort_j = 0
        
        # 注册下一次单步排序任务,间隔3秒
        QTimer.singleShot(3000, self.sortSingleStep)

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec())

if __name__ == '__main__':
    main()
核心修改说明
  • 移除paintEvent中的排序调用,paintEvent仅保留绘图逻辑,避免阻塞渲染和递归触发问题。
  • 将原本同步阻塞的双层冒泡循环拆分为单步执行的sortSingleStep方法,每次调用仅处理一次元素对比/交换,执行完成后立刻把控制权交还给Qt事件循环,保证界面可以正常渲染更新。
  • 用类成员变量记录排序进度(外循环索引、内循环索引、交换标记),每次定时触发时基于当前进度推进排序,不再一次性跑完所有循环。
  • 每完成一次单步操作后,再注册下一次3秒的定时任务,保证每一步的间隔准确,不会出现所有定时任务同时触发的问题;仅在元素发生交换时触发界面刷新,匹配需求要求。

内容的提问来源于stack exchange,提问作者Arundeep Chohan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:57:26