Stack Overflow на русском Asked on December 11, 2021
Есть простой интерфейс.
Необходимо чтобы при нажатии кнопки ‘Start’ стартовал прирост 1 единица прогресса в секунду используя обычный метод, например такой:
def add_value(prog_bar):
for i in range(100):
time.sleep(1)
prog_bar.setValue(i)
а при нажатии ‘Stop’ прирост останавливался.
Сделать это необходимо с помощю QThread.
Мой код:
from PyQt5 import QtWidgets
import sys
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QWidget()
window.setWindowTitle('ProgressBar')
vbx = QtWidgets.QVBoxLayout()
prg_bar = QtWidgets.QProgressBar()
prg_bar.setRange(0,100)
button_start = QtWidgets.QPushButton('Start')
button_stop = QtWidgets.QPushButton('Stop')
vbx.addWidget(prg_bar)
vbx.addWidget(button_start)
vbx.addWidget(button_stop)
window.setLayout(vbx)
window.show()
sys.exit(app.exec_())
Можно наследоваться от QThread и использовать QWaitCondition, QMutex и QThread.sleep для того, чтобы генерировать периодические события:
from PyQt5 import QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal, QWaitCondition, QMutex
import sys
class WoofThread(QThread):
# Сигнал потока
signal_woof = pyqtSignal()
def __init__(self):
QThread.__init__(self)
# Поле для работы вечного цикла
self._action = True
# интервал сна/паузы
self._timeout = 1
# объект погружения/пробуждения потока в сон/ из сна
self._waitCondition = QWaitCondition()
def run(self):
mutex = QMutex()
# Поле-признак того, что пока спать, или просыпаться
self._wait = True
self._action = True
while self._action:
# Если поступил приказ ждать - ждем
if self._wait:
mutex.lock()
self._waitCondition.wait(mutex)
mutex.unlock()
# Спим _timeout - времени
QThread.sleep(self._timeout)
# Гав!
self.signal_woof.emit()
# Поехали
def go(self):
self._wait = False
self._waitCondition.wakeAll()
# Погодите
def wait(self):
self._wait = True
# Завершить работу потока
def cancel(self):
self._action = False
self._waitCondition.wakeAll()
app = QtWidgets.QApplication(sys.argv)
thread = WoofThread()
window = QtWidgets.QWidget()
window.setWindowTitle('ProgressBar')
vbx = QtWidgets.QVBoxLayout()
prg_bar = QtWidgets.QProgressBar()
prg_bar.setRange(0,100)
prg_bar.setValue(0)
button_start = QtWidgets.QPushButton('Start')
# Клик вызывает пробуждение и продолжение работы потока
button_start.clicked.connect(thread.go)
button_stop = QtWidgets.QPushButton('Stop')
# Клик вызывает ожидание потока
button_stop.clicked.connect(thread.wait)
# Получили сигнал из потока - увеличили прогресс на +1
thread.signal_woof.connect(lambda: prg_bar.setValue(prg_bar.value() +1))
vbx.addWidget(prg_bar)
vbx.addWidget(button_start)
vbx.addWidget(button_stop)
window.setLayout(vbx)
window.show()
# Запустили поток
thread.start()
sys.exit(app.exec_())
Answered by Alexander Chernin on December 11, 2021
Как вариант:
from PyQt5 import QtCore, QtWidgets
class Worker(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
data = QtCore.pyqtSignal(int)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.running = False
self.num = 0
@QtCore.pyqtSlot()
def read_data_from_sensor(self):
self.started.emit()
QtCore.QThread.msleep(1000) # Моделируем процесс блокировки
while self.running and self.num < 100:
self.num += 1
self.data.emit(self.num)
QtCore.QThread.msleep(1000)
self.finished.emit()
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Реализация QThread-moveToThread")
self.resize(400, 300)
centralWidget = QtWidgets.QWidget(self)
self.setCentralWidget(centralWidget)
self.boton_iniciar = QtWidgets.QPushButton('Начать', self)
self.boton_iniciar.clicked.connect(self.read_data)
self.label_data = QtWidgets.QLabel(self, alignment=QtCore.Qt.AlignCenter)
self.label_data.setText('В ожидании')
self.label_data.adjustSize()
self.prg_bar = QtWidgets.QProgressBar()
layout = QtWidgets.QGridLayout(centralWidget)
layout.addWidget(self.label_data)
layout.addWidget(self.prg_bar)
layout.addWidget(self.boton_iniciar)
self._worker = Worker()
self._worker.started.connect(self.on_started)
self._worker.finished.connect(self.on_finished)
self._worker.data.connect(self.update_label)
self._thread = QtCore.QThread(self)
self._thread.start()
self._worker.moveToThread(self._thread)
@QtCore.pyqtSlot()
def on_started(self):
""" slot будет вызван, когда начнется сбор данных """
if self._worker.num == 100:
self._worker.num = 0
self.prg_bar.setValue(0)
self._worker.running = False
self.label_data.setText("Читаем данные")
self.boton_iniciar.setText("Стоп")
self.boton_iniciar.setEnabled(True)
@QtCore.pyqtSlot()
def on_finished(self):
""" slot будет вызван, когда сбор данных закончится """
self.label_data.setText("В ожидании")
self.boton_iniciar.setText("Начать")
self.boton_iniciar.setEnabled(True)
print("_worker.running: finished", self.prg_bar.value())
@QtCore.pyqtSlot()
def read_data(self):
""" Начать / остановить чтение при нажатии кнопки """
print("_worker.running:", self._worker.running)
self.on_started()
if self._worker.running:
self._worker.running = False
else:
self._worker.running = True
QtCore.QTimer.singleShot(0, self._worker.read_data_from_sensor)
self.boton_iniciar.setEnabled(False)
@QtCore.pyqtSlot(int) # str
def update_label(self, data):
""" Slot будет вызываться при появлении новых данных в метке """
self.prg_bar.setValue(data)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ventana = App()
ventana.show()
sys.exit(app.exec_())
Answered by S. Nick on December 11, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP