Keeping track of a button status inside a thread (PyQt5) - multithreading

I created this simple GUI that displays a conuter on a text box. I am using workers and threads (this is just a simplified program I have other threads). I want to be able to check the status of the push button inside the label update thread. for example if the user clicked, then the counter will increment by 5 instead of 1 (for this iteration only), basically I want to keep an eye on this button's status all the time.
here is my code for the counter, how do I add the button check functionality to it?
Edit: I've updated the code using signals and slots to print 'hi' as a start, yet I do not get any output when I run it.
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
import os
import cv2
import numpy as np
import time
############################# Telemtry widgets update ##########################
class DISPLAY(QObject):
acc1_val = pyqtSignal(int)
finished = pyqtSignal()
def run(self):
global cntr
cntr = 0
self.inst = Ui_MainWindow()
self.inst.flag.connect(self.update)
print('connected')
while 1:
cntr = cntr +1
time.sleep(1)
self.acc1_val.emit(cntr)
if(cntr > 50):
cntr = 0
self.finished.emit()
#pyqtSlot()
def update(self,flag):
print('hi')
print(flag)
############################ GUI #######################################
class Ui_MainWindow(QObject):
flag = pyqtSignal(int)
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(500, 500)
MainWindow.setFocusPolicy(QtCore.Qt.NoFocus)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.Title = QtWidgets.QLabel(self.centralwidget)
self.Title.setGeometry(QtCore.QRect(30, 10, 421, 71))
font = QtGui.QFont()
font.setPointSize(24)
font.setBold(True)
font.setWeight(75)
self.Title.setFont(font)
self.Title.setObjectName("Title")
self.ACC1_X = QtWidgets.QLineEdit(self.centralwidget)
self.ACC1_X.setGeometry(QtCore.QRect(300, 300, 41, 31))
self.ACC1_X.setObjectName("ACC1_X")
self.btn = QtWidgets.QPushButton(self.centralwidget)
self.btn.setGeometry(QtCore.QRect(100, 100, 101, 41))
font = QtGui.QFont()
font.setPointSize(13)
self.btn.setFont(font)
self.btn.setObjectName("Release_btn")
self.btn.clicked.connect(self.release_callback)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1920, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
###################### Display thread ######################
self.thread1 = QThread()
self.worker1 = DISPLAY()
self.worker1.moveToThread(self.thread1)
self.thread1.started.connect(self.worker1.run)
self.worker1.acc1_val.connect(self.Label_update)
self.thread1.finished.connect(self.worker1.deleteLater)
self.thread1.start()
def release_callback(self,flag):
self.x = 1
print(flag)
self.flag.emit(True)
def Label_update(self,acc_val):
self.ACC1_X.setText(str(acc_val))
#print(str(acc_val))
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.btn.setText(_translate("MainWindow", "click me"))
self.Title.setText(_translate("MainWindow", "TEST"))
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_())

Related

PyQt5 calling gui from pyuic5 converted file or uic.loadUi

Hi I am new to python (up to lecture 2 and half of MIT 6001 Introduction to Computer Science and Programming in Python) nevetheless I started playing with Gtk & Glade and PyQt5 and Designer.
following https://stackoverflow.com/a/54081597/9877065 I used pyuic5 to convert my prova.ui, Designer generated window and imported in the code below:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from prova1 import Ui_MainWindow
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ButtonQ.clicked.connect(self.QPushButtonQPressed)
self.ButtonA.clicked.connect(self.QPushButtonAPressed)
def QPushButtonQPressed(self):
# This is executed when the button is pressed
print('pppppppp exit from QQQQQQQQQQQQQQQQQQQQQQQQQQQQQ')
sys.exit()
def QPushButtonAPressed(self):
# This is executed when the button is pressed
print('exit from AAAAAAAAAAAAAAAAAAAAAAA')
sys.exit()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
but when I run it in terminal I got a :
File "./main.py", line 80, in <module>
w = MyWindow()
File "./main.py", line 38, in __init__
self.ButtonQ.clicked.connect(self.QPushButtonQPressed)
AttributeError: 'MyWindow' object has no attribute 'ButtonQ'
error !!!!
while using loaduic like:
import sys
from PyQt5 import QtWidgets, uic
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
uic.loadUi('prova1.ui', self)
self.ButtonQ.clicked.connect(self.QPushButtonQPressed)
self.ButtonA.clicked.connect(self.QPushButtonAPressed)
self.show()
def QPushButtonQPressed(self):
# This is executed when the button is pressed
print('pppppppp exit from QQQQQQQQQQQQQQQQQQQQQQQQQQQQQ')
sys.exit()
def QPushButtonAPressed(self):
# This is executed when the button is pressed
print('exit from AAAAAAAAAAAAAAAAAAAAAAA')
sys.exit()
app = QtWidgets.QApplication(sys.argv)
window = Ui()
app.exec_()
the program works as expected, that is show the window gui and exit if A or Quit button is pressed
as per the prova1.ui file that converted with pyuic5 gives, prova1.py:
# Form implementation generated from reading ui file 'prova1.ui'
#
# Created by: PyQt5 UI code generator 5.12.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(256, 351)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setEnabled(True)
self.centralwidget.setObjectName("centralwidget")
self.gridLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 0, 221, 261))
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.ButtonA = QtWidgets.QPushButton(self.gridLayoutWidget)
font = QtGui.QFont()
font.setFamily("Abyssinica SIL")
font.setItalic(True)
font.setUnderline(True)
font.setStrikeOut(False)
font.setKerning(False)
self.ButtonA.setFont(font)
self.ButtonA.setCheckable(True)
self.ButtonA.setAutoDefault(False)
self.ButtonA.setDefault(False)
self.ButtonA.setObjectName("ButtonA")
self.gridLayout.addWidget(self.ButtonA, 0, 0, 1, 1)
self.C = QtWidgets.QPushButton(self.gridLayoutWidget)
self.C.setObjectName("C")
self.gridLayout.addWidget(self.C, 2, 0, 1, 1)
self.B = QtWidgets.QPushButton(self.gridLayoutWidget)
self.B.setObjectName("B")
self.gridLayout.addWidget(self.B, 1, 0, 1, 1)
self.ButtonQ = QtWidgets.QPushButton(self.gridLayoutWidget)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.ButtonQ.setFont(font)
self.ButtonQ.setCheckable(True)
self.ButtonQ.setAutoDefault(False)
self.ButtonQ.setDefault(False)
self.ButtonQ.setObjectName("ButtonQ")
self.gridLayout.addWidget(self.ButtonQ, 3, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 256, 29))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.statusbar.setFont(font)
self.statusbar.setAutoFillBackground(True)
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.ButtonA.setText(_translate("MainWindow", "A"))
self.C.setText(_translate("MainWindow", "C"))
self.B.setText(_translate("MainWindow", "B"))
self.ButtonQ.setText(_translate("MainWindow", "Q quit"))
I am sure the error is somehow related to the class definitions but cannot really grasp it ? Any help ?
Heike solved it
In the first version of MyWindow, ButonA and ButtonQ are attributes of self.ui, not of self itself, so you need to use somthing like self.ui.ButtonA.clicked.connect(...), etc.

How get text from QTextEdit in Pyqt5? [duplicate]

This question already has an answer here:
Get text from qtextedit and assign it to a variable
(1 answer)
Closed 2 years ago.
I need get text from QTextEdit, but have such trouble: Traceback (most recent call last):
File "main.py", line 28, in otpravit_naz
textboxValue = self.textEdit.text()
AttributeError: 'MyWin' object has no attribute 'textEdit'
This is my code(main.py):
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from test import *
import socket
sock = socket.socket()
class MyWin(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.otpravit.clicked.connect(self.otpravit_naz)
def mbox(self, body, title='Error'):
dialog = QMessageBox(QMessageBox.Information, title, body)
dialog.exec_()
def otpravit_naz(self):
print("1")
textboxValue = self.textEdit.text()
print(textboxValue)
#sock.connect(('192.168.1.16', 9090))
sock.connect(("192.168.1.45", 9090))
sock.send(b'textboxValue')
sock.close()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myapp = MyWin()
myapp.show()
sys.exit(app.exec_())
And ui form:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(517, 283)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(60, 20, 421, 201))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(23)
self.verticalLayout.setObjectName("verticalLayout")
self.textEdit = QtWidgets.QTextEdit(self.verticalLayoutWidget)
self.textEdit.setObjectName("textEdit")
self.verticalLayout.addWidget(self.textEdit)
self.label = QtWidgets.QLabel(self.verticalLayoutWidget)
self.label.setLineWidth(0)
self.label.setMidLineWidth(0)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.list = QtWidgets.QComboBox(self.verticalLayoutWidget)
self.list.setObjectName("list")
self.list.addItem("")
self.list.addItem("")
self.list.addItem("")
self.verticalLayout.addWidget(self.list)
self.otpravit = QtWidgets.QPushButton(self.verticalLayoutWidget)
self.otpravit.setObjectName("otpravit")
self.verticalLayout.addWidget(self.otpravit)
self.verticalLayout.setStretch(0, 20)
self.verticalLayout.setStretch(1, 20)
self.verticalLayout.setStretch(2, 20)
self.verticalLayout.setStretch(3, 20)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 517, 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.label.setText(_translate("MainWindow", "Предмет:"))
self.list.setItemText(0, _translate("MainWindow", "Русский"))
self.list.setItemText(1, _translate("MainWindow", "Литература"))
self.list.setItemText(2, _translate("MainWindow", "Английский"))
self.otpravit.setText(_translate("MainWindow", "Отправить"))
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_())
If it very stupid troble, pls don't kick me
You're "installing" the GUI on the self.ui object, so every widget that is on the ui is actually accessible as self.ui.someWidget.
Also, QTextEdit doesn't have a text() property, but toPlainText():
def otpravit_naz(self):
print("1")
textboxValue = self.ui.textEdit.toPlainText()
print(textboxValue)
I suggest you to never edit the files generated with pyuic, but always use them as imported modules; read more on using Designer; also, be careful to set the main layout on the central widget, not on its children, and add everything to that layout, otherwise the children widgets could be hidden whenever the window is resized.

Pyqt5 QFileDialog not working in my program for Getting Directories

I have This Qt MainWindow Shown Below:
I want my Browse button to Open a Dialog box for selecting Specific Directory.
I Went through the various post on Stack Overflow, I tried implementing the solution in the post, but It's not working for me.
Here is my Code :
from PyQt5 import QtCore, QtGui, QtWidgets
import os
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.gridLayout_2 = QtWidgets.QGridLayout()
self.gridLayout_2.setObjectName("gridLayout_2")
self.start_button = QtWidgets.QPushButton(self.centralwidget)
self.start_button.setAutoFillBackground(False)
self.start_button.setAutoDefault(False)
self.start_button.setDefault(False)
self.start_button.setFlat(False)
self.start_button.setObjectName("start_button")
self.start_button.clicked.connect(lambda: self.start_button_click())
self.gridLayout_2.addWidget(self.start_button, 0, 0, 1, 1)
self.Br_button = QtWidgets.QPushButton(self.centralwidget)
self.Br_button.setObjectName("Br_button")
self.Br_button.clicked.connect(lambda: self.browse_button())
self.gridLayout_2.addWidget(self.Br_button, 2, 0, 1, 1)
self.label = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
font.setWeight(75)
self.label.setFont(font)
self.label.setObjectName("label")
self.gridLayout_2.addWidget(self.label, 2, 1, 1, 1, QtCore.Qt.AlignHCenter)
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(0)
self.tableWidget.setRowCount(0)
self.gridLayout_2.addWidget(self.tableWidget, 3, 0, 1, 2)
self.gridLayout.addLayout(self.gridLayout_2, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.start_button.setToolTip(_translate("MainWindow", "Start The Program"))
self.start_button.setText(_translate("MainWindow", "Start"))
self.Br_button.setToolTip(_translate("MainWindow", "Browse the File Location to Watch on"))
self.Br_button.setText(_translate("MainWindow", "Browse"))
def start_button_click(self):
self.label.setText("Hello")
def browse_button(self):
fileName = QtWidgets.QFileDialog.getExistingDirectory(QtWidgets.QFileDialog,None,"Open Directory",os.getcwd(), QtWidgets.QFileDialog.ShowDirsOnly)
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_())
When I Click on the Browse button it closes the Application abruptly after few seconds and I am Getting This Error Shown below:
Try it:
import sys
import os
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Form(QMainWindow):
def __init__(self,parent=None):
super().__init__(parent)
self.plainTextEdit = QPlainTextEdit()
self.plainTextEdit.setFont(QFont('Arial', 11))
openDirButton = QPushButton("Open Directory")
openDirButton.clicked.connect(self.browse_button)
layoutV = QVBoxLayout()
layoutV.addWidget(openDirButton)
layoutH = QHBoxLayout()
layoutH.addLayout(layoutV)
layoutH.addWidget(self.plainTextEdit)
centerWidget = QWidget()
centerWidget.setLayout(layoutH)
self.setCentralWidget(centerWidget)
def browse_button(self):
fileName = QFileDialog.getExistingDirectory(
#QtWidgets.QFileDialog, # ???
None,
"Open Directory",
os.getcwd(),
QFileDialog.ShowDirsOnly)
self.plainTextEdit.appendHtml("<br>Chose a folder: <b>{}</b>".format(fileName))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Form()
ex.resize(740,480)
ex.setWindowTitle("PyQt5-QFileDialog")
ex.show()
sys.exit(app.exec_())

Embed a Matplotlib graphic into a widget - PyQt5

I would like to embed a graphic from Matplotlib into an existing GUI containing a Widget and a PushButton developed from QtDesigner and PyQt5. I can embed the graphic but can't resize the graphic to take all space available/needed into the Widget.
Front end code:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(595, 393)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setMaximumSize(QtCore.QSize(100, 16777215))
self.pushButton.setObjectName("pushButton")
self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setMinimumSize(QtCore.QSize(0, 200))
self.widget.setStyleSheet("background-color: rgb(255, 255, 255);")
self.widget.setObjectName("widget")
self.gridLayout.addWidget(self.widget, 0, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 595, 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", "PushButton"))
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_())
Back end code:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QSizePolicy
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from front_end import Ui_MainWindow
class Graph_init(FigureCanvas):
def __init__(self, parent=None):
fig = Figure()
self.axes = fig.add_subplot(111)
self.compute_initial_figure()
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
class Graph_populate(Graph_init):
def compute_initial_figure(self):
x = [2000,2001,2002,2003,2004]
y = [10,20,30,40,50]
self.axes.plot(x, y)
class GUI(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(GUI, self).__init__(parent)
self.setupUi(self)
self.sc = Graph_populate(self.widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
prog = GUI()
prog.showMaximized()
sys.exit(app.exec_())
Thank you
In PyQt you would normally add a widget to your application by adding it to a Layout. In the code you seem to have forgotten to do that step.
So if self.gridLayout is the layout you want your FigureCanvas to reside in, you would need to add the latter to the former as
self.gridLayout.addWidget(self.sc, 0, 1, 1, 1)
The role of self.widget on the other hand is not really clear here and you may probably remove it. The self.centralwidget can take the role of the parent, if it is really needed,
self.sc = Graph_populate(self.centralwidget)

PyQt5 crashing with threading and progress bar

I have a progress bar that is controlled by a start stop button. The progress bar fills up using a thread. However, whenever I run the program it crashes at random times (different time each time program is run).
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.fill_thread = None
Thread for filling progress bar. I have tried using both time.sleep and QThread.msleep.
def fill_bar(self):
while not self.stop_fill and self.completed < 100:
self.completed += 0.5
QThread.msleep(100)
self.chargeprog.setValue(self.completed)
Buttons that alternate between start and stop that call the thread
def charging(self):
if self.chargebtn.text() == 'Start':
self.chargebtn.setText('Stop')
self.chargebtn.setStyleSheet('background-color:red')
self.fill_thread = threading.Thread(target=self.fill_bar)
self.stop_fill = False
self.fill_thread.start()
else:
self.stop_fill = True
self.fill_thread.join()
self.chargebtn.setText('Start')
self.chargebtn.setStyleSheet('background-color:limegreen')
window.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'window.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(180, 150, 118, 23))
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName("progressBar")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(330, 150, 75, 23))
self.pushButton.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 18))
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", "PushButton"))
test.py
import sys
from PyQt5.QtWidgets import QApplication,QMainWindow
from PyQt5.QtCore import QThread,pyqtSignal
from window import Ui_MainWindow
class CThread(QThread):
valueChanged = pyqtSignal([int])
def __init__(self,value):
super().__init__()
self.stop_fill = False
self.completed = value
def run(self):
while not self.stop_fill and self.completed < 100:
self.completed += 0.5
self.sleep(1)
self.valueChanged.emit(self.completed)
class Window(QMainWindow,Ui_MainWindow):
def __init__(self):
super().__init__()
super().setupUi(self)
self.fill_thread = None
self.pushButton.clicked.connect(self.charging)
def charging(self):
if self.pushButton.text() == 'Start':
self.pushButton.setText('Stop')
self.pushButton.setStyleSheet('background-color:red')
print(self.progressBar.value())
self.fill_thread = CThread(self.progressBar.value())
self.fill_thread.valueChanged.connect(self.progressBar.setValue)
self.fill_thread.start()
else:
if self.fill_thread != None:
self.fill_thread.disconnect() # event unbind
self.fill_thread.stop_fill = True
self.fill_thread.wait()
self.fill_thread.quit()
print(self.fill_thread.isRunning())
self.pushButton.setText('Start')
self.pushButton.setStyleSheet('background-color:limegreen')
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
If you want communicate between multi-threads, you can try signal/slots.

Resources