I need to implement the following UI:
- There is a window with a label "running experiment 1/X" and a button
- When the window is loaded, some experiments are started. The experiments are run by os.system
of subprocess.Popen
, they are just pre-compiled C++ programs
- The experiments should run strictly one after another and not simultaneously (hence I can't use subprocess.Popen
)
- The window should be active while the experiments are running and the user can press the button
- When the button is pressed, the experiments stop (we can just wait until the current experiment ends and stop) and the window closes
- When all experiments are over, the window should close itself
First I tried running experiments in threading.Thread
, but it still blocked the window. So I switched to multiprocessing.Process
:
class StoppableProcess(Process):
def __init__(self, name, alg, proj, parent):
Process.__init__(self)
self.stop = False
self.name = name
self.alg = alg
self.proj = proj
self.parent = parent
def stop(self):
self.stop = True
def stopped(self):
return self.stop
def run(self):
count = len([k for k in self.proj.values()])
i = 1
for p in self.proj.values():
self.parent.label.setText("Running experiment " + str(i) + " / " + str(count))
os.system("some command here")
i += 1
if self.stopped():
break
self.parent.hide()
class Runner(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
self.layout = QVBoxLayout()
self.label = QLabel("Running experiment 0 / 0")
self.setWindowTitle("Running experiments")
button = QPushButton("Break experiments")
self.layout.addWidget(self.label)
self.layout.addWidget(button)
self.setLayout(self.layout)
QObject.connect(button, SIGNAL("clicked()"), self.Break)
def Run(self, name, alg, proj):
self.thread = StoppableProcess(name, alg, proj, self)
self.thread.start()
self.show()
self.thread.join()
def Break(self):
self.thread.stop()
self.hide()
However, this doesn't work at all, apparently because the Runner
object should be pickled to be passed to a subprocess, but pickling fails. I was thinking about avoiding passing the parent argument and using Qt signals instead, but maybe there's a better solution?