chase
chase

Reputation: 3782

QThread Signals/Slots to QProcesses

I have a program which uses QThreads and Signals/Slots to communicate to a GUI. It has the simplified form shown below.

However, I would like to change this to a QProcess so that I can take advantage of multicore processing. Is there a simple way to do this?

If I simply change QThread to QProcess , there is no moveToThread() function for processes. I have been trying several different approaches to multicore processing, such as Pipes() and Queues() in the multiprocessing module, but I can't get anything to work very well. So, I figured it would be easier to use QProcess since I am already in Qtland.

Here is the simplified code I have for QThreads, signals and slots.

from PyQt4 import QtCore, QtGui
import multiprocessing as mp
import numpy as np
import sys

class Spectra(QtCore.QObject):

    update_signal = QtCore.pyqtSignal(str)
    done_signal = QtCore.pyqtSignal()

    def __init__(self, spectra_name, X, Y):
        QtCore.QObject.__init__(self)
        self.spectra_name = spectra_name
        self.X = X
        self.Y = Y
        self.iteration = 0

    @QtCore.pyqtSlot() 
    def complex_processing_on_spectra(self):
        for i in range(0,99999):
            self.iteration += 1
            self.update_signal.emit(str(self.iteration))
        self.done_signal.emit()

class Spectra_Tab(QtGui.QTabWidget):
    start_comp = QtCore.pyqtSignal()
    kill_thread = QtCore.pyqtSignal()
    def __init__(self, parent, spectra):
        self.parent = parent
        self.spectra = spectra
        QtGui.QTabWidget.__init__(self, parent)

        self.treeWidget = QtGui.QTreeWidget(self)
        self.properties = QtGui.QTreeWidgetItem(self.treeWidget, ["Properties"])
        self.step = QtGui.QTreeWidgetItem(self.properties, ["Iteration #"])

        thread = QtCore.QThread(parent=self)
        self.worker = self.spectra
        self.worker.moveToThread(thread)
        self.worker.update_signal.connect(self.update_GUI)
        self.worker.done_signal.connect(self.closeEvent)
        self.start_comp.connect(self.worker.complex_processing_on_spectra)
        self.kill_thread.connect(thread.quit)
        thread.start()

    @QtCore.pyqtSlot(str)
    def update_GUI(self, iteration):
        self.step.setText(0, iteration)

    def start_computation(self):
        self.start_comp.emit()

    def closeEvent(self):
        print 'done with processing'
        self.kill_thread.emit()

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent = None):
        QtGui.QMainWindow.__init__(self)

        self.setTabShape(QtGui.QTabWidget.Rounded)
        self.centralwidget = QtGui.QWidget(self)
        self.top_level_layout = QtGui.QGridLayout(self.centralwidget)

        self.tabWidget = QtGui.QTabWidget(self.centralwidget)
        self.top_level_layout.addWidget(self.tabWidget, 1, 0, 25, 25)

        process_button = QtGui.QPushButton("Process")
        self.top_level_layout.addWidget(process_button, 0, 1)
        QtCore.QObject.connect(process_button, QtCore.SIGNAL("clicked()"), self.process)

        self.setCentralWidget(self.centralwidget)
        self.centralwidget.setLayout(self.top_level_layout)

        # Open several files in loop from button - simplifed to one here
        X = np.arange(0.1200,.2)
        Y = np.arange(0.1200,.2)
        self.spectra = Spectra('name', X, Y)
        self.spectra_tab = Spectra_Tab(self.tabWidget, self.spectra)
        self.tabWidget.addTab(self.spectra_tab, 'name')

    def process(self):
        self.spectra_tab.start_computation()
        return

if __name__ == "__main__":
    app = QtGui.QApplication([])
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())

Upvotes: 1

Views: 1675

Answers (1)

Ilya Kobelevskiy
Ilya Kobelevskiy

Reputation: 5345

There is no moveToThread() for processes since a process lives in its own memory space, so it cannot see MainWindow or any of it members. The application that you start using QProcess should be able to execute as stand-alone application.

To run spectra in another QProcess, you will need to make spectra a separate executable module instead of MainWindow member as it is now.

EDIT:

You need to define the self-contained module that is least dependent on the MainWindow - it can be spectra process only, or spectra process with tab. You can pass info to process either on construction, or through standard input, and retrieve data from process through standard output. Key idea when selecting lawyer to put process in is to minimize communication and dependency between the process and MainWindow. You may think of a process as simple C program:

int main(int argc,char* argv[]);

you can pass arguments on startup, get additional input from MainWindow through cin/stdin if necessary, output some results to MainWindow through cout/stdout/stderr (QProcess have interface for that).

Upvotes: 2

Related Questions