Search code examples
pythonpyqtpyqt5qthread

Python PyQt5 threading don't work


i want to create a progress bar showing(as busy) until the code of a button ends .My target is to show it when button(connected to function) pressed ,stay visible as code runs , and hide it when the function connected to the button ends.This task is done partially but my progress bar setVisible(True) waits until code ends and they show. My code is here:

from ui import Ui_MainWindow
from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport
from PyQt5.QtWidgets import QDialog,QWidget,QApplication, QInputDialog, QLineEdit, QFileDialog
from PyQt5.QtGui import QIcon

class ProgressThread(QtCore.QThread):
    job_done = QtCore.pyqtSignal('QString')
    def __init__(self, parent=None):
        super(ProgressThread, self).__init__(parent)
        self.gui_bar = None
    def do_work(self):
        self.job_done.emit(self.gui_bar)

    def run(self):
        self.do_work()

class mainProgram(QtWidgets.QMainWindow, Ui_MainWindow):                   #main window
    def __init__(self, parent=None):
        super(mainProgram, self).__init__(parent)
        self.setupUi(self)

        self.progress_thread = ProgressThread()
        self.progress_thread.job_done.connect(self.on_job_start)
        self.create_ui()

        self.B_aerodrome_data.clicked.connect(self.start_thread)

        self.B_aerodrome_data.clicked.connect(self.aerodrome_data)


    def aerodrome_data(self):          #def i want with start show progress bar
        #here show progressBar(self.progress.setVisible(True) and update gui)
        #do many staffs of code here that takes time

        #here hide progress bar and update gui 

    def start_thread(self):
        self.progress_thread.gui_bar = self.progress.setVisible(False)
        self.progress_thread.start()

    def on_job_done(self):
        print("Generated string : ")
        self.progress.setVisible(False)


    def on_job_start(self):
        print("aaaaaaaaaa")
        self.progress.setRange(0,0)
        self.progress.setVisible(True)
    def create_ui(self):
        self.progress = QtWidgets.QProgressBar(self)
        self.progress.setVisible(False)
        self.progress.setGeometry(200, 205, 250, 20)
        self.progress.setRange(0, 0)
        self.progress.setObjectName("progress")
        #self.button.clicked.connect(self.start_thread)
        layout = QtWidgets.QVBoxLayout(self)
        #layout.addWidget(self.button)

if __name__ == "__main__":                       
    app = QtWidgets.QApplication(sys.argv)
    nextGui = mainProgram()
    nextGui.showMaximized()
    sys.exit(app.exec_()) 

The Ui_Mainwindow is here:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1371, 924)
        MainWindow.setAcceptDrops(True)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("images/356.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        MainWindow.setAutoFillBackground(True)
        MainWindow.setDocumentMode(True)
        self.centralWidget = QtWidgets.QWidget(MainWindow)
        self.centralWidget.setObjectName("centralWidget")
        self.L_adinput = QtWidgets.QLabel(self.centralWidget)
        self.L_adinput.setGeometry(QtCore.QRect(30, 70, 141, 31))
        self.L_adinput.setObjectName("L_adinput")
        # self.progress = QtWidgets.QProgressBar(self)
        # self.progress.setGeometry(200, 205, 250, 20)
        # self.progress.setProperty("value", 0)
        # self.progress.setObjectName("progress")
        self.L_progress = QtWidgets.QLabel(self.centralWidget)
        self.L_progress.setGeometry(QtCore.QRect(150, 200, 141, 31))
        self.L_progress.setObjectName("L_progress")
        self.B_aerodrome_data = QtWidgets.QPushButton(self.centralWidget)
        self.B_aerodrome_data.setGeometry(QtCore.QRect(670, 100, 271, 41))
        self.B_aerodrome_data.setObjectName("B_aerodrome_data")
        self.T_aerodrome_ouput = QtWidgets.QTextEdit(self.centralWidget)
        self.T_aerodrome_ouput.setGeometry(QtCore.QRect(30, 230, 561, 371))
        self.T_aerodrome_ouput.setReadOnly(True)
        self.T_aerodrome_ouput.setObjectName("T_aerodrome_ouput")
        self.B_alternates = QtWidgets.QPushButton(self.centralWidget)
        self.B_alternates.setGeometry(QtCore.QRect(670, 160, 271, 41))
        self.B_alternates.setObjectName("B_alternates")
        self.B_weather = QtWidgets.QPushButton(self.centralWidget)
        self.B_weather.setGeometry(QtCore.QRect(670, 220, 271, 41))
        self.B_weather.setObjectName("B_weather")
        self.B_fuel = QtWidgets.QPushButton(self.centralWidget)
        self.B_fuel.setEnabled(True)
        self.B_fuel.setGeometry(QtCore.QRect(1050, 100, 271, 41))
        self.B_fuel.setObjectName("B_fuel")
        self.set_path1 = QtWidgets.QPushButton(self.centralWidget)
        self.set_path1.setEnabled(True)
        self.set_path1.setGeometry(QtCore.QRect(1100, 160, 101, 31))
        self.set_path1.setObjectName("set_path1")
        self.set_path2 = QtWidgets.QPushButton(self.centralWidget)
        self.set_path2.setEnabled(True)
        self.set_path2.setGeometry(QtCore.QRect(1100, 210, 101, 31))
        self.set_path2.setObjectName("set_path2")
        self.set_path3 = QtWidgets.QPushButton(self.centralWidget)
        self.set_path3.setEnabled(True)
        self.set_path3.setGeometry(QtCore.QRect(1100, 260, 101, 31))
        self.set_path3.setObjectName("set_path3")
        self.set_path4 = QtWidgets.QPushButton(self.centralWidget)
        self.set_path4.setEnabled(True)
        self.set_path4.setGeometry(QtCore.QRect(1100, 310, 101, 31))
        self.set_path4.setObjectName("set_path4")
        self.set_path5 = QtWidgets.QPushButton(self.centralWidget)
        self.set_path5.setEnabled(True)
        self.set_path5.setGeometry(QtCore.QRect(1100, 360, 101, 31))
        self.set_path5.setObjectName("set_path5")
        self.tool1 = QtWidgets.QToolButton(self.centralWidget)
        self.tool1.setGeometry(QtCore.QRect(1240, 170, 25, 19))
        self.tool1.setObjectName("tool1")
        self.tool2 = QtWidgets.QToolButton(self.centralWidget)
        self.tool2.setGeometry(QtCore.QRect(1240, 220, 25, 20))
        self.tool2.setObjectName("tool2")
        self.tool3 = QtWidgets.QToolButton(self.centralWidget)
        self.tool3.setGeometry(QtCore.QRect(1240, 270, 25, 19))
        self.tool3.setObjectName("tool3")
        self.tool4 = QtWidgets.QToolButton(self.centralWidget)
        self.tool4.setGeometry(QtCore.QRect(1240, 320, 25, 19))
        self.tool4.setObjectName("tool4")
        self.tool1x = QtWidgets.QToolButton(self.centralWidget)
        self.tool1x.setGeometry(QtCore.QRect(1280, 220, 25, 19))
        self.tool1x.setObjectName("tool1x")
        self.tool2x = QtWidgets.QToolButton(self.centralWidget)
        self.tool2x.setGeometry(QtCore.QRect(1280, 270, 25, 19))
        self.tool2x.setObjectName("tool2x")
        self.tool3x = QtWidgets.QToolButton(self.centralWidget)
        self.tool3x.setGeometry(QtCore.QRect(1280, 320, 25, 19))
        self.tool3x.setObjectName("tool3x")
        self.tool4x = QtWidgets.QToolButton(self.centralWidget)
        self.tool4x.setGeometry(QtCore.QRect(1280, 370, 25, 19))
        self.tool4x.setObjectName("tool4x")
        self.line = QtWidgets.QFrame(self.centralWidget)
        self.line.setGeometry(QtCore.QRect(990, -50, 20, 851))
        self.line.setFrameShape(QtWidgets.QFrame.VLine)
        self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.line.setObjectName("line")
        self.T_aerodromes_input = QtWidgets.QTextEdit(self.centralWidget)
        self.T_aerodromes_input.setGeometry(QtCore.QRect(30, 100, 331, 71))
        self.T_aerodromes_input.setStyleSheet("font: 10pt \"MS Shell Dlg 2\";")
        self.T_aerodromes_input.setObjectName("T_aerodromes_input")
        self.label = QtWidgets.QLabel(self.centralWidget)
        self.label.setGeometry(QtCore.QRect(30, 200, 161, 31))
        self.label.setObjectName("label")
        self.B_print = QtWidgets.QPushButton(self.centralWidget)
        self.B_print.setGeometry(QtCore.QRect(530, 230, 41, 31))
        self.B_print.setText("")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap("images/printer.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.B_print.setIcon(icon1)
        self.B_print.setIconSize(QtCore.QSize(41, 31))
        self.B_print.setObjectName("B_print")
        self.B_clear = QtWidgets.QPushButton(self.centralWidget)
        self.B_clear.setGeometry(QtCore.QRect(490, 230, 41, 31))
        self.B_clear.setText("")
        self.label_2 = QtWidgets.QLabel(self.centralWidget)
        self.label_2.setGeometry(QtCore.QRect(670, 30, 271, 41))
        self.label_2.setStyleSheet("font: 75 11pt \"MS Shell Dlg 2\";")
        self.label_2.setAlignment(QtCore.Qt.AlignCenter)
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(self.centralWidget)
        self.label_3.setGeometry(QtCore.QRect(1050, 30, 271, 41))
        self.label_3.setStyleSheet("font: 75 11pt \"MS Shell Dlg 2\";")
        self.label_3.setAlignment(QtCore.Qt.AlignCenter)
        self.label_3.setObjectName("label_3")
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap("images/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.B_clear.setIcon(icon2)
        self.B_clear.setIconSize(QtCore.QSize(41, 31))
        self.B_clear.setObjectName("B_clear")
        self.L_adinput.raise_()
        self.L_progress.raise_()
        self.B_aerodrome_data.raise_()
        self.T_aerodrome_ouput.raise_()
        self.B_alternates.raise_()
        self.B_weather.raise_()
        self.B_fuel.raise_()
        self.set_path2.raise_()
        self.set_path3.raise_()
        self.set_path4.raise_()
        self.set_path5.raise_()
        self.tool1.raise_()
        self.set_path1.raise_()
        self.tool2.raise_()
        self.tool3.raise_()
        self.tool4.raise_()
        self.tool1x.raise_()
        self.tool2x.raise_()
        self.tool3x.raise_()
        self.tool4x.raise_()
        self.line.raise_()
        self.T_aerodromes_input.raise_()
        self.label.raise_()
        self.B_print.raise_()
        self.B_clear.raise_()
        self.label_2.raise_()
        self.label_3.raise_()
        MainWindow.setCentralWidget(self.centralWidget)

        self.retranslateUi(MainWindow)
        self.tool1.clicked.connect(self.tool2.show)
        self.tool1.clicked.connect(self.set_path2.show)
        self.tool2.clicked.connect(self.tool3.show)
        self.tool3.clicked.connect(self.tool4.show)
        self.tool3.clicked.connect(self.set_path4.show)
        self.tool4.clicked.connect(self.set_path5.show)
        self.tool2.clicked.connect(self.set_path3.show)
        self.tool4x.clicked.connect(self.set_path5.hide)
        self.tool3x.clicked.connect(self.tool4.hide)
        self.tool3x.clicked.connect(self.set_path4.hide)
        self.tool2x.clicked.connect(self.tool3.hide)
        self.tool2x.clicked.connect(self.set_path3.hide)
        self.tool1x.clicked.connect(self.tool2.hide)
        self.tool1x.clicked.connect(self.set_path2.hide)
        self.tool4x.clicked.connect(self.tool4x.hide)
        self.tool3x.clicked.connect(self.tool3x.hide)
        self.tool2x.clicked.connect(self.tool2x.hide)
        self.tool1x.clicked.connect(self.tool1x.hide)
        self.tool1.clicked.connect(self.tool1x.show)
        self.tool2.clicked.connect(self.tool2x.show)
        self.tool3.clicked.connect(self.tool3x.show)
        self.tool4.clicked.connect(self.tool4x.show)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Planner"))
        self.L_adinput.setText(_translate("MainWindow", "ICAO LOCATORS"))
        self.L_progress.setText(_translate("MainWindow", "Progress"))
        self.B_aerodrome_data.setText(_translate("MainWindow", "AERODROME DATA"))
        # self.T_aerodrome_ouput.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
# "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
# "p, li { white-space: pre-wrap; }\n"
# "</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8.25pt; font-weight:400; font-style:normal;\">\n"
# "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p></body></html>"))
        self.B_alternates.setText(_translate("MainWindow", "ALTERNATES XLSX"))
        self.B_weather.setText(_translate("MainWindow", "WEATHER BRIEFING"))
        self.B_fuel.setText(_translate("MainWindow", "FUEL XLSX"))
        self.set_path1.setText(_translate("MainWindow", "SET FORM"))
        self.set_path2.setText(_translate("MainWindow", "SET FORM"))
        self.set_path3.setText(_translate("MainWindow", "SET FORM"))
        self.set_path4.setText(_translate("MainWindow", "SET FORM"))
        self.set_path5.setText(_translate("MainWindow", "SET FORM"))
        self.tool1.setText(_translate("MainWindow", "..."))
        self.tool2.setText(_translate("MainWindow", "..."))
        self.tool3.setText(_translate("MainWindow", "..."))
        self.tool4.setText(_translate("MainWindow", "..."))
        self.tool1x.setText(_translate("MainWindow", "X"))
        self.tool2x.setText(_translate("MainWindow", "X"))
        self.tool3x.setText(_translate("MainWindow", "X"))
        self.tool4x.setText(_translate("MainWindow", "X"))
        self.T_aerodromes_input.setPlaceholderText(_translate("MainWindow", "Set 4 character ICAO Locator here , divided by spaces..."))
        self.label.setText(_translate("MainWindow", "OUTPUT"))
        self.label_2.setText(_translate("MainWindow", "GENERAL"))
        self.label_3.setText(_translate("MainWindow", "FUEL"))

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_())

Solution

  • In your case I see that you have created functions unnecessarily, I have eliminated some. According to what you tell me, it is not necessary for the signal to carry information, so I will create a signal without parameters. the slot connected to the button must make visible the QProgressBar and start the thread, and the signal job_done must connect with the method that hides the QProgressBar, in the following example use QThread::sleep() to emulate some processing.

    class ProgressThread(QtCore.QThread):
        job_done = QtCore.pyqtSignal()
    
        def __init__(self, parent=None):
            super(ProgressThread, self).__init__(parent)
    
        def do_work(self):
            QtCore.QThread.sleep(2) # emulate processing
            self.job_done.emit()
    
        def run(self):
            self.do_work()
    
    
    class mainProgram(QtWidgets.QMainWindow, Ui_MainWindow):  # main window
        def __init__(self, parent=None):
            super(mainProgram, self).__init__(parent)
            self.setupUi(self)
    
            self.progress_thread = ProgressThread()
            self.progress_thread.job_done.connect(self.on_job_done)
            self.create_ui()
            self.B_aerodrome_data.clicked.connect(self.aerodrome_data)
    
        def aerodrome_data(self):
            self.start_thread()
    
        def start_thread(self):
            self.progress.setVisible(True)
            self.progress_thread.start()
    
        def on_job_done(self):
            print("Generated string : ")
            self.progress.setVisible(False)
    
        def create_ui(self):
            [...]