How to pause/play a thread in PyQT5? - python

I'm making a light GUI program with PyQT5.
But now I'm facing some problem about thread.
I just made simple test program like bottom:
the program simply trying to append numbers to textbox, but it crashes.
I don't know why but somehow I can prevent it by removing a comment(time.sleep)
import sys
import threading
import time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Some(QWidget):
e = threading.Event()
def btnfunc(self):
self.e.set()
def __init__(self):
super().__init__()
self.myButton = QPushButton('do next')
self.logs = QTextEdit()
self.mylay = QVBoxLayout()
self.mylay.addWidget(self.myButton)
self.mylay.addWidget(self.logs)
self.setLayout(self.mylay)
self.setGeometry(300, 300, 300, 550)
self.setWindowTitle('mytest')
self.show()
t = threading.Thread(target=self.myfunc, args=( ))
t.start()
self.myButton.clicked.connect(self.btnfunc)
def myfunc(self):
for i in range(300):
# time.sleep(0.4)
self.logs.append(str(i))
if i == 20:
self.e.wait()
app = QApplication(sys.argv)
ex = Some()
sys.exit(app.exec_())
It would be better if sets time higher.
I thought it is because of resource accessing, since it is pyQT5 GUI.
So I've find QThread. and I tried like bottom,
import sys
import time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Some(QWidget):
qw = QWaitCondition()
qm = QMutex()
def btnfunc(self):
self.qw.wakeAll()
def __init__(self):
super().__init__()
self.myButton = QPushButton('do next')
self.logs = QTextEdit()
self.mylay = QVBoxLayout()
self.mylay.addWidget(self.myButton)
self.mylay.addWidget(self.logs)
self.setLayout(self.mylay)
self.setGeometry(300, 300, 300, 550)
self.setWindowTitle('mytest')
self.show()
self.myButton.clicked.connect(self.btnfunc)
self.thread = QThread()
self.thread.started.connect(self.myfunc)
self.thread.start()
def myfunc(self):
for i in range(300):
self.logs.append(str(i))
if i == 20:
self.qw.wait(self.qm)
app = QApplication(sys.argv)
ex = Some()
sys.exit(app.exec_())
But crashes, doesn't work. and tried QThread+threading.Event(). It freezes GUI.
Now I don't know how to proceed it...
Edit:
I just realized about thread. Should not be accessed from other thread except QThread.
Then I will keep find about QWaitCondition

You should not control GUI directly via multithreading. Since two different threads are trying to control the GUI this results to freeze or crash.
I have learnt about this concept from here http://www.xyzlang.com/python/PyQT5/pyqt_multithreading.html
Here is your code that will work perfectly.
import sys
import threading
import time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
# Added new
class Communicate(QObject):
signal = pyqtSignal(str)
class Some(QWidget):
e = threading.Event()
def btnfunc(self):
self.e.set()
def __init__(self):
super().__init__()
#communicate object
self.comm = Communicate()
self.comm.signal.connect(self.append_data)
self.myButton = QPushButton('do next')
self.logs = QTextEdit()
self.mylay = QVBoxLayout()
self.mylay.addWidget(self.myButton)
self.mylay.addWidget(self.logs)
self.setLayout(self.mylay)
self.setGeometry(300, 300, 300, 550)
self.setWindowTitle('mytest')
self.show()
t = threading.Thread(target=self.myfunc, args=( ))
t.start()
self.myButton.clicked.connect(self.btnfunc)
def myfunc(self):
for i in range(300):
# time.sleep(0.4)
#self.logs.append(str(i))
self.comm.signal.emit(str(i))
if i == 20:
self.e.wait()
def append_data(self, data):
self.logs.append(data)
app = QApplication(sys.argv)
ex = Some()
sys.exit(app.exec_())

You can pause the loop by using while = True and you can stop the loop with break statement
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import (
Qt, QObject, pyqtSignal, pyqtSlot, QRunnable, QThreadPool
)
import time
from time import sleep
import threading
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(655, 589)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.run = QtWidgets.QPushButton(self.centralwidget)
self.run.setGeometry(QtCore.QRect(260, 50, 93, 28))
self.run.setObjectName("run")
self.result = QtWidgets.QTextEdit(self.centralwidget)
self.result.setGeometry(QtCore.QRect(110, 120, 491, 201))
self.result.setObjectName("result")
self.stop = QtWidgets.QPushButton(self.centralwidget)
self.stop.setGeometry(QtCore.QRect(110, 390, 93, 28))
self.stop.setObjectName("stop")
self.pause = QtWidgets.QPushButton(self.centralwidget)
self.pause.setGeometry(QtCore.QRect(300, 390, 93, 28))
self.pause.setObjectName("pause")
self.resume = QtWidgets.QPushButton(self.centralwidget)
self.resume.setGeometry(QtCore.QRect(480, 390, 93, 28))
self.resume.setObjectName("resume")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 655, 26))
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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.run.setText(_translate("MainWindow", "Run"))
self.stop.setText(_translate("MainWindow", "stop"))
self.pause.setText(_translate("MainWindow", "Pause"))
self.resume.setText(_translate("MainWindow", "Resume"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.is_paused = False
self.is_killed = False
self.run.clicked.connect(self.send_wala)
self.stop.clicked.connect(self.kill_g)
self.pause.clicked.connect(self.pause_g)
self.resume.clicked.connect(self.resume_g)
#QtCore.pyqtSlot()
def send_wala(self):
threading.Thread(target=self.working, daemon=True).start()
def working(self):
for i in range(10):
sleep(3)
self.result.append(str(i))
while self.is_paused:
time.sleep(0)
if self.is_killed:
break
def pause_g(self):
self.is_paused = True
def resume_g(self):
self.is_paused = False
def kill_g(self):
self.is_killed = True
import sys
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Related

Python threading - Change variable value in another class

I am looking for a way to change the variables between classes in different threads.
As I had a question about threading recently, I'd like to use that example code for this question again.
Main-File:
#PROGRAM/SCRIPT
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication
import sys
import GUI
import datetime
import pyqtgraph
import time
plotsize = 20
class Worker2(QtCore.QThread):
def __init__(self):
print("Thread2 has been started")
def run(self):
#now get access to variable of class Worker
# =============================================================================
# Threading for not freezing the GUI while running
# =============================================================================
class Worker(QtCore.QThread):
progress = QtCore.pyqtSignal(int)
finished = QtCore.pyqtSignal()
widgetplot = QtCore.pyqtSignal(list, list)
def __init__(self, plot_time, plot_value):
print("Thread has been started")
QtCore.QThread.__init__(self, objectName='WorkerThread')
self.plot_time = plot_time
self.plot_value = plot_value
def run(self):
#now get access to variable of Worker2
_count = 0
_start_time = datetime.datetime.now()
while 0 <= _count < 100:
# Use local variable!
_count_prev = _count
QtCore.QThread.usleep(10000)
_diff = datetime.datetime.now() - _start_time
_count = int((_diff.total_seconds() * 10))
if(_count != _count_prev):
print(_count)
x = self.plot_time[:_count]
y = self.plot_value[:_count]
self.widgetplot.emit(x, y)
class my_class(QtWidgets.QMainWindow, GUI.Ui_MainWindow):
def __init__(self, parent=None):
super(my_class, self).__init__(parent)
self.setupUi(self)
self.WidgetPlot.setXRange(0, 105, padding=0)
self.WidgetPlot.setYRange(0, 105, padding=0)
self.second_line = pyqtgraph.PlotDataItem(pen=pyqtgraph.mkPen('w', width=plotsize*2))
self.plot_time = []
self.plot_value = []
self.worker_thread = Worker(self.plot_time, self.plot_value)
self.worker_thread.widgetplot.connect(self.update_second_line_plot)
self.worker_thread2 = Worker2()
self.pushButton.clicked.connect(self.my_function)
self.WidgetPlot.setMouseEnabled(x=False, y=False)
font=QtGui.QFont()
font.setPixelSize(20)
font.setBold(True)
self.WidgetPlot.getAxis("bottom").setTickFont(font)
self.WidgetPlot.getAxis("left").setTickFont(font)
def my_function(self):
_l = list(range(100))
self.plot_time.extend(_l)
self.plot_value.extend(_l)
self.start()
def update_second_line_plot(self, plot_time, plot_value):
self.second_line.setData(plot_time, plot_value)
def start(self):
self.WidgetPlot.plot(self.plot_time, self.plot_value, pen=pyqtgraph.mkPen('r', width=plotsize))
self.WidgetPlot.addItem(self.second_line)
self.worker_thread.start()
self.worker_thread2.start()
def main():
app = QApplication(sys.argv)
form = my_class()
form.show()
app.exec_()
if __name__ == '__main__':
main()
GUI:
#GUI.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(739, 532)
MainWindow.setStyleSheet("")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.WidgetPlot = PlotWidget(self.centralwidget)
self.WidgetPlot.setGeometry(QtCore.QRect(100, 40, 541, 341))
self.WidgetPlot.setObjectName("WidgetPlot")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(330, 420, 93, 28))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Main Window"))
self.pushButton.setText(_translate("MainWindow", "Start"))
from pyqtgraph import PlotWidget
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_())
I'd like to change variable in class Worker2 from class Worker and vice versa.
Many thanks in advance!
Andrew
but for the other class there is no way to call/change variables...
Member variables* in Python are public by default.** Suppose you have
class P:
def __init__(self):
self.q = "whatever"
def printit(self):
print(self.q)
You can do this in the repl:
>>> p = P()
p = P()
>>> p.printit()
p.printit()
whatever
>>> p.q
p.q
'whatever'
>>> p.q = 'new value'
p.q = 'new value'
>>> p.printit()
p.printit()
new value
>>> p.q
p.q
'new value'
You can do the same from anywhere in Python code that has a reference to an object belonging to class P.
* "Attributes?" "fields?" I wrote a lot of Python programs that were ancillary to projects that I worked on—mostly for my own use. I haven't talked a lot with other Python programmers, and I don't really know the lingo.
** See https://towardsdatascience.com/private-protected-attributes-in-python-demystified-once-and-for-all-9456d4e56414 for more about "public" vs. "private."

xbbg pulling bdp data with multithreading

I am trying to develop a pyqt5 app where I can live stream stock prices from Bloomberg. I put some field names (eg. LAST_TRADE) in the ThreadClass (QThread) to pull price every second. I also have a function in the main class to pull some non-realtime data (eg. PX_YEST_CLOSE) from Bloomberg whenever a push button is clicked. I ran into this issue that when the push button clicked, it sometimes returns LAST_TRADE data instead of PX_YEST_CLOSE. I think this is because the API only allow one request at a time. Is there a better way to workaround it?
I've included a simple version of my code below just to illustrate. Thank you!
import sys, time
from xbbg import blp
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow
from ui_interface import Ui_MainWindow
ticker = ['AMD Equity', 'NVDA Equity', 'CHK Equity', 'ABNB Equity', 'AFRM Equity', 'U Equity']
live_fields = ['LAST_TRADE']
class MainWindow(QMainWindow, Ui_MainWindow):
"""Class for the Main window"""
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.thread={}
self.getStaticData()
self.connectSignalsSlots()
self.start_worker()
def getStaticData(self):
'''Pull static data from Bloomberg'''
self.staticData = blp.bdp(list(set(ticker)), flds=['CUR_MKT_CAP', 'PX_YEST_CLOSE'])
self.label_2.setText(str(self.staticData.iat[0,0]))
def start_worker(self):
self.thread[1] = ThreadClass(parent = None)
self.thread[1].start()
self.thread[1].any_signal.connect(self.liveFeed)
def liveFeed(self,liveData):
self.label.setText(str(liveData.iat[0,0]))
def updateData(self):
'''Update table if clicked'''
print(blp.bdp(['AAPL Equity'], flds=['CUR_MKT_CAP', 'PX_YEST_CLOSE']))
def connectSignalsSlots(self):
'''Signal-slots connections'''
self.pushButton.clicked.connect(self.updateData)
class ThreadClass(QtCore.QThread):
any_signal = QtCore.pyqtSignal(object)
def __init__(self, parent=None):
super(ThreadClass, self).__init__(parent)
self.is_running = True
def run(self):
print('Starting...')
while (True):
data=blp.bdp(ticker, flds=live_fields)
time.sleep(0.1)
self.any_signal.emit(data)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
control = MainWindow()
widget = QtWidgets.QStackedWidget()
widget.addWidget(control)
widget.show()
sys.exit(app.exec())
UI below:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(590, 582)
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.pushButton = QPushButton(self.centralwidget)
self.pushButton.setObjectName(u"pushButton")
self.pushButton.setGeometry(QRect(360, 80, 75, 23))
self.label = QLabel(self.centralwidget)
self.label.setObjectName(u"label")
self.label.setGeometry(QRect(90, 70, 171, 41))
self.label_2 = QLabel(self.centralwidget)
self.label_2.setObjectName(u"label_2")
self.label_2.setGeometry(QRect(90, 140, 171, 41))
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 590, 21))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QStatusBar(MainWindow)
self.statusbar.setObjectName(u"statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
self.pushButton.setText(QCoreApplication.translate("MainWindow", u"Update", None))
self.label.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))
self.label_2.setText(QCoreApplication.translate("MainWindow", u"TextLabel", None))

How to stop a thread using a button

We are creating an object detection project using Object detection API. We are train the program making pyqt5 GUI application. Trying to run the training part using thread. We want to stop the running thread using a push button. Here the code sample
class stopClass(QtCore.QThread):
def __init__(self, parent=None):
super(stopClass, self).__init__(parent)
def startTrain(self):
#changing directory
os.chdir(r"c://tensorflow_1//models//research//object_detection")
args3 = shlex.split('python train.py --logtostderr --train_dir=training/ --
pipeline_config_path=training/faster_rcnn_inception_v2_pets.config')
subprocess.run(args3, shell = True)
return
def run(self):
self.startTrain()
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(701, 495)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.Annotation = QtWidgets.QPushButton(self.centralwidget)
self.Annotation.setGeometry(QtCore.QRect(480, 10, 181, 41))
self.Annotation.setToolTip("")
self.Annotation.setObjectName("Annotation")
self.Start_train = QtWidgets.QPushButton(self.centralwidget)
self.Start_train.setGeometry(QtCore.QRect(480, 110, 181, 41))
self.Start_train.setObjectName("Start_train")
self.Stop_train = QtWidgets.QPushButton(self.centralwidget)
self.Stop_train.setEnabled(False)
self.Stop_train.setGeometry(QtCore.QRect(480, 160, 181, 41))
self.Stop_train.setObjectName("Stop_train")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 701, 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.Start_train.clicked.connect(self.starting)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Start_train.setText(_translate("MainWindow", "start train"))
self.Stop_train.setText(_translate("MainWindow", "stop train"))
def starting(self):
self.stopThread = stopClass()
self.stopThread.start()
self.Stop_train.setEnabled(True)
self.Stop_train.clicked.connect(self.stopThread.exit)
self.Start_train.setEnabled(False)
In this case I do not see the need to use threads since it is enough to use QProcess that allows a simple handling of the execution of the script. On the other hand, do not modify the script generated by pyuic so my solution assumes that you must recreate that script that must be called gui.py:
import shlex
import sys
from PyQt5.QtCore import QObject, QProcess
from PyQt5.QtWidgets import QApplication, QMainWindow
from gui import Ui_MainWindow
class Manager(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._process = QProcess()
working_directory = r"c://tensorflow_1//models//research//object_detection"
self.process.setWorkingDirectory(working_directory)
self.process.setProgram(sys.executable)
args = shlex.split(
"train.py --logtostderr --train_dir=training/ --pipeline_config_path=training/faster_rcnn_inception_v2_pets.config"
)
self.process.setArguments(args)
#property
def process(self):
return self._process
def start(self):
if self.process.state() == QProcess.NotRunning:
self.process.start()
def stop(self):
if self.process.state() != QProcess.NotRunning:
self.process.kill()
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.manager = Manager()
self.Start_train.clicked.connect(self.manager.start)
self.Stop_train.clicked.connect(self.manager.stop)
self.manager.process.stateChanged.connect(self._handle_stateChanged)
def _handle_stateChanged(self, state):
self.Start_train.setEnabled(state != QProcess.Running)
self.Stop_train.setEnabled(state == QProcess.Running)
def main():
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

How to kill the QRunnable in PyQt5?

I have an app with two buttons start and end. The start button will start a thread, which runs the audio recording function. This function is written using sounddevice and soundfile libraries. The audio recording can take place for an arbitary duration and the user can stop anytime by pressing ctrl+c.
So, now I want to implement a function for the end button to stop the thread which started by pressing start button or the function can send ctrl+c signal to the thread. So, that the current recording will be stopped. I am not sure how to achieve this. Any help is appreciated.
The code consisting in two .py is as it follows:
audio_record.py
import os
import signal
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import time
import queue
from PyQt5 import QtCore, QtGui, QtWidgets
import soundfile as sf
import sounddevice as sd
import mythreading
class Ui_MainWindow(object):
def __init__(self):
self.threadpool = QThreadPool()
print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(280, 190, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton.clicked.connect(self.start_button_func)
self.pushButton_1 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_1.setGeometry(QtCore.QRect(380, 190, 75, 23))
self.pushButton_1.setObjectName("pushButton")
self.pushButton_1.clicked.connect(self.end_button_func)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Start"))
self.pushButton_1.setText(_translate("MainWindow", "End"))
def record(self):
self.pid = os.getpid()
self.q = queue.Queue()
self.s = sd.InputStream(samplerate=48000, channels=2, callback=self.callback)
try:
# Make sure the file is open before recording begins
with sf.SoundFile('check.wav', mode='x', samplerate=48000, channels=2, subtype="PCM_16") as file:
with self.s:
# 1 second silence before the recording begins
time.sleep(1)
print('START')
print('#' * 80)
print('press Ctrl+C to stop the recording')
while True:
file.write(self.q.get())
except OSError:
print('The file to be recorded already exists.')
sys.exit(1)
def callback(self, indata, frames, time, status):
"""
This function is called for each audio block from the record function.
"""
if status:
print(status, file=sys.stderr)
self.q.put(indata.copy())
def start_button_func(self):
self.worker = mythreading.Worker(self.record)
self.threadpool.start(self.worker)
def end_button_func(self):
print('how to stop?')
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_())
mythreading.py is as follows:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Worker(QRunnable):
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
self.fn = fn
#pyqtSlot()
def run(self):
self.fn()
You have to use a flag, in this case threading.Event() to indicate that the thread should no longer be executed. For the case of Ctrl + C you must use QShortcut
import os
import queue
from PyQt5 import QtCore, QtGui, QtWidgets
import soundfile as sf
import sounddevice as sd
import mythreading
import threading
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(280, 190, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton_1 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_1.setGeometry(QtCore.QRect(380, 190, 75, 23))
self.pushButton_1.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Start"))
self.pushButton_1.setText(_translate("MainWindow", "End"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.threadpool = QtCore.QThreadPool()
print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
self.pushButton.clicked.connect(self.start_button_func)
self.pushButton_1.clicked.connect(self.end_button_func)
self.event_stop = threading.Event()
QtWidgets.QShortcut("Ctrl+C", self, activated=self.end_button_func)
def record(self):
self.pid = os.getpid()
self.q = queue.Queue()
self.s = sd.InputStream(samplerate=48000, channels=2, callback=self.callback)
try:
# Make sure the file is open before recording begins
with sf.SoundFile('check.wav', mode='x', samplerate=48000, channels=2, subtype="PCM_16") as file:
with self.s:
# 1 second silence before the recording begins
QtCore.QThread.sleep(1)
print('START')
print('#' * 80)
print('press Ctrl+C to stop the recording')
while not self.event_stop.is_set():
file.write(self.q.get())
print("STOP")
except OSError:
print('The file to be recorded already exists.')
sys.exit(1)
def callback(self, indata, frames, time, status):
if status:
print(status, file=sys.stderr)
self.q.put(indata.copy())
#QtCore.pyqtSlot()
def start_button_func(self):
print("start")
self.worker = mythreading.Worker(self.record)
self.threadpool.start(self.worker)
#QtCore.pyqtSlot()
def end_button_func(self):
print('how to stop?')
self.event_stop.set()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Python PyQt5 Progress Bar is not progressing

so basically i have programs that are meant to show the progress of reading an excel file line by line in the background. So far i have the following code:
excelresult.py:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import Qt, QBasicTimer
import os, sys, xlrd, threading, time, pythoncom
import win32com.client
from time import sleep
from test import MyGlobals
class ExcelCheck(threading.Thread):
progPercent = 0
def __init__(self):
threading.Thread.__init__(self)
self.event = threading.Event()
def run(self):
pythoncom.CoInitialize()
try:
while not self.event.is_set():
excel = win32com.client.Dispatch("Excel.Application")
wb = excel.ActiveWorkbook
ws = wb.Worksheets("TC")
va_title = ws.Range(ws.Range('I7'), ws.Range('I700'))
i = 0
for r in va_title.Cells:
if r.Text != '':
i = i + 1
# print(r.Text)
# print(i)
# print(round(i / 178.0 * 100,0))
# rounding off
progPercent = round(i / 178.0 * 100.0)
MyGlobals.x=progPercent
print(progPercent)
return progPercent
except:
print('Excel is not executed')
# sleep(1)
# self.event.wait()
def stop(self):
self.event.set()
scm.py
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtCore import Qt, QBasicTimer
import os, sys, xlrd, win32com.client, xlwt, threading, time
from time import sleep
from ExcelResult import *
from test import MyGlobals
import threading
class Ui_MainWindow(object):
def __init__(self):
super().__init__()
self.btn_active = False
print('init_false')
def startBtnClicked(self):
self.btnStart.setText('start!')
self.btn_active = True
print(self.btn_active)
tmr = ExcelCheck()
tmr.start()
while(MyGlobals.x<=100):
#print (MyGlobals.x)
self.progressBar.setValue(MyGlobals.x)
# self.progressBar.minimum = 1
# self.progressBar.maximum = 100
# for progPercent in range(1, 101):
# self.progressBar.setValue(progPercent)
# time.sleep(1)
def exitBtnClicked(self):
# self.ExcelCheck()
self.btn_active = False
print(self.btn_active)
# os.system("taskkill /f /im Scm21.Client.exe")
# self.close()
# Stop the progress of python
self.sys.exit()
tmr = ExcelCheck()
tmr.stop()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(446, 207)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(40, 70, 381, 23))
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.btnStart = QtWidgets.QPushButton(self.centralwidget)
self.btnStart.setGeometry(QtCore.QRect(110, 110, 75, 23))
self.btnStart.setObjectName("btnStart")
self.btnStart.clicked.connect(self.startBtnClicked)
self.btnExit = QtWidgets.QPushButton(self.centralwidget)
self.btnExit.setGeometry(QtCore.QRect(260, 110, 75, 23))
self.btnExit.setObjectName("btnExit")
self.btnExit.clicked.connect(self.exitBtnClicked)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 446, 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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "SCM21"))
self.btnStart.setText(_translate("MainWindow", "Start"))
self.btnExit.setText(_translate("MainWindow", "Exit"))
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_())
and, test.py
class MyGlobals(object):
x = 0
So, i am able to get the value of the ProgPercent from the ExcelResult.py into the scm.py using the test.py but completely not aware how would i update the progressbar value.
I tried using a loop but it hangs the GUI.
Thanks.
Use Qthread:
import time
from PyQt5 import QtCore
from PyQt5 import QtWidgets
class ExcelCheck(QtCore.QThread):
updated = QtCore.pyqtSignal(int)
running = False
def __init__(self, parent=None):
super(ExcelCheck, self).__init__(parent)
self.progPercent = 0
self.running = True
def run(self):
while self.running:
self.progPercent += 1
self.progPercent %= 100
self.updated.emit(int(self.progPercent))
time.sleep(0.1)
def stop(self):
self.running = False
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.setupUi(self)
self.btn_active = False
def startBtnClicked(self):
self.btnStart.setText('start!')
self.btn_active = True
self.tmr = ExcelCheck(self)
self.tmr.updated.connect(self.updateValue)
self.tmr.start()
def updateValue(self, data):
self.progressBar.setValue(data)
def exitBtnClicked(self):
# self.ExcelCheck()
self.btn_active = False
self.tmr.stop()
self.sys.exit()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(446, 207)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(40, 70, 381, 23))
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.btnStart = QtWidgets.QPushButton(self.centralwidget)
self.btnStart.setGeometry(QtCore.QRect(110, 110, 75, 23))
self.btnStart.setObjectName("btnStart")
self.btnStart.clicked.connect(self.startBtnClicked)
self.btnExit = QtWidgets.QPushButton(self.centralwidget)
self.btnExit.setGeometry(QtCore.QRect(260, 110, 75, 23))
self.btnExit.setObjectName("btnExit")
self.btnExit.clicked.connect(self.exitBtnClicked)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 446, 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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "SCM21"))
self.btnStart.setText(_translate("MainWindow", "Start"))
self.btnExit.setText(_translate("MainWindow", "Exit"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Categories

Resources