I think I have fixed the issues which caused this program to not be functional.
Now I believe the design of my code is somewhat bad and may be causing problems with the number of processes that are created (I would think 10 processes would be created when 20 are?). I am unsure what may be causing this, but I probably have lots of other issues in cleanliness of my code as well.
What I am Trying to do:
I am trying to get a GUI to allocate processes to a bunch of tabs (number of tabs is determined by the user in the real program) and then having each tab display results of each process in real time.
My hope is to have the user be able to start/stop a long process on each tab's data at will, and then be able to manually change the data in between starting/stopping the automated data manipulation process.
Here is a simple script:
from PyQt4 import QtCore, QtGui
import multiprocessing as mp
import sys
import time
# Just make some data to manipulate and process
def make_data():
data = {'num': 3, 'num2': 4}
return data
# Some function which tries to process the data
# which can be stopped and allows the adjustment of the data by the user
def f(data, can_run):
for i in range(data['num'], data['num'] + 10**5):
can_run.wait()
data['num'] += 1
data['num2'] += 100
# Each tab holds a set of data which shows the manipulation of it's contents
# can be started and stopped to adjust the data with a button
class Tab(QtGui.QTabWidget):
def __init__(self, parent, data_init):
# GUI junk
QtGui.QTabWidget.__init__(self, parent)
self.top_level_layout = QtGui.QGridLayout(self)
self.frame = QtGui.QFrame(self)
self.top_level_layout.addWidget(self.frame)
self.step_label = dict()
self.step_stacked = dict()
self.step_text = dict()
self.step_input = dict()
for wdgts in data_init.keys():
self.step_label[wdgts] = QtGui.QLabel(str(wdgts))
self.step_stacked[wdgts] = QtGui.QStackedWidget()
self.step_text[wdgts] = QtGui.QLabel(str(data_init[wdgts]))
self.step_input[wdgts] = QtGui.QLineEdit()
self.step_stacked[wdgts].addWidget(self.step_text[wdgts])
self.step_stacked[wdgts].addWidget(self.step_input[wdgts])
self.top_level_layout.addWidget(self.step_stacked[wdgts])
self.top_level_layout.addWidget(self.step_label[wdgts])
# Each tab gets a button to start or stop a process
self.process_button = QtGui.QPushButton("Process")
self.top_level_layout.addWidget(self.process_button, 1, 1)
QtCore.QObject.connect(self.process_button, QtCore.SIGNAL("clicked()"), self.start_process)
# setup a managet to hold the data to pass between the GUI and the process
self.manager = mp.Manager()
self.data = self.manager.dict(make_data())
self.Event = self.manager.Event()
self.process = mp.Process(target=f, args=(self.data,self.Event,))
self.process.daemon = True
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.update_GUI)
self.first_start = True
def update_GUI(self):
try:
for wdgt in self.data.keys():
self.step_label[wdgt].setText(str(wdgt))
self.step_input[wdgt].setText(str(self.data[wdgt]))
self.step_text[wdgt].setText(str(self.data[wdgt]))
except EOFError:
print 'have reached the end of the file'
QtCore.QObject.disconnect(self.process_button, QtCore.SIGNAL("clicked()"), self.stop_process)
QtCore.QObject.disconnect(self.process_button, QtCore.SIGNAL("clicked()"), self.start_process)
self.timer.stop()
self.process.join()
return
def start_process(self):
for wdgt in self.step_stacked.keys():
self.step_stacked[wdgt].setCurrentWidget(self.step_text[wdgt])
if self.first_start==True:
print 'first start'
self.process.start()
self.first_start = False
else:
for wdgt in self.data.keys():
self.data[wdgt] = int(self.step_input[wdgt].text())
print 'start process again'
self.process_button.setText('Stop Processing - (manually adjust data)')
QtCore.QObject.disconnect(self.process_button, QtCore.SIGNAL("clicked()"), self.start_process)
QtCore.QObject.connect(self.process_button, QtCore.SIGNAL("clicked()"), self.stop_process)
self.timer.start(100)
self.Event.set()
return
def stop_process(self):
print 'stopping proccess'
self.Event.clear()
for wdgt in self.step_stacked.keys():
self.step_stacked[wdgt].setCurrentWidget(self.step_input[wdgt])
self.timer.stop()
self.process_button.setText('Start Processing Again Using Data')
QtCore.QObject.disconnect(self.process_button, QtCore.SIGNAL("clicked()"), self.stop_process)
QtCore.QObject.connect(self.process_button, QtCore.SIGNAL("clicked()"), self.start_process)
return
# More GUI stuff
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self)
screen_height = app.desktop().screenGeometry().height()
screen_width = app.desktop().screenGeometry().width()
self.resize(int(screen_width*0.2), int(screen_height*0.2))
self.tab_list = []
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)
self.setCentralWidget(self.centralwidget)
self.centralwidget.setLayout(self.top_level_layout)
self.process_all__button = QtGui.QPushButton("Start All Processes")
self.top_level_layout.addWidget(self.process_all__button, 0, 0)
QtCore.QObject.connect(self.process_all__button, QtCore.SIGNAL("clicked()"), self.start_all_process)
# Make Tabs in loop from button
for i in range(0,10):
super_cool_data = make_data()
name = 'tab ' + str(i)
self.tab_list.append(Tab(self.tabWidget, super_cool_data))
self.tabWidget.addTab(self.tab_list[-1], name)
# All Processes can be started and stopped together
def start_all_process(self):
self.process_all__button.setText('Stop All Processing')
QtCore.QObject.disconnect(self.process_all__button, QtCore.SIGNAL("clicked()"), self.start_all_process)
QtCore.QObject.connect(self.process_all__button, QtCore.SIGNAL("clicked()"), self.stop_all_process)
for i in self.tab_list:
i.start_process()
def stop_all_process(self):
self.process_all__button.setText('Start All Processing')
QtCore.QObject.disconnect(self.process_all__button, QtCore.SIGNAL("clicked()"), self.stop_all_process)
QtCore.QObject.connect(self.process_all__button, QtCore.SIGNAL("clicked()"), self.start_all_process)
for i in self.tab_list:
i.stop_process()
# Get rid of the processes after closing the GUI, no matter where they are in process stage
def closeEvent(self, event):
for tab in self.tab_list:
tab.process.terminate()
if __name__ == "__main__":
app = QtGui.QApplication([])
win = MainWindow()
win.show()
sys.exit(app.exec_())