I have read bunch of QThread tutorials and SO Answers about this. But I can't make my threading works. Most of the time, it just run once or it print error message. Threading works if I started it immediately after the app start, but I want the thread to run after certain function, cause I want to set the directory location first.
The file structure is arranged like this:
App.py
Controllers/
main_controller.py
recorder.py
Model/
model.py
Views/
main_view.py
App.py
import sys
from PyQt5.QtWidgets import QApplication
from Model.model import Model
from Controllers.main_controller import MainController
from Views.main_view import MainView
class App(QApplication):
def __init__(self, sys_argv):
super().__init__(sys_argv)
self.model = Model()
self.main_controller = MainController(self.model)
self.main_view = MainView(self.model, self.main_controller)
if __name__ == "__main__":
app = App(sys.argv)
sys.exit(app.exec_())
model.py
from PyQt5.QtCore import QObject
class Model(QObject):
def __init__(self):
super().__init__()
self.directory = ""
def get_directory(self):
return self.directory
def set_directory(self, directory):
self.directory = directory
main_view.py
from PyQt5.QtWidgets import QMenu, QSystemTrayIcon, QMainWindow, QFileDialog
from PyQt5 import QtGui
from PyQt5.QtWidgets import QApplication
from Controllers.recorder import Recorder
class MainView(QMainWindow):
def __init__(self, model, main_controller):
super().__init__()
self._model = model
self._main_controller = main_controller
# UI
icon = QtGui.QIcon("icon24x24.png")
menu = QMenu()
start_action = menu.addAction("Start Recording")
stop_action = menu.addAction("Stop Recording")
self.tray = QSystemTrayIcon()
self.tray.setIcon(icon)
self.tray.setContextMenu(menu)
self.tray.show()
start_action.triggered.connect(self.start_app)
stop_action.triggered.connect(self.stop_app)
self.recordThread = Recorder()
def start_app(self):
directory = QFileDialog.getExistingDirectory(self, "Select Directory")
self._main_controller.set_directory(directory)
self.start_thread()
def start_thread(self):
self.recordThread.start()
def stop_app(self):
self.recordThread.terminate()
QApplication.instance().quit()
print("app stopped")
main_controller.py
from PyQt5.QtCore import QObject
class MainController(QObject):
def __init__(self, model):
super().__init__()
self._model = model
def set_directory(self, directory):
self._model.set_directory(directory)
recorder.py
import time
from PyQt5.QtCore import QThread, QTimer, pyqtSignal
from Model.model import Model
class Recorder(QThread):
job_done = pyqtSignal()
def __init__(self):
QThread.__init__(self)
self._model = Model()
def __del__(self):
self.wait()
def run(self):
while True:
print("I am the loop")
print(self._model.get_directory())
# time.sleep(4 - time.time() % 4)
QThread.sleep(4)
print("now is {}".format(time.time()))
self.job_done.emit()
I've tried using various style, including Qthread, QObject, pyqtsignal according to various tutorial. but nothing works for me. It either just print "I am the loop" then exit. or print
I am the loop
Fatal Python error: could not acquire lock for <_io.BufferedWriter name='<stdout>'> at interpreter shutdown, possibly due to daemon threads
Thread 0x00007f5d1bfff700 (most recent call first):
File "/App/Controllers/recorder.py", line 20 in run
Current thread 0x00007f5d3458f700 (most recent call first):
Aborted
Thank you
Nothing wrong with your code. The app closed immediately after calling QFileDialog.getExistingDirectory
because it's the nature of Qt.
Qt is made to exit when all Windows are closed
The app closed because you no longer have any windows. Your app doesn't have any windows but QSystemTrayIcon()
. Setting setQuitOnLastWindowClosed()
to False solved the problem.
yourApp.setQuitOnLastWindowClosed(False)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.