Блокировка QMessageBox при выполнении цикла while в дополнительном потоке
Есть код, который изначально был сделан в одном потоке, но блокировался основной потоке при работе бесконечного цикла (while True:).
После вроде разобрался, сделал выполнение функции в другом потоке. Но при вызове перестают работать QMessageBox (программа сообщения передает, но вылетает), которые мне необходимы об уведомлении, что будильник свою работу выполнил, либо же время было некорректно установлено.
Думаю и переделываю уже 3 день все, проблема наверное в бесконечном цикле.
Собственно прошу помощи в данной проблеме и пути ее решения. Опыта у меня немного, заранее спасибо!
class WorkerThread(QThread):
message = pyqtSignal(str)
def __init__(self, callback, *args, **kwargs):
super().__init__()
self.callback = callback
self.args = args
self.kwargs = kwargs
def run(self):
self.callback(*self.args, **self.kwargs)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(331, 345)
MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonStyle.ToolButtonTextOnly)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.groupBox = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox.setGeometry(QtCore.QRect(30, 10, 271, 71))
self.groupBox.setObjectName("groupBox")
self.groupBox.setStyleSheet("color: black; "
"font-weight: bold;"
"")
self.label = QtWidgets.QLabel(parent=self.groupBox)
self.label.setGeometry(QtCore.QRect(20, 20, 231, 41))
self.label.setObjectName("label")
self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.label.setFont(QtGui.QFont("Times", 20)) #ШРИФТ И РАЗМЕР
self.label.setStyleSheet("font-weight: bold;"
"border: 1px solid;")
self.groupBox_2 = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox_2.setGeometry(QtCore.QRect(30, 110, 271, 61))
self.groupBox_2.setObjectName("groupBox_2")
self.groupBox_2.setStyleSheet("color: black; "
"font-weight: bold;"
"")
self.timeEdit = QtWidgets.QTimeEdit(parent=self.groupBox_2)
self.timeEdit.setEnabled(True)
self.timeEdit.setGeometry(QtCore.QRect(10, 20, 251, 31))
self.timeEdit.setWrapping(False)
self.timeEdit.setFrame(False)
self.timeEdit.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.timeEdit.setButtonSymbols(QtWidgets.QAbstractSpinBox.ButtonSymbols.UpDownArrows)
self.timeEdit.setAccelerated(False)
self.timeEdit.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectionMode.CorrectToPreviousValue)
self.timeEdit.setProperty("showGroupSeparator", False)
self.timeEdit.setTime(QtCore.QTime(0, 0, 0))
self.timeEdit.setObjectName("timeEdit")
self.timeEdit.setFont(QtGui.QFont("Times", 20))
self.timeEdit.setStyleSheet("font-weight: bold;"
"border: 1px solid;")
self.groupBox_3 = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox_3.setGeometry(QtCore.QRect(29, 180, 271, 61))
self.groupBox_3.setObjectName("groupBox_3")
self.lineEdit = QtWidgets.QLineEdit(parent=self.groupBox_3)
self.lineEdit.setGeometry(QtCore.QRect(10, 20, 251, 31))
self.lineEdit.setFrame(False)
self.lineEdit.setObjectName("lineEdit")
self.pushButton = QtWidgets.QPushButton(parent=self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(30, 260, 271, 41))
self.pushButton.setObjectName("pushButton")
self.line = QtWidgets.QFrame(parent=self.centralwidget)
self.line.setGeometry(QtCore.QRect(10, 10, 20, 311))
self.line.setFrameShape(QtWidgets.QFrame.Shape.VLine)
self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.line.setObjectName("line")
self.line_2 = QtWidgets.QFrame(parent=self.centralwidget)
self.line_2.setGeometry(QtCore.QRect(300, 10, 21, 311))
self.line_2.setFrameShape(QtWidgets.QFrame.Shape.VLine)
self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.line_2.setObjectName("line_2")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def Svernut(self):
self.showMinimized()
def update_time(self):
self.timer = QTimer()
self.timer.timeout.connect(self.update_time)
self.timer.start(1000)
current_time = QDateTime.currentDateTime().toString('hh:mm:ss')
self.label.setText(current_time)
def run_alarm(self):
self.worker = WorkerThread(self.alarm)
self.worker.message.connect(self.show_message)
self.worker.start()
def alarm(self):
now = datetime.now()
t_mod = self.timeEdit.time()
while True:
now = datetime.now()
if now.hour <= t_mod.hour():
if now.minute == t_mod.minute():
self.worker.message.emit('Будильник')
print("YES")
break
elif t_mod.minute() <= now.minute:
print("NO")
break
else:
pass
else:
pass
def show_message(self, message):
print(message)
QtWidgets.QMessageBox.information(self, 'Bудильник', message)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Будильник"))
self.groupBox.setTitle(_translate("MainWindow", "Текущее время"))
self.groupBox_2.setTitle(_translate("MainWindow", "Будильник"))
self.groupBox_3.setTitle(_translate("MainWindow", "Сообщение"))
self.pushButton.setText(_translate("MainWindow", "Поставить будильник"))
self.update_time()
self.pushButton.clicked.connect(self.run_alarm)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec())
Ответы (1 шт):
НИКОГДА НЕ ИЗМЕНЯЙТЕ код, сгенерированный Qt Designer, НИКОГДА.
Создайте другой класс, который наследуется от соответствующего виджета, и используйте созданный класс для его заполнения.Бесконечный цикл нельзя использовать в основном потоке, это блокирует интерфейс.
Я оставил возможный вариант с дополнительным потоком и бесконечным циклом в нем.
Хотя для вашей задачи не нужен ни бесконечный цикл, ни дополнительный поток. Все что вам надо это
QTimer. Подумайте как это можно реализовать только используяQTimer, если у вас что-то не получится, а вам это будет надо - зададите новый вопрос.
from datetime import datetime
from PyQt5.Qt import *
from PyQt5 import QtWidgets, QtCore, QtGui
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(331, 345)
MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonStyle.ToolButtonTextOnly)
self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.groupBox = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox.setGeometry(QtCore.QRect(30, 10, 271, 71))
self.groupBox.setObjectName("groupBox")
self.groupBox.setStyleSheet("color: black; "
"font-weight: bold;"
"")
self.label = QtWidgets.QLabel(parent=self.groupBox)
self.label.setGeometry(QtCore.QRect(20, 20, 231, 41))
self.label.setObjectName("label")
self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.label.setFont(QtGui.QFont("Times", 20)) # ШРИФТ И РАЗМЕР
self.label.setStyleSheet("font-weight: bold;"
"border: 1px solid;")
self.groupBox_2 = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox_2.setGeometry(QtCore.QRect(30, 110, 271, 61))
self.groupBox_2.setObjectName("groupBox_2")
self.groupBox_2.setStyleSheet("color: black; "
"font-weight: bold;"
"")
self.timeEdit = QtWidgets.QTimeEdit(parent=self.groupBox_2)
self.timeEdit.setEnabled(True)
self.timeEdit.setGeometry(QtCore.QRect(10, 20, 251, 31))
self.timeEdit.setWrapping(False)
self.timeEdit.setFrame(False)
self.timeEdit.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.timeEdit.setButtonSymbols(QtWidgets.QAbstractSpinBox.ButtonSymbols.UpDownArrows)
self.timeEdit.setAccelerated(False)
self.timeEdit.setCorrectionMode(QtWidgets.QAbstractSpinBox.CorrectionMode.CorrectToPreviousValue)
self.timeEdit.setProperty("showGroupSeparator", False)
self.timeEdit.setTime(QtCore.QTime(0, 0, 0))
self.timeEdit.setObjectName("timeEdit")
self.timeEdit.setFont(QtGui.QFont("Times", 20))
self.timeEdit.setStyleSheet("font-weight: bold;"
"border: 1px solid;")
self.groupBox_3 = QtWidgets.QGroupBox(parent=self.centralwidget)
self.groupBox_3.setGeometry(QtCore.QRect(29, 180, 271, 61))
self.groupBox_3.setObjectName("groupBox_3")
self.lineEdit = QtWidgets.QLineEdit(parent=self.groupBox_3)
self.lineEdit.setGeometry(QtCore.QRect(10, 20, 251, 31))
self.lineEdit.setFrame(False)
self.lineEdit.setObjectName("lineEdit")
self.pushButton = QtWidgets.QPushButton(parent=self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(30, 260, 271, 41))
self.pushButton.setObjectName("pushButton")
self.line = QtWidgets.QFrame(parent=self.centralwidget)
self.line.setGeometry(QtCore.QRect(10, 10, 20, 311))
self.line.setFrameShape(QtWidgets.QFrame.Shape.VLine)
self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.line.setObjectName("line")
self.line_2 = QtWidgets.QFrame(parent=self.centralwidget)
self.line_2.setGeometry(QtCore.QRect(300, 10, 21, 311))
self.line_2.setFrameShape(QtWidgets.QFrame.Shape.VLine)
self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken)
self.line_2.setObjectName("line_2")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Будильник"))
self.groupBox.setTitle(_translate("MainWindow", "Текущее время"))
self.groupBox_2.setTitle(_translate("MainWindow", "Будильник"))
self.groupBox_3.setTitle(_translate("MainWindow", "Сообщение"))
self.pushButton.setText(_translate("MainWindow", "Поставить будильник"))
# self.update_time()
# self.pushButton.clicked.connect(self.run_alarm)
class WorkerThread(QThread):
message = pyqtSignal(str)
def __init__(self): #(self, callback, *args, **kwargs):
super().__init__()
# self.callback = callback
# self.args = args
# self.kwargs = kwargs
self.t_mod_hour = 0 # +++
self.t_mod_minute = 0 # +++
self.flag = False # +++
def run(self):
while self.flag:
now = datetime.now()
# if now.hour <= self.t_mod_hour:
if now.hour == self.t_mod_hour:
if now.minute == self.t_mod_minute:
self.message.emit('Будильник')
#print("YES")
self.flag = False
elif self.t_mod_minute < now.minute:
self.message.emit('NO. Установите новое время для будильника.')
#print("NO")
self.flag = False
self.msleep(1000) # +++
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.run_alarm)
self.timer = QTimer() # +++
self.timer.timeout.connect(self.update_time) # +++
self.timer.start(1000) # +++
# self.update_time()
self.worker = WorkerThread() # +++
self.worker.message.connect(self.show_message) # +++
# ?? def Svernut(self):
# ?? self.showMinimized()
def update_time(self):
current_time = QDateTime.currentDateTime().toString('hh:mm:ss')
self.label.setText(current_time)
def run_alarm(self):
# self.worker = WorkerThread(self.alarm)
# self.worker.message.connect(self.show_message)
self.worker.t_mod_hour = self.timeEdit.time().hour() # +++
self.worker.t_mod_minute = self.timeEdit.time().minute() # +++
self.worker.flag = True # +++
self.worker.start()
def show_message(self, message):
self.lineEdit.setText(message) # +++
QtWidgets.QMessageBox.information(self,
'Bудильник',
f'{message}: {self.label.text()}')
def closeEvent(self, event):
self.worker.flag = False
if self.worker.isRunning():
self.worker.terminate()
super().closeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
# MainWindow = QtWidgets.QMainWindow()
# ui = Ui_MainWindow()
# ui.setupUi(MainWindow)
# MainWindow.show()
w = MainWindow()
w.show()
sys.exit(app.exec())

