def add_buttons_to_layout(self, layout): """Add tool buttons to layout""" # Image orientation angle_label = QLabel(_("Angle (°):")) layout.addWidget(angle_label) self.angle_combo = QComboBox(self) self.angle_combo.addItems(self.ROTATION_ANGLES) self.angle_combo.setCurrentIndex(1) self.angle_combo.currentIndexChanged.connect( lambda index: self.apply_transformation()) layout.addWidget(self.angle_combo) layout.addSpacing(10) # Image flipping flip_label = QLabel(_("Flip:")) layout.addWidget(flip_label) hflip = create_toolbutton( self, text="", icon=get_icon("hflip.png"), toggled=lambda state: self.apply_transformation(), autoraise=False) self.hflip_btn = hflip layout.addWidget(hflip) vflip = create_toolbutton( self, text="", icon=get_icon("vflip.png"), toggled=lambda state: self.apply_transformation(), autoraise=False) self.vflip_btn = vflip layout.addWidget(vflip) layout.addSpacing(15) self.add_reset_button(layout)
def __init__(self, parent, appdata): super(SessionInfos, self).__init__(parent) self.appdata = appdata self.setWindowTitle( 'Information for the session' ) self.setFixedSize(250, 300) self.buttonBox = QDialogButtonBox( self ) self.buttonBox.setOrientation( Qt.Horizontal ) self.buttonBox.setStandardButtons( QDialogButtonBox.Cancel|QDialogButtonBox.Ok ) labelcombo = QLabel( 'Breathing Zone:' ) self.breathzone = QComboBox() self.breathzone.addItem( '', '' ) self.breathzone.addItem( 'Abdominal', 1 ) self.breathzone.addItem( 'Thoracic', 2 ) self.breathzone.move(10, 10) labelnote = QLabel( 'Note:' ) self.note = QTextEdit() layout = QVBoxLayout() layout.addWidget( self.create_SessionType_Group() ) layout.addWidget( labelcombo ) layout.addWidget( self.breathzone ) layout.addWidget( labelnote ) layout.addWidget( self.note ) layout.addWidget( self.buttonBox ) self.setLayout( layout ) self.buttonBox.accepted.connect( self.accept ) self.buttonBox.rejected.connect( self.reject )
def add_buttons_to_layout(self, layout): """Add tool buttons to layout""" # Image orientation angle_label = QLabel(_("Angle (°):")) layout.addWidget(angle_label) self.angle_combo = QComboBox(self) self.angle_combo.addItems(self.ROTATION_ANGLES) self.angle_combo.setCurrentIndex(1) self.angle_combo.currentIndexChanged.connect( lambda index: self.apply_transformation()) layout.addWidget(self.angle_combo) layout.addSpacing(10) # Image flipping flip_label = QLabel(_("Flip:")) layout.addWidget(flip_label) hflip = create_toolbutton(self, text="", icon=get_icon("hflip.png"), toggled=lambda state: self.apply_transformation(), autoraise=False) self.hflip_btn = hflip layout.addWidget(hflip) vflip = create_toolbutton(self, text="", icon=get_icon("vflip.png"), toggled=lambda state: self.apply_transformation(), autoraise=False) self.vflip_btn = vflip layout.addWidget(vflip) layout.addSpacing(15) self.add_reset_button(layout)
def __init__(self, parent=None): QWidget.__init__(self, parent) self.widget_layout = QVBoxLayout() title_layout = QHBoxLayout() title_layout.addStretch() style = "<span style=\'color: #444444\'><b>%s</b></span>" title = QLabel(style % "Operations") title_layout.addWidget(title) title_layout.addStretch() self.widget_layout.addLayout(title_layout) # Create ListWidget and add 10 items to move around. self.list_widget = QListWidget() # self.list_widget.setDragDropMode(QAbstractItemView.InternalMove) self.list_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_widget.setSortingEnabled(False) self.list_widget.currentItemChanged.connect(self._populate_settings_update) self.widget_layout.addWidget(self.list_widget) otitle_layout = QHBoxLayout() otitle_layout.addStretch() otitle = QLabel(style % "Operation settings") otitle_layout.addWidget(otitle) otitle_layout.addStretch() self.widget_layout.addLayout(otitle_layout) self.operations_combo = QComboBox() self.operations_combo.currentIndexChanged.connect(self._populate_settings_add) self.widget_layout.addWidget(self.operations_combo) self.operation_settings = GenericOperationWidget() self.widget_layout.addWidget(self.operation_settings) self.toolbar = QToolBar() self.toolbar.addAction(get_icon('apply.png'), "Apply/Replace", self._change_operation) self.toolbar.addAction(get_icon('editors/edit_add.png'), "Add after", self._add_operation) self.toolbar.addAction(get_icon('trash.png'), "Remove", self._remove_operation) self.widget_layout.addWidget(self.toolbar) self.setLayout(self.widget_layout)
def __init__(self, item, parent_layout): super(ChoiceWidget, self).__init__(item, parent_layout) self.combobox = self.group = QComboBox() self.combobox.setToolTip(item.get_help()) self.__first_call = True self.store = self.item.get_prop("display", "store", None) self.combobox.currentIndexChanged.connect(self.index_changed)
class SessionInfos( QDialog ): def __init__(self, parent, appdata): super(SessionInfos, self).__init__(parent) self.appdata = appdata self.setWindowTitle( 'Information for the session' ) self.setFixedSize(250, 300) self.buttonBox = QDialogButtonBox( self ) self.buttonBox.setOrientation( Qt.Horizontal ) self.buttonBox.setStandardButtons( QDialogButtonBox.Cancel|QDialogButtonBox.Ok ) labelcombo = QLabel( 'Breathing Zone:' ) self.breathzone = QComboBox() self.breathzone.addItem( '', '' ) self.breathzone.addItem( 'Abdominal', 1 ) self.breathzone.addItem( 'Thoracic', 2 ) self.breathzone.move(10, 10) labelnote = QLabel( 'Note:' ) self.note = QTextEdit() layout = QVBoxLayout() layout.addWidget( self.create_SessionType_Group() ) layout.addWidget( labelcombo ) layout.addWidget( self.breathzone ) layout.addWidget( labelnote ) layout.addWidget( self.note ) layout.addWidget( self.buttonBox ) self.setLayout( layout ) self.buttonBox.accepted.connect( self.accept ) self.buttonBox.rejected.connect( self.reject ) # def accept(self): # print "accepted" # # def reject(self): # pass def create_SessionType_Group( self ): groupBox = QGroupBox(' Session Type' ) vbox = QVBoxLayout() self.sessiontypes = [] types = [['Unconscious', 0], ['Mindfull', 1]] for t in types: self.sessiontypes.append( QRadioButton( t[0] ) ) vbox.addWidget( self.sessiontypes[-1] ) self.sessiontypes[0].setChecked(True) vbox.addStretch(1) groupBox.setLayout(vbox) return groupBox
def __init__(self, item, parent_layout): super(ChoiceWidget, self).__init__(item, parent_layout) self._first_call = True self.is_radio = item.get_prop_value("display", "radio") self.store = self.item.get_prop("display", "store", None) if self.is_radio: self.group = QGroupBox() self.group.setToolTip(item.get_help()) self.vbox = QVBoxLayout() self.group.setLayout(self.vbox) self._buttons = [] else: self.combobox = self.group = QComboBox() self.combobox.setToolTip(item.get_help()) self.combobox.currentIndexChanged.connect(self.index_changed)
def __init__(self, parent): #super(ObjectFT, self).__init__(Qt.Vertical, parent) super().__init__(parent) self.scp = None # variable to hold oscilloscope object self.mutex = QMutex() layoutWidget = QWidget() layout = QGridLayout() layoutWidget.setLayout(layout) self.openDevBtn = QPushButton('Open Osci') # channel stuff self.measCh = QComboBox() self.chSens = QComboBox() self.triggCh = QComboBox() self.frequency = QLineEdit() self.frequency.setValidator(QIntValidator()) self.recordLen = QLineEdit() self.recordLen.setValidator(QIntValidator()) self.delay = QLineEdit() self.delay.setValidator(QDoubleValidator()) # trigger stuff self.triggLevel = QLineEdit() self.triggLevel.setToolTip( 'http://api.tiepie.com/libtiepie/0.5/triggering_scpch.html#triggering_scpch_level' ) self.triggLevel.setText( '0.5' ) # init value otherwise there's trouble with signal changing index of sensitivity self.triggLevel.setValidator(QDoubleValidator(0., 1., 3)) self.hystereses = QLineEdit() self.hystereses.setText('0.05') self.hystereses.setToolTip( 'http://api.tiepie.com/libtiepie/0.5/triggering_scpch.html#triggering_scpch_hysteresis' ) self.hystereses.setValidator(QDoubleValidator(0., 1., 3)) self.triggKind = QComboBox() # do averages self.averages = QSpinBox() self.averages.setValue(1) self.averages.setRange(1, 10000) # put layout together layout.addWidget(self.openDevBtn, 0, 0) layout.addWidget(QLabel('Measuring Ch'), 1, 0) layout.addWidget(self.measCh, 1, 1) layout.addWidget(QLabel('Ch sensitivity'), 2, 0) layout.addWidget(self.chSens, 2, 1) layout.addWidget(QLabel('Sample freq. (kHz)'), 3, 0) layout.addWidget(self.frequency, 3, 1) layout.addWidget(QLabel('Record length'), 4, 0) layout.addWidget(self.recordLen, 4, 1) layout.addWidget(QLabel('Delay'), 5, 0) layout.addWidget(self.delay, 5, 1) layout.addWidget(QLabel('Trigger Ch'), 6, 0) layout.addWidget(self.triggCh, 6, 1) layout.addWidget(QLabel('Trigger Level (%)'), 7, 0) layout.addWidget(self.triggLevel, 7, 1) layout.addWidget(QLabel('Hystereses'), 8, 0) layout.addWidget(self.hystereses, 8, 1) layout.addWidget(QLabel('Trigger kind'), 9, 0) layout.addWidget(self.triggKind, 9, 1) layout.addWidget(QLabel('Averages'), 10, 0) layout.addWidget(self.averages, 10, 1) layout.setRowStretch(11, 10) layout.setColumnStretch(2, 10) self.addWidget(layoutWidget) # connect UI to get things working self.openDevBtn.released.connect(self.openDev) self.chSens.currentIndexChanged.connect(self._changeSens) self.frequency.returnPressed.connect(self._changeFreq) self.recordLen.returnPressed.connect(self._changeRecordLength) self.triggCh.currentIndexChanged.connect(self._changeTrigCh) self.triggLevel.returnPressed.connect(self._triggLevelChanged) self.triggLevel.textChanged.connect(self._check_state) self.hystereses.returnPressed.connect(self._setHystereses) self.hystereses.textChanged.connect(self._check_state)
class TiePieUi(QSplitter): ''' Handling user interface to manage TiePie HS4/Diff Oscilloscope ''' scpConnected = Signal() xAxeChanged = Signal(object, object) yAxeChanged = Signal(object, object) triggLevelChanged = Signal(object) def __init__(self, parent): #super(ObjectFT, self).__init__(Qt.Vertical, parent) super().__init__(parent) self.scp = None # variable to hold oscilloscope object self.mutex = QMutex() layoutWidget = QWidget() layout = QGridLayout() layoutWidget.setLayout(layout) self.openDevBtn = QPushButton('Open Osci') # channel stuff self.measCh = QComboBox() self.chSens = QComboBox() self.triggCh = QComboBox() self.frequency = QLineEdit() self.frequency.setValidator(QIntValidator()) self.recordLen = QLineEdit() self.recordLen.setValidator(QIntValidator()) self.delay = QLineEdit() self.delay.setValidator(QDoubleValidator()) # trigger stuff self.triggLevel = QLineEdit() self.triggLevel.setToolTip( 'http://api.tiepie.com/libtiepie/0.5/triggering_scpch.html#triggering_scpch_level' ) self.triggLevel.setText( '0.5' ) # init value otherwise there's trouble with signal changing index of sensitivity self.triggLevel.setValidator(QDoubleValidator(0., 1., 3)) self.hystereses = QLineEdit() self.hystereses.setText('0.05') self.hystereses.setToolTip( 'http://api.tiepie.com/libtiepie/0.5/triggering_scpch.html#triggering_scpch_hysteresis' ) self.hystereses.setValidator(QDoubleValidator(0., 1., 3)) self.triggKind = QComboBox() # do averages self.averages = QSpinBox() self.averages.setValue(1) self.averages.setRange(1, 10000) # put layout together layout.addWidget(self.openDevBtn, 0, 0) layout.addWidget(QLabel('Measuring Ch'), 1, 0) layout.addWidget(self.measCh, 1, 1) layout.addWidget(QLabel('Ch sensitivity'), 2, 0) layout.addWidget(self.chSens, 2, 1) layout.addWidget(QLabel('Sample freq. (kHz)'), 3, 0) layout.addWidget(self.frequency, 3, 1) layout.addWidget(QLabel('Record length'), 4, 0) layout.addWidget(self.recordLen, 4, 1) layout.addWidget(QLabel('Delay'), 5, 0) layout.addWidget(self.delay, 5, 1) layout.addWidget(QLabel('Trigger Ch'), 6, 0) layout.addWidget(self.triggCh, 6, 1) layout.addWidget(QLabel('Trigger Level (%)'), 7, 0) layout.addWidget(self.triggLevel, 7, 1) layout.addWidget(QLabel('Hystereses'), 8, 0) layout.addWidget(self.hystereses, 8, 1) layout.addWidget(QLabel('Trigger kind'), 9, 0) layout.addWidget(self.triggKind, 9, 1) layout.addWidget(QLabel('Averages'), 10, 0) layout.addWidget(self.averages, 10, 1) layout.setRowStretch(11, 10) layout.setColumnStretch(2, 10) self.addWidget(layoutWidget) # connect UI to get things working self.openDevBtn.released.connect(self.openDev) self.chSens.currentIndexChanged.connect(self._changeSens) self.frequency.returnPressed.connect(self._changeFreq) self.recordLen.returnPressed.connect(self._changeRecordLength) self.triggCh.currentIndexChanged.connect(self._changeTrigCh) self.triggLevel.returnPressed.connect(self._triggLevelChanged) self.triggLevel.textChanged.connect(self._check_state) self.hystereses.returnPressed.connect(self._setHystereses) self.hystereses.textChanged.connect(self._check_state) def openDev(self): # search for devices libtiepie.device_list.update() # try to open an oscilloscope with block measurement support for item in libtiepie.device_list: if item.can_open(libtiepie.DEVICETYPE_OSCILLOSCOPE): self.scp = item.open_oscilloscope() if self.scp.measure_modes & libtiepie.MM_BLOCK: break else: self.scp = None # init UI #print(self.scp.name, 'found') if self.scp is not None: # Set measure mode: self.scp.measure_mode = libtiepie.MM_BLOCK # Set sample frequency: self.scp.sample_frequency = 1e6 # 1 MHz # Set record length: self.scp.record_length = 10000 # 10000 samples # Set pre sample ratio: self.scp.pre_sample_ratio = 0 # 0 % # Set trigger timeout: self.scp.trigger_time_out = 100e-3 # 100 ms # Enable channel 1 for measurement # http://api.tiepie.com/libtiepie/0.5/group__scp__ch__enabled.html self.scp.channels[ 0].enabled = True # by default all channels are enabled self.scp.range = 0.2 self.scp.coupling = libtiepie.CK_DCV # DC Volt # Disable all channel trigger sources for ch in self.scp.channels: ch.trigger.enabled = False # Setup channel trigger on 1 ch = self.scp.channels[0] ch.trigger.enabled = True ch.trigger.kind = libtiepie.TK_RISINGEDGE ch.trigger.levels[0] = 0.5 # 50% ch.trigger.hystereses[0] = 0.05 # 5% # update UI # channel self.measCh.addItems( ['Ch{:d}'.format(i) for i in range(self.scp.channels.count)]) self.chSens.addItems( ['{:.1f} V'.format(i) for i in self.scp.channels[0].ranges]) self.frequency.setValidator( QIntValidator(1, 1e-3 * self.scp.sample_frequency_max)) self.frequency.setText('{:d}'.format( int(self.scp.sample_frequency * 1e-3))) self.recordLen.setValidator( QIntValidator(1, self.scp.record_length_max)) self.recordLen.setText('{:d}'.format(self.scp.record_length)) # trigger self.triggCh.addItems( ['Ch{:d}'.format(i) for i in range(self.scp.channels.count)]) # TODO: doen't work in module anymore!! #self.triggLevel.setText(str(ch.trigger.levels[0])) #self.hystereses.setText(str(ch.trigger.hystereses[0])) self.triggKind.addItems([ '{:s}'.format(i) for i in libtiepie.trigger_kind_str( ch.trigger.kinds).split(', ') ]) self.openDevBtn.setEnabled(False) # tell the world that the scope is connected self.xAxeChanged.emit( 0, 1 / int(self.frequency.text()) * 1e-3 * int(self.recordLen.text())) self.yAxeChanged.emit(-1 * self.scp.range, self.scp.range) self.triggLevelChanged.emit(ch.trigger.levels[0] * 2 * self.scp.range - self.scp.range) self.scpConnected.emit() else: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText('No supported device found') msg.exec_() def getData(self): # function called thread for updating plot avg = int(self.averages.text()) with QMutexLocker(self.mutex): x = np.linspace( 0, 1 / self.scp.sample_frequency * self.scp.record_length, self.scp.record_length) y = np.zeros((avg, self.scp.record_length)) for i in range(avg): self.scp.start() while not self.scp.is_data_ready: time.sleep(0.01) y[i, :] = self.scp.get_data()[self.measCh.currentIndex()] return np.column_stack((x, y.mean(axis=0))) #@Slot def _changeSens(self, i): with QMutexLocker(self.mutex): yMax = self.scp.channels[0].ranges[i] self.scp.range = yMax self.yAxeChanged.emit(-1 * yMax, yMax) self.triggLevelChanged.emit( float(self.triggLevel.text()) * 2 * yMax - yMax) def _changeTrigCh(self, newTrig): print('new trigger channel', newTrig) scope = self.scp with QMutexLocker(self.mutex): # Disable all channel trigger sources for ch in scope.channels: ch.trigger.enabled = False # enable trigger on newly selected channel ch = scope.channels[newTrig] ch.trigger.enabled = True ch.trigger.kind = libtiepie.TK_RISINGEDGE ch.trigger.levels[0] = float(self.triggLevel.text()) ch.trigger.hystereses[0] = float(self.hystereses.text()) def _triggLevelChanged(self): with QMutexLocker(self.mutex): idx = self.triggCh.currentIndex() ch = self.scp.channels[idx] ch.trigger.levels[0] = float(self.triggLevel.text()) self.triggLevelChanged.emit( float(self.triggLevel.text()) * 2 * self.scp.range - self.scp.range) def _changeFreq(self): with QMutexLocker(self.mutex): self.scp.sample_frequency = int(self.frequency.text()) * 1e3 self.xAxeChanged.emit( 0, 1 / self.scp.sample_frequency * self.scp.record_length) def _changeRecordLength(self): with QMutexLocker(self.mutex): self.scp.record_length = int(self.recordLen.text()) self.xAxeChanged.emit( 0, 1 / self.scp.sample_frequency * self.scp.record_length) def _setHystereses(self): with QMutexLocker(self.mutex): self.scp.hystereses = float(self.hystereses.text()) def _check_state(self, *args, **kwargs): '''https://snorfalorpagus.net/blog/2014/08/09/validating-user-input-in-pyqt4-using-qvalidator/''' sender = self.sender() validator = sender.validator() state = validator.validate(sender.text(), 0)[0] if state == QValidator.Acceptable: color = '#FFFFFF' # green elif state == QValidator.Intermediate: color = '#fff79a' # yellow else: color = '#f6989d' # red sender.setStyleSheet('QLineEdit { background-color: %s }' % color)
class FlipRotateMixin(base.BaseTransformMixin): """Rotate & Crop mixin class, to be mixed with a class providing the get_plot method, like ImageDialog or FlipRotateWidget (see below)""" ROTATION_ANGLES = [str((i-1)*90) for i in range(4)] #------BaseTransformMixin API---------------------------------------------- def add_buttons_to_layout(self, layout): """Add tool buttons to layout""" # Image orientation angle_label = QLabel(_("Angle (°):")) layout.addWidget(angle_label) self.angle_combo = QComboBox(self) self.angle_combo.addItems(self.ROTATION_ANGLES) self.angle_combo.setCurrentIndex(1) self.angle_combo.currentIndexChanged.connect( lambda index: self.apply_transformation()) layout.addWidget(self.angle_combo) layout.addSpacing(10) # Image flipping flip_label = QLabel(_("Flip:")) layout.addWidget(flip_label) hflip = create_toolbutton(self, text="", icon=get_icon("hflip.png"), toggled=lambda state: self.apply_transformation(), autoraise=False) self.hflip_btn = hflip layout.addWidget(hflip) vflip = create_toolbutton(self, text="", icon=get_icon("vflip.png"), toggled=lambda state: self.apply_transformation(), autoraise=False) self.vflip_btn = vflip layout.addWidget(vflip) layout.addSpacing(15) self.add_reset_button(layout) def reset_transformation(self): """Reset transformation""" self.angle_combo.setCurrentIndex(1) self.hflip_btn.setChecked(False) self.vflip_btn.setChecked(False) def apply_transformation(self): """Apply transformation, e.g. crop or rotate""" angle, hflip, vflip = self.get_parameters() x, y, _a, px, py, _hf, _vf = self.item.get_transform() self.item.set_transform(x, y, angle*np.pi/180, px, py, hflip, vflip) self.get_plot().replot() def compute_transformation(self): """Compute transformation, return compute output array""" angle, hflip, vflip = self.get_parameters() data = self.item.data.copy() if hflip: data = np.fliplr(data) if vflip: data = np.flipud(data) if angle: k = int( (-angle % 360)/90 ) data = np.rot90(data, k) return data #------Public API---------------------------------------------------------- def get_parameters(self): """Return transform parameters""" angle = int(str(self.angle_combo.currentText())) hflip = self.hflip_btn.isChecked() vflip = self.vflip_btn.isChecked() return angle, hflip, vflip def set_parameters(self, angle, hflip, vflip): """Set transform parameters""" angle_index = self.ROTATION_ANGLES.index(str(angle)) self.angle_combo.setCurrentIndex(angle_index) self.hflip_btn.setChecked(hflip) self.vflip_btn.setChecked(vflip)
class FlipRotateMixin(base.BaseTransformMixin): """Rotate & Crop mixin class, to be mixed with a class providing the get_plot method, like ImageDialog or FlipRotateWidget (see below)""" ROTATION_ANGLES = [str((i - 1) * 90) for i in range(4)] #------BaseTransformMixin API---------------------------------------------- def add_buttons_to_layout(self, layout): """Add tool buttons to layout""" # Image orientation angle_label = QLabel(_("Angle (°):")) layout.addWidget(angle_label) self.angle_combo = QComboBox(self) self.angle_combo.addItems(self.ROTATION_ANGLES) self.angle_combo.setCurrentIndex(1) self.angle_combo.currentIndexChanged.connect( lambda index: self.apply_transformation()) layout.addWidget(self.angle_combo) layout.addSpacing(10) # Image flipping flip_label = QLabel(_("Flip:")) layout.addWidget(flip_label) hflip = create_toolbutton( self, text="", icon=get_icon("hflip.png"), toggled=lambda state: self.apply_transformation(), autoraise=False) self.hflip_btn = hflip layout.addWidget(hflip) vflip = create_toolbutton( self, text="", icon=get_icon("vflip.png"), toggled=lambda state: self.apply_transformation(), autoraise=False) self.vflip_btn = vflip layout.addWidget(vflip) layout.addSpacing(15) self.add_reset_button(layout) def reset_transformation(self): """Reset transformation""" self.angle_combo.setCurrentIndex(1) self.hflip_btn.setChecked(False) self.vflip_btn.setChecked(False) def apply_transformation(self): """Apply transformation, e.g. crop or rotate""" angle, hflip, vflip = self.get_parameters() x, y, _a, px, py, _hf, _vf = self.item.get_transform() self.item.set_transform(x, y, angle * np.pi / 180, px, py, hflip, vflip) self.get_plot().replot() def compute_transformation(self): """Compute transformation, return compute output array""" angle, hflip, vflip = self.get_parameters() data = self.item.data.copy() if hflip: data = np.fliplr(data) if vflip: data = np.flipud(data) if angle: k = int((-angle % 360) / 90) data = np.rot90(data, k) return data #------Public API---------------------------------------------------------- def get_parameters(self): """Return transform parameters""" angle = int(str(self.angle_combo.currentText())) hflip = self.hflip_btn.isChecked() vflip = self.vflip_btn.isChecked() return angle, hflip, vflip def set_parameters(self, angle, hflip, vflip): """Set transform parameters""" angle_index = self.ROTATION_ANGLES.index(str(angle)) self.angle_combo.setCurrentIndex(angle_index) self.hflip_btn.setChecked(hflip) self.vflip_btn.setChecked(vflip)
def __init__(self, parent): super().__init__(parent) self.camera = None self.cameraSettings = None self.aquireData = False self.directory = 'N:/4all/mpsd_drive/xtsfasta/Data' layoutWidget = QWidget() layout = QGridLayout() layoutWidget.setLayout(layout) ############### # GUI elements self.openCamBtn = QPushButton('Connect camera') self.startAquBtn = QPushButton('Start aquisiton') self.readoutSpeedCombo = QComboBox() # this really should not be hard coded but received from dll self.readoutSpeedCombo.addItems(["1 MHz", "1.8 MHz", "2.3 MHz", "2.8 MHz", "250 kHz", "500 kHz"]) self.exposureTimeSpin = QSpinBox() self.exposureTimeSpin.setRange(1, 1e6) self.exposureTimeSpin.setValue(1e3) # default exposure 1s self.exposureTimeSpin.setSingleStep(100) self.exposureTimeSpin.setSuffix(' ms') #self.exposureTimeSpin.setValidator(QIntValidator(1, 2**31)) # ms self.binningXCombo = QComboBox() self.binningXCombo.addItems(["No binning", "Binning of 2 columns", "Binning of 4 columns", "Binning of 8 columns", "Binning of 16 columns", "Binning of 32 columns", "Binning of 64 columns", "Binning of 128 columns", "Full horizontal binning"]) self.binningYCombo = QComboBox() self.binningYCombo.addItems(["No binning", "Binning of 2 lines", "Binning of 4 lines", "Binning of 8 lines", "Binning of 16 lines", "Binning of 32 lines", "Binning of 64 lines", "Binning of 128 lines", "Binning of 256 lines"]) self.temperatureSpin = QSpinBox() self.temperatureSpin.setRange(-100, 20) self.temperatureSpin.setValue(-10) self.temperatureSpin.setSuffix('°C') self.updateInterSpin = QSpinBox() self.updateInterSpin.setRange(1, 3600) self.updateInterSpin.setValue(5) self.updateInterSpin.setSuffix(' s') #self.updateInterSpin.setText("2") #self.updateInterEdit.setValidator(QIntValidator(1, 3600)) self.loi = QSpinBox() self.loi.setRange(1, 511) # one pixel less as the camera has self.deltaPixels = QSpinBox() self.deltaPixels.setRange(0, 256) self.autoSave = QCheckBox("Auto save") self.getDirectory = QPushButton('Choose Dir') self.dirPath = QLineEdit(self.directory) self.comment = QPlainTextEdit() ############## # put elements in layout layout.addWidget(self.openCamBtn, 0, 0) layout.addWidget(self.startAquBtn, 0, 1) layout.addWidget(QLabel('readout speed'), 1, 0) layout.addWidget(self.readoutSpeedCombo, 1, 1) layout.addWidget(QLabel('exposure time'), 2, 0) layout.addWidget(self.exposureTimeSpin, 2, 1) layout.addWidget(QLabel('binning X'), 3, 0) layout.addWidget(self.binningXCombo, 3, 1) layout.addWidget(QLabel('binning Y'), 4, 0) layout.addWidget(self.binningYCombo, 4, 1) layout.addWidget(QLabel('temperature'), 5, 0) layout.addWidget(self.temperatureSpin, 5, 1) layout.addWidget(QLabel('update every n-seconds'), 6, 0) layout.addWidget(self.updateInterSpin, 6, 1) layout.addWidget(QLabel('Pixel of interest'), 7, 0) layout.addWidget(self.loi, 7, 1) layout.addWidget(QLabel('Δ pixels'), 8, 0) layout.addWidget(self.deltaPixels, 8, 1) layout.addWidget(self.autoSave, 9, 1) layout.addWidget(self.getDirectory, 10, 0) layout.addWidget(self.dirPath, 10, 1) layout.addWidget(QLabel('Comment:'), 11, 0) layout.addWidget(self.comment, 12, 0, 1, 2) layout.setRowStretch(13, 10) self.addWidget(layoutWidget) ################# # connect elements for functionality self.openCamBtn.released.connect(self.__openCam) self.getDirectory.released.connect(self.__chooseDir) self.temperatureSpin.valueChanged.connect(self.__setTemperature) self.exposureTimeSpin.valueChanged.connect(self.__setCamParameter) self.readoutSpeedCombo.currentIndexChanged.connect(self.__setCamParameter) self.startAquBtn.released.connect(self.__startCurrImageThr) ################ # thread for updating position self.currImage_thread = QThread() # create the QThread self.currImage_thread.start() # This causes my_worker.run() to eventually execute in my_thread: self.currImage_worker = GenericWorker(self.__getCurrImage) self.currImage_worker.moveToThread(self.currImage_thread) self.startAquBtn.setEnabled(False) self.readoutSpeedCombo.setEnabled(False) self.exposureTimeSpin.setEnabled(False) self.binningXCombo.setEnabled(False) self.binningYCombo.setEnabled(False) self.temperatureSpin.setEnabled(False) self.updateInterSpin.setEnabled(False)
class GreatEyesUi(QSplitter): ''' Handling user interface to manage greateys cameras ''' newPlotData = Signal(object, object) message = Signal(object) def __init__(self, parent): super().__init__(parent) self.camera = None self.cameraSettings = None self.aquireData = False self.directory = 'N:/4all/mpsd_drive/xtsfasta/Data' layoutWidget = QWidget() layout = QGridLayout() layoutWidget.setLayout(layout) ############### # GUI elements self.openCamBtn = QPushButton('Connect camera') self.startAquBtn = QPushButton('Start aquisiton') self.readoutSpeedCombo = QComboBox() # this really should not be hard coded but received from dll self.readoutSpeedCombo.addItems(["1 MHz", "1.8 MHz", "2.3 MHz", "2.8 MHz", "250 kHz", "500 kHz"]) self.exposureTimeSpin = QSpinBox() self.exposureTimeSpin.setRange(1, 1e6) self.exposureTimeSpin.setValue(1e3) # default exposure 1s self.exposureTimeSpin.setSingleStep(100) self.exposureTimeSpin.setSuffix(' ms') #self.exposureTimeSpin.setValidator(QIntValidator(1, 2**31)) # ms self.binningXCombo = QComboBox() self.binningXCombo.addItems(["No binning", "Binning of 2 columns", "Binning of 4 columns", "Binning of 8 columns", "Binning of 16 columns", "Binning of 32 columns", "Binning of 64 columns", "Binning of 128 columns", "Full horizontal binning"]) self.binningYCombo = QComboBox() self.binningYCombo.addItems(["No binning", "Binning of 2 lines", "Binning of 4 lines", "Binning of 8 lines", "Binning of 16 lines", "Binning of 32 lines", "Binning of 64 lines", "Binning of 128 lines", "Binning of 256 lines"]) self.temperatureSpin = QSpinBox() self.temperatureSpin.setRange(-100, 20) self.temperatureSpin.setValue(-10) self.temperatureSpin.setSuffix('°C') self.updateInterSpin = QSpinBox() self.updateInterSpin.setRange(1, 3600) self.updateInterSpin.setValue(5) self.updateInterSpin.setSuffix(' s') #self.updateInterSpin.setText("2") #self.updateInterEdit.setValidator(QIntValidator(1, 3600)) self.loi = QSpinBox() self.loi.setRange(1, 511) # one pixel less as the camera has self.deltaPixels = QSpinBox() self.deltaPixels.setRange(0, 256) self.autoSave = QCheckBox("Auto save") self.getDirectory = QPushButton('Choose Dir') self.dirPath = QLineEdit(self.directory) self.comment = QPlainTextEdit() ############## # put elements in layout layout.addWidget(self.openCamBtn, 0, 0) layout.addWidget(self.startAquBtn, 0, 1) layout.addWidget(QLabel('readout speed'), 1, 0) layout.addWidget(self.readoutSpeedCombo, 1, 1) layout.addWidget(QLabel('exposure time'), 2, 0) layout.addWidget(self.exposureTimeSpin, 2, 1) layout.addWidget(QLabel('binning X'), 3, 0) layout.addWidget(self.binningXCombo, 3, 1) layout.addWidget(QLabel('binning Y'), 4, 0) layout.addWidget(self.binningYCombo, 4, 1) layout.addWidget(QLabel('temperature'), 5, 0) layout.addWidget(self.temperatureSpin, 5, 1) layout.addWidget(QLabel('update every n-seconds'), 6, 0) layout.addWidget(self.updateInterSpin, 6, 1) layout.addWidget(QLabel('Pixel of interest'), 7, 0) layout.addWidget(self.loi, 7, 1) layout.addWidget(QLabel('Δ pixels'), 8, 0) layout.addWidget(self.deltaPixels, 8, 1) layout.addWidget(self.autoSave, 9, 1) layout.addWidget(self.getDirectory, 10, 0) layout.addWidget(self.dirPath, 10, 1) layout.addWidget(QLabel('Comment:'), 11, 0) layout.addWidget(self.comment, 12, 0, 1, 2) layout.setRowStretch(13, 10) self.addWidget(layoutWidget) ################# # connect elements for functionality self.openCamBtn.released.connect(self.__openCam) self.getDirectory.released.connect(self.__chooseDir) self.temperatureSpin.valueChanged.connect(self.__setTemperature) self.exposureTimeSpin.valueChanged.connect(self.__setCamParameter) self.readoutSpeedCombo.currentIndexChanged.connect(self.__setCamParameter) self.startAquBtn.released.connect(self.__startCurrImageThr) ################ # thread for updating position self.currImage_thread = QThread() # create the QThread self.currImage_thread.start() # This causes my_worker.run() to eventually execute in my_thread: self.currImage_worker = GenericWorker(self.__getCurrImage) self.currImage_worker.moveToThread(self.currImage_thread) self.startAquBtn.setEnabled(False) self.readoutSpeedCombo.setEnabled(False) self.exposureTimeSpin.setEnabled(False) self.binningXCombo.setEnabled(False) self.binningYCombo.setEnabled(False) self.temperatureSpin.setEnabled(False) self.updateInterSpin.setEnabled(False) def __openCam(self): self.camera = greatEyes() if not self.camera.connected: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText('Sorry, could not connect to camera :(\n' + self.camera.status) msg.exec_() return self.openCamBtn.setText('Connected') self.message.emit('Camera connected') self.openCamBtn.setStyleSheet('QPushButton {color: green;}') self.readoutSpeedCombo.setEnabled(True) self.exposureTimeSpin.setEnabled(True) self.binningXCombo.setEnabled(False) self.binningYCombo.setEnabled(False) self.temperatureSpin.setEnabled(True) self.updateInterSpin.setEnabled(True) self.openCamBtn.setEnabled(False) self.startAquBtn.setEnabled(True) def __chooseDir(self): self.directory = QFileDialog.getExistingDirectory(self, "Choose directory", self.directory) self.dirPath.setText(self.directory) def __startCurrImageThr(self): if not self.aquireData: self.aquireData = True self.currImage_worker.start.emit() self.startAquBtn.setText('Stop aquisition') self.message.emit('Starting aqusition') else: self.__stopCurrImageThr() self.startAquBtn.setText('Start aquisition') self.message.emit('Stopping aqusition') def __stopCurrImageThr(self): self.aquireData = False #while(self.currPosThr.isRunning()): # time.sleep(0.03) def __getCurrImage(self): #from scipy import mgrid #import numpy as np #X, Y = mgrid[-256:256, -1024:1025] i = self.updateInterSpin.value() while self.aquireData: # seconds over which to record a new image imageIntervall = self.updateInterSpin.value() # sleep for n seconds to check if intervall was changed sleepy = 1 if i >= imageIntervall: # dummy image #z = np.exp(-0.5*(X**2+Y**2)/np.random.uniform(30000, 40000))*np.cos(0.1*X+0.1*Y) z = self.camera.getImage() timeStamp = datetime.datetime.now() self.cameraSettings = { 'temperature': self.camera.getTemperature(), 'exposure_time': self.exposureTimeSpin.value(), 'readout_speed': self.readoutSpeedCombo.currentText() 'time_stamp': timeStamp} self.newPlotData.emit(z, timeStamp) i = 0 # restart counter i += sleepy time.sleep(sleepy) def __setTemperature(self, temp): self.camera.setTemperture(temp) self.message.emit('Temperature set to {:d}°C'.format(temp)) def __setCamParameter(self, param): self.camera.setCameraParameter( self.readoutSpeedCombo.currentIndex(), self.exposureTimeSpin.value(), 0, 0) self.message.emit('Readout: {:s}, Exposure: {:d}, binningX: 0, binningY: 0'.format(self.readoutSpeedCombo.currentText(), self.exposureTimeSpin.value()))
class OperationsWidget(QWidget): operations_changed = QtCore.pyqtSignal() operation_changed = QtCore.pyqtSignal(dict, int) operation_added = QtCore.pyqtSignal(dict, int) def __init__(self, parent=None): QWidget.__init__(self, parent) self.widget_layout = QVBoxLayout() title_layout = QHBoxLayout() title_layout.addStretch() style = "<span style=\'color: #444444\'><b>%s</b></span>" title = QLabel(style % "Operations") title_layout.addWidget(title) title_layout.addStretch() self.widget_layout.addLayout(title_layout) # Create ListWidget and add 10 items to move around. self.list_widget = QListWidget() # self.list_widget.setDragDropMode(QAbstractItemView.InternalMove) self.list_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.list_widget.setSortingEnabled(False) self.list_widget.currentItemChanged.connect(self._populate_settings_update) self.widget_layout.addWidget(self.list_widget) otitle_layout = QHBoxLayout() otitle_layout.addStretch() otitle = QLabel(style % "Operation settings") otitle_layout.addWidget(otitle) otitle_layout.addStretch() self.widget_layout.addLayout(otitle_layout) self.operations_combo = QComboBox() self.operations_combo.currentIndexChanged.connect(self._populate_settings_add) self.widget_layout.addWidget(self.operations_combo) self.operation_settings = GenericOperationWidget() self.widget_layout.addWidget(self.operation_settings) self.toolbar = QToolBar() self.toolbar.addAction(get_icon('apply.png'), "Apply/Replace", self._change_operation) self.toolbar.addAction(get_icon('editors/edit_add.png'), "Add after", self._add_operation) self.toolbar.addAction(get_icon('trash.png'), "Remove", self._remove_operation) self.widget_layout.addWidget(self.toolbar) self.setLayout(self.widget_layout) def populate_available_operations(self, dict): """ Populate combobox with available operation names """ self.operations_combo.addItems(dict) def set_operations(self, operations_dict): """ Populate operations list with given dict of operations """ self.list_widget.clear() for op in operations_dict: self.list_widget.addItem(Operation(op)) def get_operations(self): """ Return list of operations. """ operations = [] for i in range(self.list_widget.count()): op = self.list_widget.item(i) operations.append(op._op) return operations def _remove_operation(self): self.list_widget.takeItem(self.list_widget.currentRow()) self.operations_changed.emit() def _add_operation(self): """ Add operation currently in self.operation_settings to the operation list. Signals: ======== Emits self.opeartion_added and self.operations_changed on success """ op = self.operation_settings.get_operation() current_row = self.list_widget.currentRow() self.list_widget.insertItem(current_row + 1, Operation(op)) index = self.list_widget.model().index(current_row + 1, 0) self.list_widget.setCurrentIndex(index) self.operation_added.emit(op, current_row + 1) self.operations_changed.emit() def _change_operation(self): """ Replace currently selected operation with operation in self.operation_settings (apply changed settings or replace operation). Signals: ======== Emits self.operation_changed and self.operations_changed on success """ op = self.operation_settings.get_operation() current_row = self.list_widget.currentRow() self.list_widget.takeItem(self.list_widget.currentRow()) self.list_widget.insertItem(current_row, Operation(op)) index = self.list_widget.model().index(current_row, 0) self.list_widget.setCurrentIndex(index) self.operation_changed.emit(op, current_row) self.operations_changed.emit() def _populate_settings_update(self, item): """ Fill self.operation_settings with details of currently selected operation. """ try: idx = self.operations_combo.findText(item._op["module"]) if idx >= 0: self.operations_combo.setCurrentIndex(idx) self.operation_settings.set_operation(item._op) except AttributeError: pass def _populate_settings_add(self, index): self.operation_settings.set_operation({"module": self.operations_combo.currentText()})
def __init__(self, parent=None, tdms_file=None, group_label="Data group", channel_labels=["X channel", "Y channel", "Z channel", "Z2 channel", ]): """ Params ====== twin_z : bool Allow to select two Z (data) channels group_label : str: Label text for group combo box channel_labels : list of str Label texts for channel combo boxes """ QWidget.__init__(self, parent) self.widget_layout = QVBoxLayout() self.group_widgets = [] self.channel_widgets = [] for i, label_text in enumerate([group_label] + channel_labels): label = QLabel(label_text) channel_widget = QComboBox() channel_widget.addItem(label_text) channel_widget.setMinimumWidth(250) channel_widget.setDisabled(True) group_widget = QComboBox() group_widget.addItem(label_text) group_widget.setMinimumWidth(250) group_widget.setDisabled(True) layout = QHBoxLayout() layout.addWidget(label) layout.addWidget(group_widget) if i != 0: layout.addWidget(channel_widget) self.widget_layout.addLayout(layout) if i == 0: self.group_combo = group_widget self.group_combo.currentIndexChanged.connect(self.change_sub_channels) else: self.group_widgets.append(group_widget) self.channel_widgets.append(channel_widget) group_widget.currentIndexChanged.connect(self._populate_channels) self.setLayout(self.widget_layout) self.tdms_file = tdms_file