Corsa1r
@Corsa1r
Учу Python

Как сделать цикл PyQt5, что бы он обновлялся в интерфейсе приложения?

Ответ вроде как нашел, но немного не могу додуматься. Знатоки поточности "thread" и PyQt выручайте новичка.
Суть: Есть программа, таймер обратного отсчета. Сначала кнопками "Up" и "Down" выбираем время, жмем старт и должен пойти отсчет в label. Так же кнопка "Start" становиться кнопкой "Стоп". При её нажатии отсчет прекращается и всё возвращается в начальное положение. После окончания таймера в данном случае выполняется "print("END")"
639758cc37690043022652.png
Характер проблемы: При нажатии кнопок "Up" и "Down", label меняется. Но при нажатии "Start" интерфейс программы зависает, однако сам код продолжает выполняться.
from PyQt5 import QtCore, QtGui, QtWidgets
import os
from time import sleep
import threading

global hours
global minutes
global seconds
hours = "00"
minutes = "00"
seconds = "00"
global flag
flag = "green"

def sleep_timer():
	global hours
	global minutes
	global seconds
	if int(minutes) > 0:
		minutes = int(minutes) - 1
	seconds = "59"
	flag_timer = True
	while flag_timer:
		while int(hours) >= 0:
			while int(minutes) >= 0:
				while int(seconds) > 0:
					if int(minutes) < 10:
						minutes = "0" + str(minutes)
					if int(seconds) < 10:
						seconds = "0" + str(seconds)
					all_numbers = str(hours) + ":" + str(minutes) + ":" + str(seconds)

					self.label.setText(all_numbers)

					print(all_numbers)
					minutes = int(minutes)
					seconds = int(seconds)
					seconds = int(seconds) - 1
					QtCore.QThread.sleep(1)
				minutes = int(minutes) - 1
				seconds = 59
			if int(hours) != 0:
				hours = int(hours) - 1
				minutes = 59
			else:
				hours = int(hours) - 1
		flag_timer = False
	print("END")

class Ui_MainWindow(object):
	def setupUi(self, MainWindow):
		MainWindow.setObjectName("MainWindow")
		MainWindow.resize(230, 185)
		MainWindow.setStyleSheet("background-color: rgb(26, 74, 90);")
		MainWindow.setWindowIcon(QtGui.QIcon("time.png"))
		self.centralwidget = QtWidgets.QWidget(MainWindow)
		self.centralwidget.setObjectName("centralwidget")
		self.label = QtWidgets.QLabel(self.centralwidget)
		self.label.setGeometry(QtCore.QRect(0, 40, 230, 60))
		font = QtGui.QFont()
		font.setPointSize(32)
		font.setBold(True)
		font.setWeight(75)
		self.label.setFont(font)
		self.label.setStyleSheet("color: rgb(20, 141, 141);")
		self.label.setAlignment(QtCore.Qt.AlignCenter)
		self.label.setObjectName("label")
		self.btn_up_m = QtWidgets.QPushButton(self.centralwidget)
		self.btn_up_m.setGeometry(QtCore.QRect(90, 20, 51, 23))
		self.btn_up_m.setStyleSheet("background-color: rgb(20, 141, 141);border: 0;border-radius: 5px;color: #c1e1a7;font: bold;")
		self.btn_up_m.setObjectName("btn_up_m")
		self.btn_up_h = QtWidgets.QPushButton(self.centralwidget)
		self.btn_up_h.setGeometry(QtCore.QRect(20, 20, 51, 23))
		self.btn_up_h.setStyleSheet("background-color: rgb(20, 141, 141);border: 0;border-radius: 5px;color: #c1e1a7;font: bold;")
		self.btn_up_h.setObjectName("btn_up_h")
		self.btn_down_h = QtWidgets.QPushButton(self.centralwidget)
		self.btn_down_h.setGeometry(QtCore.QRect(20, 100, 51, 23))
		self.btn_down_h.setStyleSheet("background-color: rgb(20, 141, 141);border: 0;border-radius: 5px;color: #c1e1a7;font: bold;")
		self.btn_down_h.setObjectName("btn_down_h")
		self.btn_down_m = QtWidgets.QPushButton(self.centralwidget)
		self.btn_down_m.setGeometry(QtCore.QRect(90, 100, 51, 23))
		self.btn_down_m.setStyleSheet("background-color: rgb(20, 141, 141);border: 0;border-radius: 5px;color: #c1e1a7;font: bold;")
		self.btn_down_m.setObjectName("btn_down_m")
		self.btn_start = QtWidgets.QPushButton(self.centralwidget)
		self.btn_start.setGeometry(QtCore.QRect(30, 130, 171, 23))
		self.btn_start.setStyleSheet("background-color: #5EE88D;border: 0;border-radius: 5px;color: rgb(26, 74, 90);font-size: 16px;font: bold;")
		# Red = #E8635E
		# Green = #5EE88D
		self.btn_start.setObjectName("btn_start")
		MainWindow.setCentralWidget(self.centralwidget)
		self.menubar = QtWidgets.QMenuBar(MainWindow)
		self.menubar.setGeometry(QtCore.QRect(0, 0, 230, 21))
		self.menubar.setObjectName("menubar")
		MainWindow.setMenuBar(self.menubar)
		self.statusbar = QtWidgets.QStatusBar(MainWindow)
		self.statusbar.setObjectName("statusbar")
		MainWindow.setStatusBar(self.statusbar)

		self.retranslateUi(MainWindow)
		QtCore.QMetaObject.connectSlotsByName(MainWindow)

		self.add_functions()

	def retranslateUi(self, MainWindow):
		_translate = QtCore.QCoreApplication.translate
		MainWindow.setWindowTitle(_translate("MainWindow", "Sleep timer"))
		self.label.setText(_translate("MainWindow", "00:00:00"))
		self.btn_up_m.setText(_translate("MainWindow", "UP"))
		self.btn_up_h.setText(_translate("MainWindow", "UP"))
		self.btn_down_h.setText(_translate("MainWindow", "DOWN"))
		self.btn_down_m.setText(_translate("MainWindow", "DOWN"))
		self.btn_start.setText(_translate("MainWindow", "START"))

	def add_functions(self):
		self.btn_up_h.clicked.connect(lambda: self.add_number("h", "up"))
		self.btn_down_h.clicked.connect(lambda: self.add_number("h", "down"))
		self.btn_up_m.clicked.connect(lambda: self.add_number("m", "up"))
		self.btn_down_m.clicked.connect(lambda: self.add_number("m", "down"))
		self.btn_start.clicked.connect(lambda: self.start(flag))

	def add_number(self, first, second):
		global hours
		global minutes
		global seconds
		if first == "h":
			if second == "up":
				if int(hours) == 12:
					hours = "00"
				else:
					hours = int(hours) + 1
					if int(hours) < 10:
						hours = "0" + str(hours)
			if second == "down":
				if int(hours) == 0:
					hours = "12"
				else:
					hours = int(hours) - 1
					if int(hours) < 10:
						hours = "0" + str(hours)

		if first == "m":
			if second == "up":
				if int(minutes) == 59:
					minutes = "00"
				else:
					minutes = int(minutes) + 1
					if int(minutes) < 10:
						minutes = "0" + str(minutes)
			if second == "down":
				if int(minutes) == 0:
					minutes = "59"
				else:
					minutes = int(minutes) - 1
					if int(minutes) < 10:
						minutes = "0" + str(minutes)
		all_numbers = str(hours) + ":" + str(minutes) + ":" + str(seconds)
		self.label.setText(all_numbers)
	
	# Функция для кнопки START
	def start(self, flag_1):
		global hours
		global minutes
		global seconds
		global flag
		if flag_1 == "green":
			flag = "red"
			self.btn_start.setStyleSheet("background-color: #E8635E;border: 0;border-radius: 5px;color: rgb(26, 74, 90);font-size: 16px;font: bold;")
			self.btn_start.setText("STOP")
			self.btn_up_h.setVisible(False)
			self.btn_down_h.setVisible(False)
			self.btn_up_m.setVisible(False)
			self.btn_down_m.setVisible(False)
			#t = QtCore.QThread.thread(target=sleep_timer(self), args=())
			t.start()
			#sleep_timer(self)

		else:
			flag = "green"
			self.btn_start.setStyleSheet("background-color: #5EE88D;border: 0;border-radius: 5px;color: rgb(26, 74, 90);font-size: 16px;font: bold;")
			self.btn_start.setText("START")
			hours = "00"
			minutes = "00"
			seconds = "00"
			all_numbers = str(hours) + ":" + str(minutes) + ":" + str(seconds)
			self.label.setText(all_numbers)
			self.btn_up_h.setVisible(True)
			self.btn_down_h.setVisible(True)
			self.btn_up_m.setVisible(True)
			self.btn_down_m.setVisible(True)

t = threading.Thread(target = sleep_timer(), args=())

if __name__ == "__main__":
	import sys
	app = QtWidgets.QApplication(sys.argv)
	#global MainWindow
	MainWindow = QtWidgets.QMainWindow()
	ui = Ui_MainWindow()
	ui.setupUi(MainWindow)
	MainWindow.show()
	sys.exit(app.exec_())

Начитался, мол, надо писать многопоточность, для меня PyQt то что то новое, а тут многопоточность... Ну нашел какой-то код. Попробовал из него взять кусочек. Работает, но вот какая ошибка: Я не могу понять "ветку" label, когда она находиться ВНЕ класса. (Строка 32) Когда внутри класса я обращаюсь просто, через self.
Помогите сделать это рабочим. Спасибо!

P.S. - Прошу прощения если написал вопрос некорректно или непонятно. Первый раз сюда обращаюсь. Не ругайте.
P.S.2 - Если есть какие ни будь предложения по "оптимизации" и лучшей читаемости кода, я Вас очень внимательно слушаю. Возможно что-то, где то, можно было организовать проще и правильней. Еще раз, спасибо!
P.S.3 - Для проверки кода, закомментируйте следующие строки:
173 t.start()
190 t = threading.Thread(target = sleep_timer(), args=())
  • Вопрос задан
  • 201 просмотр
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Многопоточность
Седой и строгий
Во-первых, из потоков нельзя работать с компонентами интерфейса. Во-вторых, из потоков нельзя работать с глобальными переменными.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
CTRL+ Москва
от 250 000 до 320 000 ₽
CTRL+ Москва
от 200 000 до 300 000 ₽
CTRL+ Белград
от 250 000 до 320 000 ₽
22 нояб. 2024, в 00:55
500 руб./за проект
21 нояб. 2024, в 23:30
300000 руб./за проект
21 нояб. 2024, в 22:21
3000 руб./в час