Source code for gui.widget_experiment_control

"""
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)


[docs]class WidgetExperimentControl(QtWidgets.QGroupBox, Ui_exp):
[docs] class Signals(QObject): new_scan = pyqtSignal(str) new_delay = pyqtSignal(str) new_interleave = pyqtSignal(str)
def __init__(self, *args, obj=None, **kwargs): super(QtWidgets.QGroupBox, self).__init__(*args, **kwargs) self.setupUi(self) # Create Signals instance self.signals = self.Signals() # Setting input validators ----------------------------- Line # Edits Interleave self.lineEdit_exp_interleave.setValidator( positive_int_with_0_input_validator ) # Assign input validator to this lineEdit # Connect Signals self.signals.new_scan.connect(lambda info: self.lineEdit_scan_idx.setText(info)) self.signals.new_delay.connect( lambda info: self.lineEdit_delay_idx.setText(info) ) self.signals.new_interleave.connect( lambda info: self.lineEdit_exp_interleave_idx.setText(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()