pyside刷新界面, 同时不要阻塞用户操作

timer定时器写法

  • 要点: timer要么绑在一个持久化的对象上, 要么在main里面(有app.exec和sys.exit的地方, 他是个死循环)
# main中使用timer可以直接用, 不必绑持久对象
timer = QTimer()
timer.timeout.connect(lambda: flexlayout(movnode=movnode, contnode=contnode))
timer.start(1)

# 绑持久化对象的写法
setattr(view, "timer", timer)

# 可以只执行一次的写法
def run_once():
    flexlayout(movnode=movnode, contnode=contnode)
    timer.stop()
timer.timeout.connect(run_once)

成批计算写法

def flexlayout_progressive(*, update_nodes):
    """分批进行布局计算,每批处理后允许界面更新"""
    batch_size = 10  # 每批计算10次
    
    while True: # 死循环, 如果有不收敛的可能性, 这里也可以搞个判断
        # 计算一批
        for i in range(batch_size):
            if 收敛判断():return True  # 提前收敛
            update_nodes() # 你的更新代码
            
        # 处理界面事件,防止阻塞
        QApplication.processEvents()
        
        # 可选:更新界面显示中间结果
        upalline(movnode)
        
        # 这里也可以判断性返回, 判断条件: 计算的次数, 持续时间等
    
    return False  # 未完全收敛

异步计算

from PySide6.QtCore import QThread, pyqtSignal

class LayoutThread(QThread):
    uSig = pyqtSignal()
    
    def run(self):
        while not 收敛判断():
            update_nodes() # 你的更新代码
            self.uSig.emit()  # 通知主线程更新界面
            self.msleep(16)  # 60fps的间隔

# 不用这个, 直接用timer也是可以的, 
# 1. 可以判断满足条件就stop
# 2. 可以singleshot

def 递归调用():
    if 收敛判断() : return  # 完成       
    update_nodes() #你的更新代码
    # 1ms后递归调用自己
    QTimer.singleShot(1, lambda: 递归调用())