Pyqt5 threading can't work (Fatal Python error: could not acquire lock)
Pyqt5 threading can't work (Fatal Python error: could not acquire lock)
我已经阅读了很多关于此的 QThread 教程和 SO Answers。但是我不能让我的线程工作。大多数时候,它只是 运行 一次或打印错误消息。如果我在应用程序启动后立即启动线程,线程会工作,但我希望线程在特定功能后 运行,因为我想先设置目录位置。
文件结构是这样排列的:
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()
我根据各种教程尝试使用各种风格,包括Qthread、QObject、pyqtsignal。但对我没有任何用处。它要么只是打印 "I am the loop" 然后退出。或打印
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
谢谢
你的代码没有问题。该应用程序在调用 QFileDialog.getExistingDirectory
后立即关闭,因为这是 Qt 的特性。
Qt is made to exit when all Windows are closed
应用已关闭,因为您不再有任何 windows。您的应用没有任何 windows,但 QSystemTrayIcon()
。将 setQuitOnLastWindowClosed()
设置为 False 解决了问题。
yourApp.setQuitOnLastWindowClosed(False)
我已经阅读了很多关于此的 QThread 教程和 SO Answers。但是我不能让我的线程工作。大多数时候,它只是 运行 一次或打印错误消息。如果我在应用程序启动后立即启动线程,线程会工作,但我希望线程在特定功能后 运行,因为我想先设置目录位置。
文件结构是这样排列的:
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()
我根据各种教程尝试使用各种风格,包括Qthread、QObject、pyqtsignal。但对我没有任何用处。它要么只是打印 "I am the loop" 然后退出。或打印
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
谢谢
你的代码没有问题。该应用程序在调用 QFileDialog.getExistingDirectory
后立即关闭,因为这是 Qt 的特性。
Qt is made to exit when all Windows are closed
应用已关闭,因为您不再有任何 windows。您的应用没有任何 windows,但 QSystemTrayIcon()
。将 setQuitOnLastWindowClosed()
设置为 False 解决了问题。
yourApp.setQuitOnLastWindowClosed(False)