Problem Description

I have a crawler project myself, I use PySide6 to do GUI only, and package Selenium, in which the crawler progress will be printed on the GUI, as shown in the figure below.
image.png
But when Selenium had an error and I clicked to start again, I found that PySide6 crashed! The error message is as follows:

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

Question research

Check the information online to know that this is because

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

That is, the file that is being opened is being read/written, the solution is to close the file that is already open, and then re-execute the script. But the question is which file to close 😂

custom signal

In-depth analysis of my program found that my custom signal was not written properly.

Why do you need custom signals? When we need to update the UI, we can neither directly operate on the main thread (it will block the UI), nor directly operate on the child thread (there will be unexpected bugs, such as my crash). When we need to operate the UI, we need to issue a custom signal. After the main thread receives the signal, it will update the UI as soon as possible at the right time.

First, the custom signal code is as follows

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

my_signal = MySignal()

error code:

 # 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()

correct code

 # 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()

review

The child thread directly updates the UI, which may cause multiple threads to operate Pyside components at the same time, which will cause the program to crash. The solution is to update the UI with custom signals.

The key to custom signals is: connect the custom signal to a function (update the UI in this function), and where the UI needs to be updated, emit the custom signal (while passing the necessary parameters)

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

# emit 自定义信号
my_signal.update_log.emit(log_info)

L小庸
871 声望592 粉丝