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()
-
@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.
-
@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.