Results 1 to 11 of 11

Thread: unfreezing GUI

  1. #1

    Default unfreezing GUI

    Is it true that to unfreeze a GUI one should use qthread whlie working in a pyqt framework ?

    If that is true then when a user clicks "OK" control should go to another thread passing a def from GUI. ( in the script attached )

    and ok button change to "processing"

    Googling for qthreads has helped build code to this level. However, my code does not work as required.

    I have tried two ways. One is while the GUI freezes to display "processing " on ok button so that user knows something is going on.

    Best would be to pass the task that takes time to another thread. None work .

    Kindly suggest what I am missing.



    Qt Code:
    1. #!/usr/bin/env python
    2. import sys
    3. import os, time
    4. from PyQt4 import QtCore, QtGui
    5. from backUpUi import Ui_MainWindow
    6.  
    7. class setText01Thread(QtCore.QThread):
    8.  
    9. def __init__(self, mw):
    10. super(setText01Thread, self).__init__(mw)
    11.  
    12. def run(self):
    13. self.emit(QtCore.SIGNAL('setStatus'))
    14.  
    15. class backUpMain(QtGui.QMainWindow):
    16.  
    17. """UI functionality to pack stuff for client"""
    18. def __init__(self,parent=None):
    19. super(backUpMain, self).__init__(parent)
    20. self.ui = Ui_MainWindow()
    21. self.ui.setupUi(self)
    22.  
    23. self.connect(self.ui.okButton, QtCore.SIGNAL("clicked()"), self._handlebackUp)
    24. self.ui.cancelButton.released.connect(self.close)
    25. self.statusTh = setText01Thread(self)
    26. self.connect(self.statusTh, QtCore.SIGNAL('setStatus'), self.updateText_01,QtCore.Qt.QueuedConnection)
    27.  
    28. def updateText_01(self):
    29. self.ui.okButton.setText("Processing Started")
    30.  
    31. def _handlebackUp(self):
    32.  
    33. self.statusTh.start()
    34. self.ui.logEdit.clear()
    35. .
    36. .
    37. outPutFileName = self.ui.outEdit.text()
    38. inputData = self.getInputContent(self.ui.filePathEdit.text())
    39.  
    40. # indPath = self.getIndPathFromShotgun(projectId,"sg_ind_path_to_frames")
    41. # the above line takes a long time to execute. Can this def be executed in another
    42. # thread
    43. .
    44. .
    45. .
    46.  
    47. def main():
    48. app = QtGui.QApplication(sys.argv)
    49. dialog = backUpMain()
    50. dialog.show()
    51. sys.exit(app.exec_())
    52.  
    53. if __name__ == '__main__':
    54. main()
    To copy to clipboard, switch view to plain text mode 
    Last edited by anda_skoa; 24th January 2015 at 09:57. Reason: missing [code] tags

  2. #2
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: unfreezing GUI

    I am not a python person, so take this feedback with a grain of salt...

    You should review the QThread best practices and use the "moveToThread" approach as documented/explained here: http://qt-project.org/doc/note_revisions/5/8/view.

    Also, the default QThread::run method creates an event loop and the function you defined does not do that, so unless there's some python magic under the covers, you need to either call the base class run or execute QThread::exec() on your own to create/enter an event loop.

    If you adopt the "moveToThread" approach, you don't need to subclass QThread. Just create an instance of QThread, move your worker object to the thread, and QThread::run() will enter the event loop, etc.

    Good luck.

  3. #3
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: unfreezing GUI

    You need to put the method that takes long to execute into the thread, i.e. you call getInputContent() in the thread's run() method.

    So your thread class needs to get the value that getInputContent() needs as its argument, e.g. as a constructor argument.

    Then, in _handlebackUp(), you get the value from the UI, create the thread and pass it the value.
    Then you connect the thread (e.g. its finished() signal) and start it.

    Once the thread has indicated it is finished, you retrieve the data from the thread object.

    Cheers,
    _

  4. #4

    Default Re: unfreezing GUI

    I have tried, to put in code, what you have suggested.
    The window still freezes.

    It is getIndPathFromShotgun that takes long not getInputContent

    What steps should one take in code to reach the goal ?

    Can you describe what you said codically.

    Qt Code:
    1. #!/usr/bin/env python
    2.  
    3. import re
    4. import sys
    5. import os, time
    6.  
    7. from PyQt4 import QtCore, QtGui
    8. from backUpUi import Ui_MainWindow
    9. from shotgun_api3 import Shotgun
    10.  
    11.  
    12. def getShotgunObject():
    13. sgServer = "https://abcdsdf.dsfasdfsadfsdf.com"
    14. sgScriptName = "dfsadfsadfsadfdsafd"
    15. sgScriptKey = "dfsad43lkj453-0-if4334lkjlkjx"
    16. sg = Shotgun(sgServer, sgScriptName, sgScriptKey)
    17. return sg
    18.  
    19.  
    20. class callerThread(QtCore.QThread):
    21.  
    22. def __init__(self, func, parent=None, *args, **kwargs):
    23. super(callerThread, self).__init__(parent)
    24. self._func = func
    25. self._args = args
    26. self._kwargs = kwargs
    27.  
    28. def run(self):
    29. self._func(*self._args, **self._kwargs)
    30.  
    31.  
    32. class Monitor(QtCore.QObject):
    33.  
    34. updateText = QtCore.pyqtSignal()
    35.  
    36. def __init__(self, parent=None):
    37. super(Monitor, self).__init__(parent)
    38. self.shotgun = getShotgunObject()
    39.  
    40.  
    41. def update_list(self):
    42. t_monitor = callerThread(self.monitor_vector, parent=self)
    43. t_monitor.daemon = True
    44. t_monitor.start()
    45.  
    46.  
    47.  
    48. def monitor_vector(self):
    49. print "... emitting "
    50. self.updateText.emit()
    51.  
    52.  
    53.  
    54. class backUpMain(QtGui.QMainWindow):
    55.  
    56. setText = QtCore.pyqtSignal()
    57.  
    58. """UI functionality to pack stuff for client"""
    59. def __init__(self,parent=None):
    60. super(backUpMain, self).__init__(parent)
    61. self.ui = Ui_MainWindow()
    62. self.ui.setupUi(self)
    63.  
    64. self.jobName = os.getenv('JOB')
    65. self.shotgun = getShotgunObject()
    66. self.dept = {}
    67.  
    68.  
    69. self.connect(self.ui.okButton, QtCore.SIGNAL("clicked()"), self.startThread)
    70. self.ui.cancelButton.released.connect(sys.exit)
    71.  
    72. self.ui.selectInFile.clicked.connect(self.selectInputFile)
    73. self.ui.selectOutFile.clicked.connect(self.selectOutputFile)
    74. self.ui.confirmButton.clicked.connect(self.validateAll)
    75. self.ui.clearCheckBox.clicked.connect(self.clearBox)
    76. self.ui.clearAllButton.clicked.connect(self.clearAll)
    77.  
    78.  
    79. def getIndPathFromShotgun(self):
    80.  
    81. projectId = self.getProjectId(self.jobName)
    82. filters = [['project','is',{'type':'Project','id':projectId}]]
    83. field1 = "sg_ind_path_to_frames"
    84. fields = []
    85. fields.append(field1)
    86. indPath = self.shotgun.find("Version", filters, fields)
    87. print " >>>> inside get ind path from shotgun "
    88. return indPath
    89.  
    90.  
    91. def _handlebackUp(self):
    92.  
    93. self.ui.logEdit.clear()
    94.  
    95. outPutFileName = self.ui.outEdit.text()
    96. inputData = self.getInputContent(self.ui.filePathEdit.text())
    97.  
    98. print " #### projectId in shotgun ",projectId
    99.  
    100. self.startThread()
    101.  
    102. print " #### post start thread "
    103.  
    104.  
    105.  
    106. def getProjectId(self, job):
    107. result = self.shotgun.find_one("Project", [['name', 'is', job]])
    108. prJid = int(result['id'])
    109. return prJid
    110.  
    111.  
    112. def startThread(self):
    113.  
    114. self.monitor = Monitor()
    115. print "in start thread"
    116.  
    117. self.monitor.updateText.connect(self.getIndPathFromShotgun)
    118. self.monitor.update_list()
    119.  
    120. print "post start thread"
    121.  
    122.  
    123. def getInputContent(self, data):
    124. '''
    125. check if data is file or group of shotnames or blank
    126. '''
    127. # print " data ",data
    128.  
    129. reg = r'[^a-zA-Z0-9]'
    130. shotList = []
    131. if os.path.isfile(data):
    132. with open(data) as inf:
    133. for line in inf:
    134. shotList.append(line.rstrip("\n"))
    135. # print "shotList ", shotList
    136. elif data == "":
    137. # make backup of all shots
    138. shotList.append(None)
    139. else:
    140. sss = re.findall(reg,data)
    141. if sss == []:
    142. message = "No seperator found. Try again. | or , or any non alpha numeric"
    143. self.ui.logEdit.append(message)
    144. return -1
    145. else:
    146. tmp = data.split(sss[0])
    147. for each in tmp:
    148. shotList.append(each)
    149. return shotList
    150.  
    151. .
    152. .
    153. .
    154. .
    155. .
    156.  
    157.  
    158.  
    159.  
    160. def main():
    161. app = QtGui.QApplication(sys.argv)
    162. dialog = backUpMain()
    163. dialog.show()
    164. sys.exit(app.exec_())
    165.  
    166. if __name__ == '__main__':
    167. main()
    To copy to clipboard, switch view to plain text mode 
    Last edited by anda_skoa; 27th January 2015 at 15:31. Reason: missing [code] tags

  5. #5
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: unfreezing GUI

    Quote Originally Posted by singhai.nish View Post
    It is getIndPathFromShotgun that takes long not getInputContent
    The principle is obviously the same.

    - Put what ever data you need into the thread object
    - Run whatever operation on that data in run()
    - Retrieve the results when the thread's finished() signal has indicated that it is done.

    Cheers,
    _

  6. #6

    Thumbs up Re: unfreezing GUI

    Thank you. With help from this link ( http://www.matteomattei.com/pyside-s...hread-example/ ) and your suggestion, I can now see the window unfreeze while getIndPathFromShotgun was running ( important achievment ). Next step is to bigger (do more computation) .

  7. #7

    Default Re: unfreezing GUI

    So far, I've been able to pass data from sub thread to the main thread using signals. How do I pass a value from main UI to a thread.
    Or should I put this as a new question.
    Last edited by singhai.nish; 29th January 2015 at 12:05.

  8. #8
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: unfreezing GUI

    If you can pass the data before you call start(), you can pass it through the thread object's constructor.

    If you need to pass it later, you can do that through a setter method, from which you write members of the thread object.
    Make sure to properly protect access using QMutex and friends.

    Cheers,
    _

  9. #9

    Default Re: unfreezing GUI

    1. Tried first suggestion (refer : http://stackoverflow.com/questions/2...d-worker-class , kitsune meyoko)

    2. In current context, I'll have to choose latter suggestion, as it is user input that i need to pass to thread and thread is being instanced in main thread __init__ func


    Question is how to use setter method to pass variables to thread ?

    Tried googling, found this but not sure if this will help. Kindly suggest.

    https://wiki.python.org/moin/PyQt/Bi...on%20variables

  10. #10
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: unfreezing GUI

    Quote Originally Posted by singhai.nish View Post
    2. In current context, I'll have to choose latter suggestion, as it is user input that i need to pass to thread and thread is being instanced in main thread __init__ func
    For which reason do you instantiate the thread there and not when you need it?
    Is the thread running at all times and occasionally getting data?

    Cheers,
    _

  11. #11

    Thumbs up Re: unfreezing GUI

    Thank you anda_skoa. Your counter questions have helped solve qthread as a puzzle for me. Thank you very much for your support.

    I've put thread instantiation where required not in __init__. It worked.
    Last edited by singhai.nish; 2nd February 2015 at 13:28. Reason: better format

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.