关于python:解决-PySide6-崩溃闪退自定义信号

8次阅读

共计 1764 个字符,预计需要花费 5 分钟才能阅读完成。

问题形容

本人有个爬虫我的项目,应用 PySide6 只做 GUI,包装 Selenium,其中在 GUI 上会打印爬虫进度,见下图。

但当 Selenium 呈现谬误我从新点击开始的时候,发现 PySide6 crash 了!错误信息如下:

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

问题调研

网上查阅材料晓得这是因为

You’re trying to read/write a file which is open. In this case, simply closing the file and rerunning the script solved the issue

即正在读 / 写正在关上的文件,解决方案就是敞开曾经关上的文件就好,而后从新执行脚本。但问题是敞开哪个文件啊 😂

自定义信号

深入分析我的程序发现,我的自定义信号没有写好。

为什么须要自定义信号?当咱们须要更新 UI 时,咱们既不能在主线程间接操作(会阻塞 UI),又不能在子线程间接操作(会有意想不到的 BUG,比方我这个 crash)。当咱们须要操作 UI,就须要收回一个自定义信号,主线程收到信号后,会在适合的机会尽快更新 UI。

首先,自定义信号代码如下

class MySignal(QObject):
    # 定义更新日志的 signal
    update_log = Signal(str)

my_signal = MySignal()

错误代码:

# PySide UI
class MainWindow(QMainWindow):
    def __init__(self):
        self.bind_signal()

    def bind_signal(self):
        # 绑定了自定义 Signal 到特定函数,但发送时出错了
        my_signal.update_log.connect(self.update_log)

    def update_log(self, log_info):
        self.ui.log_box.appendPlainText(log_info)

    def start_buy(self):
        # ControlBuy 是 Selenium 管制类,这里把更新日志的函数传递进去了
        # 但 update_log 是间接更新了 UI,所以呈现了谬误
        # 应该是 emit 更新日志的 Signal
        control_buy = ControlBuy(self.update_log)
        thread = Thread(target=control_buy.start)
        thread.start()

正确代码

# emit 更新 log 的 signal,Selenium 间接调用的是 emit signal 的函数
# 而非间接调用 update_log
def send_log_signal(log_info):
    my_signal.update_log.emit(log_info)

# PySide UI
class MainWindow(QMainWindow):
    def __init__(self):
        self.bind_signal()

    def bind_signal(self):
        my_signal.update_log.connect(self.update_log)

    def update_log(self, log_info):
        self.ui.log_box.appendPlainText(log_info)

    def start_buy(self):
        # 传给 Selenium 管制类的是 send_log_signal 而非 self.update_log!!!
        control_buy = ControlBuy(send_log_signal)
        thread = Thread(target=control_buy.start)
        thread.start()

回顾

子线程间接更新 UI,可能导致多个线程同时操作 Pyside 组件,这样就会导致程序解体。解决办法就是借助自定义信号更新 UI。

自定义信号的要害是:将自定义信号 connect 到某个函数(在这个函数中更新 UI),在须要更新 UI 的中央,emit 自定义信号(同时传递必要参数)

# 绑定自定义信号到特定函数
my_signal.update_log.connect(self.update_log)

# emit 自定义信号
my_signal.update_log.emit(log_info)
正文完
 0