Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Showing warning from a thread



  • I am currently stuck at trying to figure out how to display any kind of warning message while in a thread. The problem is that everything I tried leads the app to crash displaying exit code -1073741819 (0xC0000005). This gets even more mysterious when the app sometimes crashes and sometimes it runs just fine. My code is listed down below. I am using a standard implementatioon of the QMainWindow, the class I have problems with is a separate class running an instance of a PHP server, but that's not important. The part where it starts to crash is when I try to verify if there is some other application listening on the port and if so, it shows a warning message. But like I said, the problem is that sometime when I call that warning window and then click the OK button to close it, the whole app crashes or freezes.

    I have tried to use QMessageBox and even tkinter windows, but the result is the same.

    Is there any way to inform the user of some event while running code in a thread or is it just not possible? Thanks for your replies.

    The file where the issue happens

    import subprocess
    import sys
    import threading
    
    from netwTools import netstat
    
    phpProcess = None
    phpProcessThread = None
    
    
    def startPhpServerThread(parent):
        global phpProcess
        global phpProcessThread
    
        if netstat.checkPortTaken(8001):
            parent.showWarning()
    
        else:
            cmd = ["C:/Users/kodzghly/PycharmProjects/UURSEM_PY/php/php.exe", "-S", "127.0.0.1:8001"]
            phpProcess = subprocess.Popen(cmd, shell=False, stderr=subprocess.PIPE, universal_newlines=True)
            outBuff = ''
            while True:
                out = phpProcess.stderr.read(1)
                if out == '' and phpProcess.poll() is not None:
                    break
                if out == '\n':
                    parent.ui.phpConsole.addItem(outBuff)
                    outBuff = ''
                    sys.stdout.flush()
                if out != '' and out != '\n':
                    outBuff += out
                    parent.ui.phpConsole.scrollToBottom()
    
    
    def startPhpServer(parent):
        global phpProcessThread
        phpProcessThread = threading.Thread(target=startPhpServerThread, args=(parent,))
        phpProcessThread.start()
    
    
    def stopPhpServer(parent):
        parent.ui.phpServerStatusWidget.changeState(2)
        global phpProcess
        if phpProcess is not None:
            phpProcess.terminate()
    
    

    And the file that runs the whole program and has actually the method to display a warning

    import sys
    
    from PySide6 import QtWidgets
    from PySide6.QtWidgets import QApplication, QMainWindow, QMessageBox
    from guiTools import darkTheme
    from phpServer import phpServer
    from ui_mainwindow import Ui_MainWindow
    
    
    class MainWindow(QMainWindow):
    
        def __init__(self):
            super(MainWindow, self).__init__()
            Ui_MainWindow.__init__(self)
            self.ui = Ui_MainWindow()
            self.ui.setupUi(self)
            self.ui.actionRun.triggered.connect(self.startPhpServer)
            self.ui.actionStop.triggered.connect(self.stopPhpServer)
            self.ui.phpServerStatusWidget.setBetterShape(1)
    
        def startPhpServer(self):
            phpServer.startPhpServer(self)
    
        def stopPhpServer(self):
            phpServer.stopPhpServer(self)
    
        def setPhpServerStatusEnabled(self):
            self.ui.phpServerStatusWidget.changeState(0)
    
        def setPhpServerStatusDisabled(self):
            self.ui.phpServerStatusWidget.changeState(2)
    
        def showWarning(self):
            msgBox = QtWidgets.QMessageBox(self)
            msgBox.setWindowTitle("Warning");
            msgBox.setText("Warning test");
            msgBox.exec();
            msgBox.close();
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        darkTheme.setDarkTheme(app)
        window = MainWindow()
        try:
            window.show()
            sys.exit(app.exec_())
        finally:
            window.stopPhpServer()
    

  • Lifetime Qt Champion

    @KodzghlyCZ said in Showing warning from a thread:

    it shows a warning message

    You must not access the ui from outside the main threads. Use signals/slots instead.


  • Lifetime Qt Champion

    @KodzghlyCZ said in Showing warning from a thread:

    it shows a warning message

    You must not access the ui from outside the main threads. Use signals/slots instead.



  • Thanks for your reply, I was not sure if using signals and slots is the right thing to use in this application, but your reply is as clear as it could. I will investigate more in how to use this feature and hopefully I will be able to solve my problem soon.


  • Moderators

    @KodzghlyCZ said in Showing warning from a thread:

    Thanks for your reply, I was not sure if using signals and slots is the right thing to use in this application, but your reply is as clear as it could. I will investigate more in how to use this feature and hopefully I will be able to solve my problem soon.

    From your thread, emit a signal when you want to raise a warning.

    In you GUI thread, implement a slot that displays a warning.

    Connect that signal to that slot.



  • First of all, what the others already suggested is correct and works fine. However, I myself find it to cumbersome to introduce a slot for this. There is a way to execute some function in the context of the event loop of a different thread (ui code has to be executed inside the main thread):

    QMetaObject::invokeMethod(qApp, [](){ QMessageBox::warning(...); });
    

    Just make sure to not capture anything by reference in the lambda to avoid lifetime issues.


Log in to reply