Rudimentary support for new communication scheme in GUI
This commit is contained in:
@@ -55,6 +55,10 @@ class Context:
|
||||
self.state = ErrorState(event.exception, self.state)
|
||||
elif isinstance(event, TeardownEvent):
|
||||
self.state = TeardownState(event.target)
|
||||
if event.target == TeardownEvent.EXIT:
|
||||
return 0
|
||||
elif event.target == TeardownEvent.RESTART:
|
||||
return 123
|
||||
else:
|
||||
self.state.handleEvent(event, self)
|
||||
|
||||
@@ -206,7 +210,7 @@ class ErrorState(State):
|
||||
context.state = self.old_state
|
||||
context.state.update()
|
||||
elif isinstance(event, GuiEvent) and event.name == 'abort':
|
||||
context.state = TeardownState()
|
||||
context.state = TeardownState(TeardownEvent.WELCOME)
|
||||
else:
|
||||
raise TypeError('Unknown Event type "{}"'.format(event))
|
||||
|
||||
@@ -216,11 +220,27 @@ class TeardownState(State):
|
||||
def __init__(self, target):
|
||||
|
||||
super().__init__()
|
||||
self._target = target
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return 'TeardownState'
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
|
||||
return self._target
|
||||
|
||||
def handleEvent(self, event, context):
|
||||
|
||||
if self._target == TeardownEvent.WELCOME:
|
||||
if isinstance(event, GuiEvent) and event.name == 'welcome':
|
||||
context.state = WelcomeState()
|
||||
else:
|
||||
raise ValueError('Unknown GuiEvent "{}"'.format(event.name))
|
||||
else:
|
||||
raise TypeError('Unknown Event type "{}"'.format(event))
|
||||
|
||||
|
||||
class WelcomeState(State):
|
||||
|
||||
@@ -237,34 +257,14 @@ class WelcomeState(State):
|
||||
if isinstance(event, GuiEvent):
|
||||
if event.name == 'start':
|
||||
context.state = StartupState()
|
||||
elif event.name == 'settings':
|
||||
context.state = SettingsState()
|
||||
elif event.name == 'exit':
|
||||
context.state = TeardownState()
|
||||
context.state = TeardownState(TeardownEvent.EXIT)
|
||||
else:
|
||||
raise ValueError('Unknown GuiEvent "{}"'.format(event.name))
|
||||
else:
|
||||
raise TypeError('Unknown Event type "{}"'.format(event))
|
||||
|
||||
|
||||
class SettingsState(State):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
super().__init__()
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return 'SettingsState'
|
||||
|
||||
def handleEvent(self, event, context):
|
||||
|
||||
if isinstance(event, GuiEvent) and event.name == 'welcome':
|
||||
context.state = WelcomeState()
|
||||
else:
|
||||
raise TypeError('Unknown Event type "{}"'.format(event))
|
||||
|
||||
|
||||
class StartupState(State):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -19,10 +19,13 @@
|
||||
|
||||
import logging
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
from time import localtime, strftime
|
||||
|
||||
from .PictureList import PictureList
|
||||
from .StateMachine import TeardownEvent, TeardownState
|
||||
from .Threading import Workers
|
||||
|
||||
|
||||
class WorkerTask:
|
||||
@@ -60,13 +63,23 @@ class PictureSaver(WorkerTask):
|
||||
|
||||
class Worker:
|
||||
|
||||
def __init__(self, config, queue):
|
||||
def __init__(self, config, comm):
|
||||
|
||||
self._queue = queue
|
||||
self._comm = comm
|
||||
|
||||
def run(self):
|
||||
|
||||
for func, args in iter(self._queue.get, 'teardown'):
|
||||
func(*args)
|
||||
for state in self._comm.iter(Workers.WORKER):
|
||||
self.handleState(state)
|
||||
|
||||
return 0
|
||||
def handleState(self, state):
|
||||
|
||||
if isinstance(state, TeardownState):
|
||||
self.teardown(state)
|
||||
|
||||
def teardown(self, state):
|
||||
|
||||
if state.target == TeardownEvent.EXIT:
|
||||
sys.exit(0)
|
||||
elif state.target == TeardownEvent.RESTART:
|
||||
sys.exit(123)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from PIL import Image, ImageOps
|
||||
|
||||
@@ -51,13 +52,17 @@ class Camera:
|
||||
self._is_keep_pictures = config.getBool('Photobooth', 'keep_pictures')
|
||||
|
||||
logging.info('Using camera {} preview functionality'.format(
|
||||
'with' if self.is_preview else 'without'))
|
||||
'with' if self._is_preview else 'without'))
|
||||
|
||||
self.setIdle()
|
||||
|
||||
def teardown(self):
|
||||
def teardown(self, state):
|
||||
|
||||
self._cap.cleanup()
|
||||
if state.target == StateMachine.TeardownEvent.EXIT:
|
||||
sys.exit(0)
|
||||
elif state.target == StateMachine.TeardownEvent.RESTART:
|
||||
sys.exit(123)
|
||||
|
||||
def run(self):
|
||||
|
||||
@@ -75,7 +80,7 @@ class Camera:
|
||||
elif isinstance(state, StateMachine.AssembleState):
|
||||
self.assemblePicture()
|
||||
elif isinstance(state, StateMachine.TeardownState):
|
||||
self.teardown()
|
||||
self.teardown(state)
|
||||
|
||||
def setActive(self):
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ countdown_time = 8
|
||||
display_time = 5
|
||||
# Timeout for postprocessing (shown after review)
|
||||
postprocess_time = 60
|
||||
# Keep single pictures (True/False)
|
||||
keep_pictures = False
|
||||
|
||||
[Picture]
|
||||
# Basedir of output pictures
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# from . import GuiState
|
||||
from .. import StateMachine
|
||||
|
||||
|
||||
@@ -86,8 +85,6 @@ class GuiSkeleton:
|
||||
self.showWelcome(state)
|
||||
elif isinstance(state, StateMachine.StartupState):
|
||||
self.showStartup(state)
|
||||
elif isinstance(state, StateMachine.SettingsState):
|
||||
self.showSettings(state)
|
||||
elif isinstance(state, StateMachine.IdleState):
|
||||
self.showIdle(state)
|
||||
elif isinstance(state, StateMachine.GreeterState):
|
||||
|
||||
@@ -34,7 +34,7 @@ from . import Widgets
|
||||
from . import styles
|
||||
|
||||
|
||||
class Start(QtWidgets.QFrame):
|
||||
class Welcome(QtWidgets.QFrame):
|
||||
|
||||
def __init__(self, start_action, set_date_action, settings_action,
|
||||
exit_action):
|
||||
@@ -79,7 +79,7 @@ class Start(QtWidgets.QFrame):
|
||||
|
||||
class IdleMessage(QtWidgets.QFrame):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, trigger_action):
|
||||
|
||||
super().__init__()
|
||||
self.setObjectName('IdleMessage')
|
||||
@@ -87,12 +87,13 @@ class IdleMessage(QtWidgets.QFrame):
|
||||
self._message_label = 'Hit the'
|
||||
self._message_button = 'Button!'
|
||||
|
||||
self.initFrame()
|
||||
self.initFrame(trigger_action)
|
||||
|
||||
def initFrame(self):
|
||||
def initFrame(self, trigger_action):
|
||||
|
||||
lbl = QtWidgets.QLabel(self._message_label)
|
||||
btn = QtWidgets.QPushButton(self._message_button)
|
||||
btn.clicked.connect(trigger_action)
|
||||
|
||||
lay = QtWidgets.QVBoxLayout()
|
||||
lay.addWidget(lbl)
|
||||
@@ -102,7 +103,7 @@ class IdleMessage(QtWidgets.QFrame):
|
||||
|
||||
class GreeterMessage(QtWidgets.QFrame):
|
||||
|
||||
def __init__(self, num_x, num_y):
|
||||
def __init__(self, num_x, num_y, countdown_action):
|
||||
|
||||
super().__init__()
|
||||
self.setObjectName('GreeterMessage')
|
||||
@@ -114,14 +115,15 @@ class GreeterMessage(QtWidgets.QFrame):
|
||||
else:
|
||||
self._text_label = ''
|
||||
|
||||
self.initFrame()
|
||||
self.initFrame(countdown_action)
|
||||
|
||||
def initFrame(self):
|
||||
def initFrame(self, countdown_action):
|
||||
|
||||
ttl = QtWidgets.QLabel(self._text_title)
|
||||
ttl.setObjectName('title')
|
||||
btn = QtWidgets.QPushButton(self._text_button)
|
||||
btn.setObjectName('button')
|
||||
btn.clicked.connect(countdown_action)
|
||||
lbl = QtWidgets.QLabel(self._text_label)
|
||||
lbl.setObjectName('message')
|
||||
|
||||
@@ -132,7 +134,7 @@ class GreeterMessage(QtWidgets.QFrame):
|
||||
self.setLayout(lay)
|
||||
|
||||
|
||||
class PoseMessage(QtWidgets.QFrame):
|
||||
class CaptureMessage(QtWidgets.QFrame):
|
||||
|
||||
def __init__(self, num_picture, num_x, num_y):
|
||||
|
||||
@@ -325,6 +327,7 @@ class PostprocessMessage(Widgets.TransparentOverlay):
|
||||
|
||||
def disableAndCall(button, handle):
|
||||
button.setEnabled(False)
|
||||
button.update()
|
||||
handle()
|
||||
|
||||
def createButton(task):
|
||||
|
||||
@@ -27,10 +27,9 @@ from PyQt5 import QtWidgets
|
||||
|
||||
from PIL import ImageQt
|
||||
|
||||
# from ... import StateMachine
|
||||
# from ...Threading import Workers
|
||||
from ...StateMachine import GuiEvent, TeardownEvent
|
||||
from ...Threading import Workers
|
||||
|
||||
from .. import GuiState
|
||||
from ..GuiSkeleton import GuiSkeleton
|
||||
from ..GuiPostprocessor import GuiPostprocessor
|
||||
|
||||
@@ -41,70 +40,54 @@ from . import Receiver
|
||||
|
||||
class PyQt5Gui(GuiSkeleton):
|
||||
|
||||
def __init__(self, argv, config, camera_conn, worker_queue, communicator):
|
||||
def __init__(self, argv, config, communicator):
|
||||
|
||||
super().__init__(communicator)
|
||||
|
||||
self._cfg = config
|
||||
self._conn = camera_conn
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--run', action='store_true',
|
||||
help='omit welcome screen and run photobooth')
|
||||
parsed_args, unparsed_args = parser.parse_known_args()
|
||||
self._omit_welcome = parsed_args.run
|
||||
|
||||
self._registerCallbacks()
|
||||
is_start, unparsed_args = self._parseArgs()
|
||||
self._initUI(argv[:1] + unparsed_args)
|
||||
self._initReceiver()
|
||||
|
||||
self._picture = None
|
||||
self._postprocess = GuiPostprocessor(self._cfg)
|
||||
|
||||
if is_start:
|
||||
self._comm.send(Workers.MASTER, GuiEvent('start'))
|
||||
|
||||
def run(self):
|
||||
|
||||
if self._omit_welcome:
|
||||
self._showStart(None)
|
||||
else:
|
||||
self._showWelcomeScreen()
|
||||
exit_code = self._app.exec_()
|
||||
self._gui = None
|
||||
return exit_code
|
||||
|
||||
def close(self):
|
||||
def _parseArgs(self):
|
||||
|
||||
self._gui.close()
|
||||
# Add parameter for direct startup
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--run', action='store_true',
|
||||
help='omit welcome screen and run photobooth')
|
||||
parsed_args, unparsed_args = parser.parse_known_args()
|
||||
|
||||
def restart(self):
|
||||
|
||||
self._app.exit(123)
|
||||
|
||||
def _registerCallbacks(self):
|
||||
|
||||
self.idle = self._showIdle
|
||||
self.trigger = self._sendTrigger
|
||||
self.greeter = self._showGreeter
|
||||
self.countdown = self._showCountdown
|
||||
self.preview = self._showPreview
|
||||
self.pose = self._showPose
|
||||
self.assemble = self._showAssemble
|
||||
self.review = self._showReview
|
||||
self.teardown = self._sendTeardown
|
||||
self.error = self._showError
|
||||
return (parsed_args.run, unparsed_args)
|
||||
|
||||
def _initUI(self, argv):
|
||||
|
||||
self._disableTrigger()
|
||||
|
||||
# Load stylesheet
|
||||
style = self._cfg.get('Gui', 'style')
|
||||
filename = next((file for name, file in styles if name == style))
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), filename), 'r') as f:
|
||||
stylesheet = f.read()
|
||||
|
||||
# Create application and main window
|
||||
self._app = QtWidgets.QApplication(argv)
|
||||
self._app.setStyleSheet(stylesheet)
|
||||
self._gui = PyQt5MainWindow(self._cfg, self._handleKeypressEvent)
|
||||
|
||||
# Load additional fonts
|
||||
fonts = ['photobooth/gui/Qt5Gui/fonts/AmaticSC-Regular.ttf',
|
||||
'photobooth/gui/Qt5Gui/fonts/AmaticSC-Bold.ttf']
|
||||
self._fonts = QtGui.QFontDatabase()
|
||||
@@ -113,14 +96,11 @@ class PyQt5Gui(GuiSkeleton):
|
||||
|
||||
def _initReceiver(self):
|
||||
|
||||
self._receiver = Receiver.Receiver([self._conn])
|
||||
# Create receiver thread
|
||||
self._receiver = Receiver.Receiver(self._comm)
|
||||
self._receiver.notify.connect(self.handleState)
|
||||
self._receiver.start()
|
||||
|
||||
def _setWidget(self, widget):
|
||||
|
||||
self._gui.setCentralWidget(widget)
|
||||
|
||||
def _enableEscape(self):
|
||||
|
||||
self._is_escape = True
|
||||
@@ -137,82 +117,58 @@ class PyQt5Gui(GuiSkeleton):
|
||||
|
||||
self._is_trigger = False
|
||||
|
||||
def _sendStart(self):
|
||||
def _setWidget(self, widget):
|
||||
|
||||
self._conn.send('start')
|
||||
self._gui.setCentralWidget(widget)
|
||||
|
||||
def _sendTrigger(self, state):
|
||||
def close(self):
|
||||
|
||||
self._conn.send('triggered')
|
||||
if self._gui.close():
|
||||
self._comm.send(Workers.MASTER, TeardownEvent(TeardownEvent.EXIT))
|
||||
|
||||
def _sendAck(self):
|
||||
def teardown(self, state):
|
||||
|
||||
self._conn.send('ack')
|
||||
if state.target == TeardownEvent.EXIT:
|
||||
self._app.exit(0)
|
||||
elif state.target == TeardownEvent.RESTART:
|
||||
self._app.exit(123)
|
||||
elif state.target == TeardownEvent.WELCOME:
|
||||
self._comm.send(Workers.MASTER, GuiEvent('welcome'))
|
||||
|
||||
def _sendCancel(self):
|
||||
def showError(self, state):
|
||||
|
||||
self._conn.send('cancel')
|
||||
logging.error('%s: %s', state.title, state.message)
|
||||
|
||||
def _sendTeardown(self, state):
|
||||
MessageBox(self, MessageBox.RETRY, state.title, state.message,
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('retry')),
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('abort')))
|
||||
|
||||
self._conn.send('teardown')
|
||||
self._showWelcomeScreen()
|
||||
|
||||
def _handleKeypressEvent(self, event):
|
||||
|
||||
if self._is_escape and event.key() == QtCore.Qt.Key_Escape:
|
||||
self.handleState(GuiState.TeardownState())
|
||||
elif self._is_trigger and event.key() == QtCore.Qt.Key_Space:
|
||||
self.handleState(GuiState.TriggerState())
|
||||
|
||||
def _showWelcomeScreen(self):
|
||||
def showWelcome(self, state):
|
||||
|
||||
self._disableTrigger()
|
||||
self._disableEscape()
|
||||
self._lastHandle = self._showWelcomeScreen
|
||||
self._setWidget(Frames.Start(self._showStart, self._showSetDateTime,
|
||||
self._showSettings, self.close))
|
||||
self._setWidget(Frames.Welcome(
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('start')),
|
||||
self._showSetDateTime, self._showSettings, self.close))
|
||||
if QtWidgets.QApplication.overrideCursor() != 0:
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
|
||||
def _showSetDateTime(self):
|
||||
|
||||
self._disableTrigger()
|
||||
self._disableEscape()
|
||||
self._lastHandle = self._showSetDateTime
|
||||
self._setWidget(Frames.SetDateTime(self._showWelcomeScreen,
|
||||
self.restart))
|
||||
|
||||
def _showSettings(self):
|
||||
|
||||
# self._comm.send(Workers.MASTER, StateMachine.GuiEvent('settings'))
|
||||
|
||||
self._disableTrigger()
|
||||
self._disableEscape()
|
||||
self._lastHandle = self._showSettings
|
||||
self._setWidget(Frames.Settings(self._cfg, self._showSettings,
|
||||
self._showWelcomeScreen, self.restart))
|
||||
|
||||
def _showStart(self, state):
|
||||
|
||||
# self._comm.send(Workers.MASTER, StateMachine.GuiEvent('start'))
|
||||
def showStartup(self, state):
|
||||
|
||||
self._disableTrigger()
|
||||
self._enableEscape()
|
||||
self._lastHandle = self._showWelcomeScreen
|
||||
self._sendStart()
|
||||
self._setWidget(Frames.WaitMessage('Starting the photobooth...'))
|
||||
if self._cfg.getBool('Gui', 'hide_cursor'):
|
||||
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.BlankCursor)
|
||||
|
||||
def _showIdle(self, state):
|
||||
def showIdle(self, state):
|
||||
|
||||
self._enableEscape()
|
||||
self._enableTrigger()
|
||||
self._lastHandle = self._showIdle
|
||||
self._setWidget(Frames.IdleMessage())
|
||||
self._setWidget(Frames.IdleMessage(
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('trigger'))))
|
||||
|
||||
def _showGreeter(self, state):
|
||||
def showGreeter(self, state):
|
||||
|
||||
self._enableEscape()
|
||||
self._disableTrigger()
|
||||
@@ -221,56 +177,79 @@ class PyQt5Gui(GuiSkeleton):
|
||||
self._cfg.getInt('Picture', 'num_y'))
|
||||
greeter_time = self._cfg.getInt('Photobooth', 'greeter_time') * 1000
|
||||
|
||||
self._setWidget(Frames.GreeterMessage(*num_pic))
|
||||
QtCore.QTimer.singleShot(greeter_time, self._sendAck)
|
||||
self._setWidget(Frames.GreeterMessage(
|
||||
*num_pic,
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('countdown'))))
|
||||
QtCore.QTimer.singleShot(
|
||||
greeter_time,
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('countdown')))
|
||||
|
||||
def _showCountdown(self, state):
|
||||
def showCountdown(self, state):
|
||||
|
||||
countdown_time = self._cfg.getInt('Photobooth', 'countdown_time')
|
||||
self._setWidget(Frames.CountdownMessage(countdown_time, self._sendAck))
|
||||
self._setWidget(Frames.CountdownMessage(
|
||||
countdown_time,
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('capture'))))
|
||||
|
||||
def _showPreview(self, state):
|
||||
def updateCountdown(self, event):
|
||||
|
||||
self._gui.centralWidget().picture = ImageQt.ImageQt(state.picture)
|
||||
self._gui.centralWidget().picture = ImageQt.ImageQt(event.picture)
|
||||
self._gui.centralWidget().update()
|
||||
|
||||
def _showPose(self, state):
|
||||
def showCapture(self, state):
|
||||
|
||||
num_pic = (self._cfg.getInt('Picture', 'num_x'),
|
||||
self._cfg.getInt('Picture', 'num_y'))
|
||||
self._setWidget(Frames.PoseMessage(state.num_picture, *num_pic))
|
||||
self._setWidget(Frames.CaptureMessage(state.num_picture, *num_pic))
|
||||
|
||||
def _showAssemble(self, state):
|
||||
def showAssemble(self, state):
|
||||
|
||||
self._setWidget(Frames.WaitMessage('Processing picture...'))
|
||||
|
||||
def _showReview(self, state):
|
||||
def showReview(self, state):
|
||||
|
||||
img = ImageQt.ImageQt(state.picture)
|
||||
self._picture = ImageQt.ImageQt(state.picture)
|
||||
review_time = self._cfg.getInt('Photobooth', 'display_time') * 1000
|
||||
self._setWidget(Frames.PictureMessage(img))
|
||||
QtCore.QTimer.singleShot(review_time, lambda:
|
||||
self._showPostprocess(state.picture))
|
||||
self._setWidget(Frames.PictureMessage(self._picture))
|
||||
QtCore.QTimer.singleShot(
|
||||
review_time,
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('postprocess')))
|
||||
|
||||
def _showPostprocess(self, picture):
|
||||
def showPostprocess(self, state):
|
||||
|
||||
tasks = self._postprocess.get(picture)
|
||||
tasks = self._postprocess.get(self._picture)
|
||||
postproc_t = self._cfg.getInt('Photobooth', 'postprocess_time')
|
||||
|
||||
Frames.PostprocessMessage(self._gui.centralWidget(), tasks,
|
||||
self._sendAck, postproc_t * 1000)
|
||||
Frames.PostprocessMessage(
|
||||
self._gui.centralWidget(), tasks,
|
||||
lambda: self._comm.send(Workers.MASTER, GuiEvent('idle')),
|
||||
postproc_t * 1000)
|
||||
|
||||
def _showError(self, state):
|
||||
def _handleKeypressEvent(self, event):
|
||||
|
||||
logging.error('%s: %s', state.title, state.message)
|
||||
if self._is_escape and event.key() == QtCore.Qt.Key_Escape:
|
||||
self._comm.send(Workers.MASTER,
|
||||
TeardownEvent(TeardownEvent.WELCOME))
|
||||
elif self._is_trigger and event.key() == QtCore.Qt.Key_Space:
|
||||
self._comm.send(Workers.MASTER, GuiEvent('trigger'))
|
||||
|
||||
def exec(*handles):
|
||||
for handle in handles:
|
||||
handle()
|
||||
def _showSetDateTime(self):
|
||||
|
||||
MessageBox(self, MessageBox.RETRY, state.title, state.message,
|
||||
exec(self._sendAck, self._lastState),
|
||||
exec(self._sendCancel, self._showWelcomeScreen))
|
||||
self._disableTrigger()
|
||||
self._disableEscape()
|
||||
self._setWidget(Frames.SetDateTime(
|
||||
self.showWelcome,
|
||||
lambda: self._comm.send(Workers.MASTER,
|
||||
TeardownEvent(TeardownEvent.RESTART))))
|
||||
|
||||
def _showSettings(self):
|
||||
|
||||
self._disableTrigger()
|
||||
self._disableEscape()
|
||||
self._setWidget(Frames.Settings(
|
||||
self._cfg, self._showSettings, self.showWelcome,
|
||||
lambda: self._comm.send(Workers.MASTER,
|
||||
TeardownEvent(TeardownEvent.RESTART))))
|
||||
|
||||
|
||||
class PyQt5MainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
@@ -17,19 +17,19 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import multiprocessing as mp
|
||||
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from ...Threading import Workers
|
||||
|
||||
|
||||
class Receiver(QtCore.QThread):
|
||||
|
||||
notify = QtCore.pyqtSignal(object)
|
||||
|
||||
def __init__(self, conn):
|
||||
def __init__(self, comm):
|
||||
|
||||
super().__init__()
|
||||
self._conn = conn
|
||||
self._comm = comm
|
||||
|
||||
def handle(self, state):
|
||||
|
||||
@@ -37,11 +37,5 @@ class Receiver(QtCore.QThread):
|
||||
|
||||
def run(self):
|
||||
|
||||
while self._conn:
|
||||
for c in mp.connection.wait(self._conn):
|
||||
try:
|
||||
state = c.recv()
|
||||
except EOFError:
|
||||
break
|
||||
else:
|
||||
self.handle(state)
|
||||
for state in self._comm.iter(Workers.GUI):
|
||||
self.handle(state)
|
||||
|
||||
@@ -98,37 +98,34 @@ class CameraProcess(mp.Process):
|
||||
|
||||
class WorkerProcess(mp.Process):
|
||||
|
||||
def __init__(self, config, queue):
|
||||
def __init__(self, config, comm):
|
||||
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
|
||||
self.cfg = config
|
||||
self.queue = queue
|
||||
self.comm = comm
|
||||
|
||||
def run(self):
|
||||
|
||||
sys.exit(Worker(self.cfg, self.queue).run())
|
||||
sys.exit(Worker(self.cfg, self.comm).run())
|
||||
|
||||
|
||||
class GuiProcess(mp.Process):
|
||||
|
||||
def __init__(self, argv, config, conn, queue, communicator):
|
||||
def __init__(self, argv, config, communicator):
|
||||
|
||||
super().__init__()
|
||||
|
||||
self.argv = argv
|
||||
self.cfg = config
|
||||
self.conn = conn
|
||||
self.queue = queue
|
||||
self.comm = communicator
|
||||
|
||||
def run(self):
|
||||
|
||||
Gui = lookup_and_import(gui.modules, self.cfg.get('Gui', 'module'),
|
||||
'gui')
|
||||
sys.exit(Gui(self.argv, self.cfg, self.conn, self.queue,
|
||||
self.comm).run())
|
||||
sys.exit(Gui(self.argv, self.cfg, self.comm).run())
|
||||
|
||||
|
||||
def run(argv):
|
||||
@@ -144,8 +141,8 @@ def run(argv):
|
||||
# Create communication objects:
|
||||
# 1. We use a pipe to connect GUI and camera process
|
||||
# 2. We use a queue to feed tasks to the postprocessing process
|
||||
gui_conn, camera_conn = mp.Pipe()
|
||||
worker_queue = mp.SimpleQueue()
|
||||
# gui_conn, camera_conn = mp.Pipe()
|
||||
# worker_queue = mp.SimpleQueue()
|
||||
|
||||
# Initialize processes: We use three processes here:
|
||||
# 1. Camera processing
|
||||
@@ -154,25 +151,27 @@ def run(argv):
|
||||
camera_proc = CameraProcess(config, comm) # camera_conn, worker_queue)
|
||||
camera_proc.start()
|
||||
|
||||
worker_proc = WorkerProcess(config, worker_queue)
|
||||
worker_proc = WorkerProcess(config, comm)
|
||||
worker_proc.start()
|
||||
|
||||
gui_proc = GuiProcess(argv, config, gui_conn, worker_queue, comm)
|
||||
gui_proc = GuiProcess(argv, config, comm)
|
||||
gui_proc.start()
|
||||
|
||||
for event in comm.iter(Workers.MASTER):
|
||||
context.handleEvent(event)
|
||||
exit_code = context.handleEvent(event)
|
||||
if exit_code in (0, 123):
|
||||
break
|
||||
|
||||
# Close endpoints
|
||||
gui_conn.close()
|
||||
camera_conn.close()
|
||||
# gui_conn.close()
|
||||
# camera_conn.close()
|
||||
|
||||
# Wait for processes to finish
|
||||
gui_proc.join()
|
||||
worker_queue.put('teardown')
|
||||
# worker_queue.put('teardown')
|
||||
worker_proc.join()
|
||||
camera_proc.join(1)
|
||||
return gui_proc.exitcode
|
||||
return exit_code
|
||||
|
||||
|
||||
def main(argv):
|
||||
|
||||
Reference in New Issue
Block a user