简体   繁体   English

Pyqt5线程无法正常工作(致命的Python错误:无法获取锁)

[英]Pyqt5 threading can't work (Fatal Python error: could not acquire lock)

I have read bunch of QThread tutorials and SO Answers about this. 我已经阅读了一堆QThread教程和SO Answers。 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 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 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 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 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 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. 根据各种教程,我尝试使用各种样式,包括Qthread,QObject,pyqtsignal。 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. 调用QFileDialog.getExistingDirectory后,应用立即关闭,因为这是Qt的本质。

Qt is made to exit when all Windows are closed 关闭所有Windows时退出Qt

The app closed because you no longer have any windows. 该应用已关闭,因为您不再有任何窗口。 Your app doesn't have any windows but QSystemTrayIcon() . 您的应用程序没有任何窗口,但QSystemTrayIcon() Setting setQuitOnLastWindowClosed() to False solved the problem. setQuitOnLastWindowClosed()设置为False可以解决此问题。

yourApp.setQuitOnLastWindowClosed(False)

Source 资源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM