2

I have a pyqt GUI and a method[BigramClassification()]which causes the GUI to hang for several seconds. Therefore, i figured out threading need to be used. So after reading several tutorials i came up with the following code.

import sys,os

from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QThread
import time

class MyForm(QtGui.QMainWindow):

    def __init__(self, parent=None):

        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.lblHistory.setPixmap(QtGui.QPixmap(os.getcwd() + "/historygraph.png"))

        self.workerThread=WorkingThread()
        self.ui.pushButton.clicked.connect(self.generateDetails)
        self.ui.btnsubmitsettings.clicked.connect(self.addDetails)



    def generateDetails(self):
        self.workerThread.start()
        self.ui.lblHistory.setPixmap(QtGui.QPixmap(os.getcwd() + "/historygraph.png"))
        self.addPiechart()
        self.addWordCloud()
        self.summaryText()


    def addPiechart(self):

        print ("Added")

    def addWordCloud(self):

        print ("Added")

    def addDetails(self):


    def summaryText(self):

        print("Added")

class WorkingThread(QThread):
    def __init__(self, parent=None):
        super(self.__class__, self).__init__(parent)

    def run(self):
        BigramsClassifier()

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    myapp = MyForm()
    myapp.show()
    sys.exit(app.exec_())

The problem i have is when i run this and click on pushButton the thread starts but also executes the methods after the start() as seen in def generateDetails(self): I need to prepare this code so that the methods in def generateDetails(self): executes after the thread is done executing with the heavy method BigramClassification()execution.

Summary How can i stop the auto execution of the methods in def generateDetails(self): but only after the method BigramClassification() is completed.

EDIT This error is thrown up when i try to close the GUI.

enter image description here

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
rando
  • 67
  • 6

1 Answers1

3

Connect a slot to the thread's finished signal which can performs other actions once the long-running task is completed:

class MyForm(QtGui.QMainWindow):    
    def __init__(self, parent=None):
        ...
        self.workerThread = WorkingThread()
        self.workerThread.finished.connect(self.doOtherStuff)
        ...

    def generateDetails(self):
        if not self.workerThread.isRunning():
            self.workerThread.start()

    def doOtherStuff(self):
        self.ui.lblHistory.setPixmap(QtGui.QPixmap(os.getcwd() + "/historygraph.png"))
        self.addPiechart()
        self.addWordCloud()
        self.summaryText()
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • 1
    Your solution worked like a charm, was stuck in this problem for the last two day. Anyhow once i close my GUI i get a RuntimeError thrown saying 'main thread is not in main loop' i am using QT designer not Tkinter. Without any of the threading parts the GUI does not throw such error on closing only hangs for several seconds – rando Oct 18 '17 at 20:43
  • @rando. Are you running this in IDLE, or something? That error has obviously got nothing to do with PyQt. Try running your script in a command window using `python.exe`. Ideally, your program should either wait for the thread to finish (or terminate it in some way) before it closes down. – ekhumoro Oct 18 '17 at 21:43
  • No, i am running it using Pycharm – rando Oct 18 '17 at 22:03
  • from what i found out in https://stackoverflow.com/a/44598715/8373304 using queues may solve the issue. Can you please guide me on how to use Queues for the threads? – rando Oct 18 '17 at 22:39
  • @rando. There is really **no way** that that error could be raised by PyQt. You must be running some tkinter code somewhere - and the only place I can see from the code in your question is the `BigramsClassifier` function. Comment that line out and put in `time.sleep(2)`, then try again. – ekhumoro Oct 18 '17 at 23:10
  • Yes, that method is the issue. I did some digging and found out that the method **def createHistoryGraph(self, percentage) ** (github.com/umairfaiz/Projec2/blob/master/analysis.py) is causing the problem it draws an graph using Matplotlib where Tkinter is by default i guess – rando Oct 19 '17 at 00:18
  • @rando. So I assume that it must open a separate tkinter window? If that is the case, it would be better to launch it in a separate *process*, rather than a separate thread. – ekhumoro Oct 19 '17 at 13:23
  • Yes, it does the plotting through Matplotlib where Tkinter is their default canvas. But i am using it to only save the plot as an image and display that image on my GUI using pyqt4. However, from what i read processing is also the same as thread but doesn't use shared memory like threading. Can you please tell me how i can achieve adding processes to run the GUI and the heavy task separately for my context? – rando Oct 20 '17 at 08:51
  • @rando. Use the `multiprocessing` module. There are lots of simple examples on [PyMOTW](https://pymotw.com/2/multiprocessing/basics.html). You might need to experiment a bit to get it to work right with your application. – ekhumoro Oct 20 '17 at 16:07