"""
This widget contains the functionality for the experimental control. The
widget can be executed as a standalone version.
########################################
Functionalities provided in this widget:
########################################
Note:
technically the features for
this widget are provided in widget_main_window.py
1. Collect Background
2. Set number of interleaves which should be driven
3. Display the scan index, the delay index and the interleave index
4. Start and stop measurement
"""
if __name__ == "__main__":
# Add directories to path for imports
import os, sys, inspect
currentdir = os.path.dirname(
os.path.abspath(inspect.getfile(inspect.currentframe()))
)
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, os.path.join(currentdir, "ui_files"))
sys.path.insert(0, parentdir)
# PyQt imports
from PyQt5 import QtWidgets
from PyQt5.QtCore import QRunnable, QThreadPool, pyqtSignal, QObject
# Import RegEx input validators
from regex_validators import *
# Import Qt Threading wrapper
from qt_multithreading_wrapper import Worker
# Import of file made from UI designer
from ui_experiment_control import Ui_GroupBox_exp as Ui_exp
# Logger Settings
import logging
# logging.basicConfig(level=logging.INFO)
if __name__ == "__main__":
import time
import threading
# TESTING -----------------------------------------------------------
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, obj=None, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("Please god let this work")
self.groupBox_exp = WidgetExperimentControl()
self.setCentralWidget(self.groupBox_exp)
self.setup_experiment()
self.threadpool = QThreadPool()
# ------------------------ Testing activation and deactivation
def setup_experiment(self):
# Disconnect old signals before reconnecting new signals
try:
self.groupBox_exp.pushButton_toggle_meas.clicked.disconnect()
except Exception:
pass
# Change text to start accordingly
self.groupBox_exp.pushButton_toggle_meas.setText("START MEASUREMENT")
# Setup GUI activation / deactivation
self.gui_activator = GUIActivation()
if True:
# Connect Start Measurement Button to show spectrum
# experiment
self.groupBox_exp.pushButton_toggle_meas.clicked.connect(
self.pseudo_experiment
)
# Add for show spectrum relevant GUI elements to gui
# activator
self.gui_activator.add(self.groupBox_exp.pushButton_exp_background)
# * This signal and slot need to be connected in the END of
# * this function
# * Otherwise measurment will start and directly stop again.
# Connect to signal such that the button changes to a stop
# measurement button once it was clicked
self.groupBox_exp.pushButton_toggle_meas.clicked.connect(
self.set_to_stop_measurement
)
def pseudo_experiment(self):
def run(self):
self.experiment = PseudoExperiment()
self.experiment.start()
work = Worker(run, self)
# Deactivate certain elements of GUI on start
work.signals.started.connect(
lambda: self.gui_activator.toggle_activation(False)
)
self.threadpool.start(work)
def set_to_stop_measurement(self, gui_activator):
# Change Start Button to Stop Button Remove slot to start
# experiment
self.groupBox_exp.pushButton_toggle_meas.clicked.disconnect()
# and replace it with slot to stop experiment
self.groupBox_exp.pushButton_toggle_meas.clicked.connect(self.stop)
print("Stop measurement signals updated")
# Change text accordingly
self.groupBox_exp.pushButton_toggle_meas.setText("STOP MEASUREMENT")
def stop(self):
def run():
# Tell acquisition to stop
self.experiment.shutdown()
# Wait for acquisition to complete #?---------
self.experiment.join()
# Emit signal that GUI can be reactivated Reset start
# button functionality.
self.setup_experiment()
work = Worker(run)
# Hinder people from smashing the stop button
work.signals.started.connect(
lambda: self.groupBox_exp.pushButton_toggle_meas.setDisabled(True)
)
# Re-enable button once acquisition was stopped
work.signals.finished.connect(
lambda: self.groupBox_exp.pushButton_toggle_meas.setEnabled(True)
)
# Re-enable GUI elements
work.signals.finished.connect(
lambda: self.gui_activator.signals.experiment_finished.emit()
)
self.threadpool.start(work)
class PseudoExperiment(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
# Multiprocessing event to stop experiment
self.exit = threading.Event()
def run(self):
while not self.exit.is_set():
time.sleep(0.7)
print("SCAN COMPLETE")
def shutdown(self):
# Setting exit will stop the loop
# within run
self.exit.set()
class GUIActivation:
class Signals(QObject):
experiment_finished = pyqtSignal()
def __init__(self):
self.signals = self.Signals()
self.gui_elements = []
self.signals.experiment_finished.connect(
lambda: self.toggle_activation(True)
)
self.signals.experiment_finished.connect(lambda: print("GUI Reactivate!!"))
def add(self, gui_element):
self.gui_elements.append(gui_element)
def toggle_activation(self, toggle):
"""
Toggles the deactivation/ reactivation of the GUI elements
that should not be accessed during the routine.
Args:
toggle (bool): True to enable. False to disable.
"""
print("toggle activation: {}".format(toggle))
for gui_element in self.gui_elements:
gui_element.setEnabled(toggle)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()