3

I'm writing a data acquisition program and I'm interested in keeping the GUI responsive at all times. That's why I'm using QThreads for the job. Even though the result is slightly better when comparing with case in which the whole job is done in a single thread, my GUI still hangs until the task is done. This is the relevant part of the code:

import numpy as np
from PyQt4 import QtGui, QtCore
import h5py as hdf
import tifffile as tiff


class MyWidget(QtGui.QFrame):

    def __init__(self, *args, **kwargs):

        super(MyWidget, self).__init__(*args, **kwargs)
        self.convertButton = QtGui.QPushButton('Convert to TIFF')
        self.convertButton.clicked.connect(self.convertToTiff)
        recGrid = QtGui.QGridLayout()
        self.setLayout(recGrid)
        recGrid.addWidget(self.convertButton, 0, 0)

    def convertToTiff(self):
        self.converterThread = QtCore.QThread()
        self.converter = TiffConverter(self.savename, self.dataname)
        self.converter.moveToThread(self.converterThread)
        self.converterThread.started.connect(self.converter.run)
        self.converterThread.start()


class TiffConverter(QtCore.QObject):

    def __init__(self, filename, dataname, *args, **kwargs):
        super(TiffConverter, self).__init__(*args, **kwargs)
        self.filename = filename
        self.dataname = dataname
        self.file = hdf.File(self.filename, mode='r')

    def run(self):
        tiff.imsave(self.filename, self.file[self.dataname])
        self.file.close()


if __name__ == '__main__':
    app = QtGui.QApplication([])

    win = MyWidget()
    win.show()

    app.exec_()

I know the GUI hangs at tiff.imsave(self.filename, self.file[self.dataname]) and I'm familiar with the fact that QThreads aren't really doing parallel computing. Could this be the reason why the GUI hangs? Or is there a problem with sharing variables like I'm doing it? Is there any workaround for these kind of cases?

Federico Barabas
  • 659
  • 8
  • 21
  • 1
    It looks like your task may be CPU-bound, but cannot be broken up into smaller pieces. If it could, you'd be able to periodically send a signal to the main thread allowing the GUI to update. You should perhaps consider using [multiprocessing](https://docs.python.org/3.4/library/multiprocessing.html), instead. – ekhumoro Mar 17 '15 at 23:57

1 Answers1

-1

You can use threading to solve your problem.

You can put your image writing function inside a new thread and then that task will get independent of your UI part and hence it will not lag.

I have done it and let me know if you need any further help.

class ThreadLiveViewProcessing(QThread):
    def __init__(self):
        super(ThreadLiveViewProcessing, self).__init__()




        self.is_ThreadLiveViewProcessing_running = True

    def run(self):
        enter code here

Then you can create its instance in init of your UI class.

class MyWidget(QtGui.QFrame):

    def __init__(self, *args, **kwargs):

        super(MyWidget, self).__init__(*args, **kwargs)

        # Thread should never have parents.
        # Create instance of Thread Class for processing in faceme.

        self.thread_live_view_processing = ThreadLiveViewProcessing()

        self.thread_live_view_processing.start()

        ... snippet ... code ... etc.
        
        recGrid = QtGui.QGridLayout()
        self.setLayout(recGrid)
        recGrid.addWidget(self.convertButton, 0, 0)

You can start the thread where you need it with:

self.thread_live_view_processing.start()
ZF007
  • 3,708
  • 8
  • 29
  • 48
  • 1
    `def convertToTiff(self): self.converterThread = QtCore.QThread()` does do threading right ...? – ZF007 Oct 15 '20 at 09:46
  • 1
    Much better. The reason why OPs code wasn't working is due to the fact QThread had parents. This should never be the case. One can learn from this example [here](https://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt). – ZF007 Oct 21 '20 at 09:02