PYQT5 QThread: Destroyed while thread is still running
-
Hi,
I am a totally beginner with Qt / PyQT5 and this is my first gui app.
I'm facing the Qthread destroyed issue. Basically, I'm trying to launch a shell command when user click on a button and display the result in the UI.
QProcess handle the command and I wrap it with QThread to make it works async. But the program crash and I get QThread: Destroyed while thread is still running.After some tests it seems that is because how my code is split.
I have my mainWindow.py (converted from .ui file) imported to a mainWindowController.py where I set my btn.clicked.connect(self.handleSubmit). In the file I have a function liledef handleSubmit(self): testThread()
It calls a testThread class imported from testThread.py where I init the QThread and start it
class WorkerThread(QtCore.QThread): def __init__(self, parent=None): super(WorkerThread, self).__init__(parent) def run(self): time.sleep(3) print("hello")
from worker import WorkerThread class testThread(): def __init__(self): self.worker = WorkerThread() self.worker.start()
However if I import my Worker directly in my MainWindowController.py and init then start the Thread from my handleSubmit function, It runs without any issue.
How is it possible to split the code?
Thanks!
-
Hi,
I am a totally beginner with Qt / PyQT5 and this is my first gui app.
I'm facing the Qthread destroyed issue. Basically, I'm trying to launch a shell command when user click on a button and display the result in the UI.
QProcess handle the command and I wrap it with QThread to make it works async. But the program crash and I get QThread: Destroyed while thread is still running.After some tests it seems that is because how my code is split.
I have my mainWindow.py (converted from .ui file) imported to a mainWindowController.py where I set my btn.clicked.connect(self.handleSubmit). In the file I have a function liledef handleSubmit(self): testThread()
It calls a testThread class imported from testThread.py where I init the QThread and start it
class WorkerThread(QtCore.QThread): def __init__(self, parent=None): super(WorkerThread, self).__init__(parent) def run(self): time.sleep(3) print("hello")
from worker import WorkerThread class testThread(): def __init__(self): self.worker = WorkerThread() self.worker.start()
However if I import my Worker directly in my MainWindowController.py and init then start the Thread from my handleSubmit function, It runs without any issue.
How is it possible to split the code?
Thanks!
@Yok0 said in PYQT5 QThread: Destroyed while thread is still running:
I am a totally beginner with Qt / PyQT5 and this is my first gui app.
In that case, why are you trying to use
QThread
at all? :) It's the hardest part, especially with Python, so why go there? -
Hi and welcome to devnet,
Your use case does not require threading at all. QProcess is already asynchronous. You should start with learning the asynchronous nature of Qt before heading to threads.
-
@Yok0 said in PYQT5 QThread: Destroyed while thread is still running:
I am a totally beginner with Qt / PyQT5 and this is my first gui app.
In that case, why are you trying to use
QThread
at all? :) It's the hardest part, especially with Python, so why go there?@JonB Yeah your right, but at that point I thought I needed it, but in my case it is useless and as @SGaist mentioned it, QProcess is already async. Before posting this message I used to get the error QProcess / Qthread destroyed while... and I did not fully understood that error. After refactoring my code everything works perfectly!
@SGaist my mistake, indeed QProcess is already async, I guess the issue was how my code was organised.
-
@JonB Yeah your right, but at that point I thought I needed it, but in my case it is useless and as @SGaist mentioned it, QProcess is already async. Before posting this message I used to get the error QProcess / Qthread destroyed while... and I did not fully understood that error. After refactoring my code everything works perfectly!
@SGaist my mistake, indeed QProcess is already async, I guess the issue was how my code was organised.
@Yok0 said in PYQT5 QThread: Destroyed while thread is still running:
QProcess / Qthread destroyed while
You get this when you set off a process, don't wait for it finish, and let the
QProcess
variable go out of scope. It needs to persist as long as the process is running. So e.g.void someFunction() { QProcess proc; // local, stack variable proc.start(...); // start process, but it hasn't yet finished // exiting here will destroy the `proc` variable // since the process is running, you'll get the " QProcess / Qthread destroyed while ..." }
-
Sorry @JonB and @SGaist but I have another question. I'ts not directly linked with QProcess but it's a general question about packaging. Now that's my app running great I packed it with fbs. With the command "fbs run", my app runs fine so I "fbs freeze" it.
The app shows up, everything working but when my QProcess get's called nothing happens. -
What are you calling from QProcess ?
-
EDIT : soooo Stupid...
@SGaist when you asked what I was calling it gave me an idea. I changed my command with an os based one like "ls -l" and it worked. I thought it was the same with my cli app I was calling. So i just threw it like QProcess.start("someapp arg").
To make it work I just had to specify the absolute path like QProcess.start("/usr/local/bin/someapp arg").Sorry for that and @SGaist thanks for your assistance!
-
Rather than hard coding such a path, you might want to consider modifying the PATH environment variable using QProcessEnvironment so that you don't rely on where it could be exactly and also provide the option for your users to change the path where that application can be found.
-
Rather than hard coding such a path, you might want to consider modifying the PATH environment variable using QProcessEnvironment so that you don't rely on where it could be exactly and also provide the option for your users to change the path where that application can be found.
@SGaist sure QProcessEnvironment is a better way.
Also, I thought I could find the path programmatically like using shutil.which("app") but when the program is bundled and launched from the myApp.app. shutil.which() can't find program in /usr/local... it only find os based executable like ls. -
How are you bundling it ?
Is it a compiled executable ? -
I meant the application you execute with QProcess.
-
Oh it's youtube-dl and it's work fine like I said if I specify the absolute path of the executable in this case it's /usr/local/bin/...
Sorry it's not related to QProcess but in some situations youtube-dl needs ffmpeg so I would check if it's installed on the system. That's why I use shutil.which('ffmpeg').
It works great in my virtualenv but after compiled the program, shutil can't find the path of ffmpeg. Somehow it can't find apps in /usr/local/bin even if it is in $PATH. However it will find os based app like "ls", "mkdir"... -
Oh it's youtube-dl and it's work fine like I said if I specify the absolute path of the executable in this case it's /usr/local/bin/...
Sorry it's not related to QProcess but in some situations youtube-dl needs ffmpeg so I would check if it's installed on the system. That's why I use shutil.which('ffmpeg').
It works great in my virtualenv but after compiled the program, shutil can't find the path of ffmpeg. Somehow it can't find apps in /usr/local/bin even if it is in $PATH. However it will find os based app like "ls", "mkdir"... -
@Yok0
Are you certain/usr/local/bin
is on your PATH, really? Things likels
/mkdir
are in/bin
and/or/usr/bin
, which will be on$PATH
, maybe/usr/local/bin
is not.@JonB Yep! I did checked it.
In my app I tried to displayed my $PATH with os.environ.get('PATH'). When I run it in my virtualenv, it shows me to correct $PATH with /usr/bin, /usr/bin/local/, .cargo/bin so on and so forth BUT after bundling the project in an executable, that same command only returns /usr/bin:/bin:/usr/sbin:/sbin
The weird thing is that the app is run by the same user in venv and as a executable. The $PATH is somehow overridden. -
@JonB Yep! I did checked it.
In my app I tried to displayed my $PATH with os.environ.get('PATH'). When I run it in my virtualenv, it shows me to correct $PATH with /usr/bin, /usr/bin/local/, .cargo/bin so on and so forth BUT after bundling the project in an executable, that same command only returns /usr/bin:/bin:/usr/sbin:/sbin
The weird thing is that the app is run by the same user in venv and as a executable. The $PATH is somehow overridden. -
@Yok0
Yes, virtualenv's job is to set your path. It is not surprising it is different from path outside venv.So your problem is that the executable you wish to run lives in a directory which is not on your usual path.
-
@JonB mhm indeed the working direcory of the executable become /
instead of /Users/foo .. obvious, thanks.