inisik
inisik

Reputation: 1

PyQt5 Abnormal exit when running QMessageBox

I am creating a program that opens the IP list csv file and executes SNMP-GET when the button is pressed. However, when the button is pressed, SNMP-GET is normally executed, but the program ends abnormally when QMessageBox is displayed.

def check_upgrade(self):
    for i in self.agw_num_list:
        send_snmp_get = getCmd(SnmpEngine()
                               , CommunityData(self.read_community, mpModel=1)
                               , UdpTransportTarget((self.ip_list[i-1], self.snmp_port), timeout=0.5, retries=1)
                               , ContextData()
                               , ObjectType(ObjectIdentity('1.3.6.1.4.1.8218.4.20.1.4.0'))
                               , ObjectType(ObjectIdentity('1.3.6.1.4.1.8218.4.20.5.2.0'))
                               )
        errorIndication, errorStatus, errorIndex, varBinds = next(send_snmp_get)

        if len(varBinds) != 0:
            encoding_pkg_version = str(varBinds[0][1]).encode()
            encoding_mgc_status = str(varBinds[1][1]).encode()
            pkg_version = encoding_pkg_version.decode()
            mgc_status = encoding_mgc_status.decode()

            result = str(i) + '   ' \
                     + str(self.ip_list[i-1]) \
                     + '   ' + str(errorIndication) \
                     + '   ' + str(pkg_version) \
                     + '   ' + str(mgc_status)
            self.display_result(result)

        else:
            result = str(i) + '   ' \
                     + str(self.ip_list[i-1]) \
                     + '   ' + 'NoReponse'
            self.display_result(result)

    self.upgrade_check_msgbox()

def upgrade_check_btn_clicked(self):
    self.result_textb.clear()
    t = threading.Thread(target=self.check_upgrade, daemon=True)
    t.start()

def upgrade_check_msgbox(self):
    if self.file_name == '':
        QMessageBox.warning(self, 'check', 'need file')
    else:
        QMessageBox.information(self, 'check', 'complete')

It works normally when the self.check_upgrade function is called without generating a thread.

Process finished with exit code -1073741819 (0xC0000005)

Upvotes: 0

Views: 141

Answers (1)

Matteo Italia
Matteo Italia

Reputation: 126867

You cannot invoke Qt Widget stuff from threads other than the one where the QApplication was created. That's a hard limitation that cannot be bypassed.

If you need to do GUI stuff in response to something happening on a thread, you have to signal it back to the main thread event loop, and have the main thread do the GUI stuff on the worker's behalf.

Generally that can be done by having the main thread run an event loop (QApplication.exec_()), and either by posting a custom event to be handled by an object "living" on the main thread, or by creating a signal on an QObject that belongs to the worker thread (= created in the worker thread, or moved there using moveToThread), and connecting it to a slot of an object living in the main thread. Qt will take care of dispatching the signal through the event loop when it's emitted.

This is generally very easy to do in trivial cases, such as when you just need to know if a worker has terminated, because QThread already has the relevant signals that are emitted when the thread ends.

Another alternative is to avoid threads entirely and use an async version of your API, if avaliable. In that case you can still run your event loop on the main thread, without blocking it when waiting for the SMTP call to end.

Upvotes: 1

Related Questions