QTimer не работает в дополнительном потоке QThread
Я создаю отдельный дополнительный поток и пытаюсь в нем запустить QTimer, чтобы раз в секунду он вызывал функцию, которая должна запускаться в этом же потоке.
Но этого не происходит, таймер просто не работает.
В чем может быть ошибка?
import sys
from time import sleep
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QMainWindow
from PyQt5.QtCore import QThread, QObject, QTimer
class Worker(QObject):
def __init__(self):
super().__init__()
def print_2(self):
print(2)
def run(self):
self.timer = QTimer()
self.timer.timeout.connect(self.print_2)
self.timer.start(1000)
while True:
print(1)
sleep(1)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.central_widget = QWidget(self)
self.setCentralWidget(self.central_widget)
self.layout_window = QVBoxLayout()
self.central_widget.setLayout(self.layout_window)
self.btn = QPushButton('Запустить поток')
self.btn.clicked.connect(self.start_thread)
self.layout_window.addWidget(self.btn)
def start_thread(self):
self.main_thread = QThread(parent=self)
self.worker = Worker()
self.worker.moveToThread(self.main_thread)
self.main_thread.started.connect(self.worker.run)
self.main_thread.start()
app = QApplication(sys.argv)
app.setStyle('Fusion')
main_window = MainWindow()
main_window.show()
sys.exit(app.exec_())
Ответы (1 шт):
Я не понимаю зачем вам в отдельном потоке запускать QTimer?
Я не знаю, что это за задача, которую вы хотите периодически запускать
раз в секунду?
QTimer — это класс, который наследуется от QObject,
а QObject принадлежит тому же, что и родитель,
и если у него нет родителя, он принадлежит потоку, в котором он был создан.
С другой стороны, QThread — это поток Qt, но это не так,
QThread — это класс, который позволяет обрабатывать
жизненный цикл собственного потока, и это четко указано в документации:
QThread class предоставляет независимый от платформы способ управления потоками.
Также обратите внимание, что новый поток, который обрабатывает QThread,
имеет только область действия метода run(),
если метод находится в другом месте, относится к полю,
где был создан QThread.
QTimer - работает только в потоке, в котором он был создан.
Попробуйте проанализировать свой код (threading.get_ident())
какой метод в каком потоке выполняется.
Вы увидите, что метод run() и метод print_2() выполняются в разных потоках.
Вот почему таймер просто не работает.
Учитывая, что я не совсем понимаю, то о чем писал выше и
только для демонстрации области действия метода run():
import sys
#from time import sleep
import threading
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, \
QPushButton, QMainWindow
from PyQt5.QtCore import QThread, QObject, QTimer
class Worker(QObject):
def __init__(self):
super().__init__()
self.timer = QTimer()
self.timer.timeout.connect(self.print_2)
self.timer.setInterval(300) # 1000
self.timer.start()
print(f"timer from : {threading.get_ident()}")
self.flag = True
def print_2(self):
# print(f'print_2(self): 2')
print(f"print_2(self) : {threading.get_ident()}")
def run(self):
QThread.msleep(1000)
while self.flag:
print(f"run(self): while True: {threading.get_ident()}\n")
QThread.msleep(1000)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.central_widget = QWidget(self)
self.setCentralWidget(self.central_widget)
self.main_thread = None
self.btn = QPushButton('Запустить поток')
self.btn.clicked.connect(self.start_thread)
self.layout_window = QVBoxLayout(self.central_widget)
self.layout_window.addWidget(self.btn)
def start_thread(self):
self.btn.setEnabled(False)
self.main_thread = QThread() #-parent=self
self.worker = Worker()
print(f"self.worker: {threading.get_ident()}\n")
self.worker.moveToThread(self.main_thread)
self.main_thread.started.connect(self.worker.run)
self.main_thread.start()
def closeEvent(self, event):
if self.main_thread:
self.worker.flag = False
self.worker.timer.stop()
self.main_thread.terminate()
self.main_thread.wait(1)
super().closeEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('Fusion')
w = MainWindow()
w.resize(300, 200)
w.show()
sys.exit(app.exec_())
