0

So problem occurred when I tried using Threading in my code. What I want to do is passing default values to the def __init__ and then calling the thread with its instance with updated values but somehow I cannot get the updated values.

Below is my initial code: main.py

from PyQt4 import QtGui
import sys
import GUI # GUI app by using PYQT4
from PyQt4.QtCore import QThread
#import Photos

class PyMain(QtGui.QWidget, GUI.Ui_Pycloud):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.password.setEchoMode(QtGui.QLineEdit.Password)

        """Picking up data from GUI.py file where initially,
        it is set to 'Username' and 'Password' respectively.
        and initialising `GetThread` class"""
        self.get_thread = GetThread(str(self.username.text()), 
                                    str(self.password.text())
                                   )
        """This is what I was initially using.
           I have tried, only passing the instance and calling 
           get_thread.start() inside __init__ fn but even if i don't click 
           `commandLinkButton` it is somehow called automatically.
           I know it is not the right approach"""
        self.commandLinkButton.clicked.connect(self.get_thread.start)


class GetThread(QThread):

    def __init__(self, username, password):
        QThread.__init__(self)
        self.username = username
        self.password = password

    def __del__(self):
        self.wait()

    def authentication(self):
        print self.username, self.password
        # user = Photos.PyPhotos(self.username, self.password)
        # user.authentication(user)

    def run(self):
        self.authentication()


def main():
    app = QtGui.QApplication(sys.argv)
    form = PyMain()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

Below is what I tried:

...........................
...........................
...........................

class PyMain(QtGui.QWidget, GUI.Ui_Pycloud):
  def __init__(self):
    super(self.__class__, self).__init__()
    self.setupUi(self)
    self.password.setEchoMode(QtGui.QLineEdit.Password)
    self.commandLinkButton.clicked.connect(GetThread(str(self.username.text()), 
                                             str(self.password.text())).__init__)

class GetThread(QThread):

 def __init__(self, username, password):
        QThread.__init__(self)
        self.username = username
        self.password = password
        self.start()
...........................
...........................
...........................

Result: Username Password

Which is shown the moment I run my main.py file, whereas I should get this only and only if I press commandLinkButton and should update variables if I update them on my GUI which is not happening.

EDIT: Below is what I tried again, it is showing me the correct output if I update them on GUI but threading is not working in this case:

..............
..............
..............
class PyMain(QtGui.QWidget, GUI.Ui_Pycloud):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.password.setEchoMode(QtGui.QLineEdit.Password)
        self.commandLinkButton.clicked.connect(self.populate)

    def populate(self):
        get_thread = GetThread(str(self.username.text()), str(self.password.text()))
        get_thread.start()


class GetThread(QThread):

    def __init__(self, username, password):
        QThread.__init__(self)
        self.username = username
        self.password = password

    def __del__(self):
        self.wait()

    def authentication(self):
        print self.username, self.password
        user = Photos.PyPhotos(self.username, self.password)
        user.authentication(user)

    def run(self):
        self.authentication()
......................
......................
......................

So anyone can please tell me how to approach this?

Aadit
  • 199
  • 1
  • 6
  • 17

1 Answers1

2

You need to use a custom signal to send the authentication result back the main thread. But note that you must not perform any gui operations of any kind outside the main thread. So, for example, the worker thread cannot show an authentication dialog or attempt to directly update widgets. All it can do is execute a lengthy non-gui process and send the result back to the main thread when it's finished.

The basic structure of the code should look like this:

class PyMain(QtGui.QWidget, GUI.Ui_Pycloud):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.password.setEchoMode(QtGui.QLineEdit.Password)
        self.commandLinkButton.clicked.connect(self.populate)

    def populate(self):
        self.thread = GetThread(self.username.text(), self.password.text())
        self.thread.authResult.connect(self.handleAuthResult)
        self.thread.start()

    def handleAuthResult(self, result):
        # do something with result...

class GetThread(QThread):
    authResult = QtCore.pyqtSignal(object)

    def __init__(self, username, password):
        QThread.__init__(self)
        self.username = username
        self.password = password

    def authentication(self):
        result = do_authentication()
        self.authResult.emit(result)

    def run(self):
        self.authentication()
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Worked flawlessly. Kind of new to PyQt and threading, thank you for sharing that. (thumbs up) - @ekhumoro – Aadit Oct 17 '17 at 19:01
  • and since we are on PyQt can you please suggest any post/blog for linking two different GUIs - @ekhumoro – Aadit Oct 17 '17 at 19:04
  • @Aadit. You're welcome. I'm not sure what you mean by "linking two different GUIs". Maybe you should post a new question? – ekhumoro Oct 17 '17 at 19:06
  • I just want to open instruction.py(Dialog window created by Qt designer) file on clicking a button on my main.py file. I have tried some approaches but running into problems. So should I post this is a question? – Aadit Oct 17 '17 at 19:31
  • 1
    @Aadit. Import the dialog class, and then create a subclass of it in the same way as `PyMain`. Then in a slot connected to the button, do `self.dialog = DialogSubClass(); self.dialog.show()`. – ekhumoro Oct 17 '17 at 19:58
  • Just got that working thank you mate could not ask for more help thanks again @ekhumoro – Aadit Oct 17 '17 at 20:50