class plotScroller: def update_val(self, proc): d=str(self.scl.value()) self.v.setText(d) if proc != None: proc(self.scl.value()) def __init__(self, master, text, geo, proc=None, lim=(0,100,1)): self.scl=QScrollBar(Qt.Horizontal, master) self.scl.resize(geo[2]-50,geo[3]) self.scl.move(geo[0]+50,geo[1]) self.scl.setMinimum(lim[0]) self.scl.setMaximum(lim[1]) self.scl.setSingleStep(lim[2]) self.scl.valueChanged.connect(lambda: self.update_val(proc)) q=QLabel(master) q.move(geo[0],geo[1]+10) q.resize(50,20) q.setText(text) self.v=QLabel(master) self.v.move(geo[2]+10,geo[1]+10) self.v.resize(50,20) self.v.setText(str(self.scl.value())) def setValue(self, v): self.scl.setValue(v)
class ObjMotorWidgetUI(QWidget): # waveforms_generated = pyqtSignal(object, object, list, int) # SignalForContourScanning = pyqtSignal(int, int, int, np.ndarray, np.ndarray) # MessageBack = pyqtSignal(str) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # os.chdir('./')# Set directory to current folder. self.setFont(QFont("Arial")) # self.setMinimumSize(1350,900) self.setWindowTitle("ObjMotorWidget") self.layout = QGridLayout(self) self.connect_status = False #************************************************************************************************************************************** #-------------------------------------------------------------------------------------------------------------------------------------- #-----------------------------------------------------------GUI for Objective Motor---------------------------------------------------- #-------------------------------------------------------------------------------------------------------------------------------------- #************************************************************************************************************************************** # Movement based on relative positions. self.ObjMotorcontrolContainer = QGroupBox("Objective motor control") self.ObjMotorcontrolContainer.setStyleSheet("QGroupBox {\ font: bold;\ border: 1px solid silver;\ border-radius: 6px;\ margin-top: 12px;\ color:Navy; \ background-color: #FFFAFA}\ QGroupBox::title{subcontrol-origin: margin;\ left: 7px;\ padding: 5px 5px 5px 5px;}") self.ObjMotorcontrolLayout = QGridLayout() self.ObjMotor_connect = StylishQT.connectButton() self.ObjMotor_connect.setFixedWidth(70) self.ObjMotorcontrolLayout.addWidget(self.ObjMotor_connect, 0, 0) self.ObjMotor_connect.clicked.connect(lambda: self.ConnectMotor()) self.ObjMotor_connect.setGraphicsEffect(QGraphicsDropShadowEffect(blurRadius=3, xOffset=2, yOffset=2)) self.ObjMotor_disconnect = StylishQT.disconnectButton() self.ObjMotor_disconnect.setFixedWidth(70) self.ObjMotor_disconnect.setGraphicsEffect(QGraphicsDropShadowEffect(blurRadius=3, xOffset=2, yOffset=2)) self.ObjMotorcontrolLayout.addWidget(self.ObjMotor_disconnect, 0, 1) self.ObjMotor_disconnect.clicked.connect(lambda: self.DisconnectMotor()) self.ObjMotor_disconnect.setEnabled(False) self.ObjMotor_upwards = QPushButton("↑") self.ObjMotor_upwards.setStyleSheet("QPushButton {color:white;background-color: teal; border-style: outset;border-radius: 10px;border-width: 2px;font: bold 14px;padding: 6px}" "QPushButton:pressed {color:red;background-color: white; border-style: outset;border-radius: 10px;border-width: 2px;font: bold 14px;padding: 6px}" "QPushButton:hover:!pressed {color:gray;background-color: teal; border-style: outset;border-radius: 10px;border-width: 2px;font: bold 14px;padding: 6px}") self.ObjMotorcontrolLayout.addWidget(self.ObjMotor_upwards, 2, 2) self.ObjMotor_upwards.clicked.connect(lambda: self.MovingMotorThread("Motor_move_upwards")) # self.ObjMotor_upwards.setShortcut('w') self.ObjMotor_down = QPushButton("↓") self.ObjMotor_down.setStyleSheet("QPushButton {color:white;background-color: teal; border-style: outset;border-radius: 10px;border-width: 2px;font: bold 14px;padding: 6px}" "QPushButton:pressed {color:red;background-color: white; border-style: outset;border-radius: 10px;border-width: 2px;font: bold 14px;padding: 6px}" "QPushButton:hover:!pressed {color:gray;background-color: teal; border-style: outset;border-radius: 10px;border-width: 2px;font: bold 14px;padding: 6px}") self.ObjMotorcontrolLayout.addWidget(self.ObjMotor_down, 3, 2) self.ObjMotor_down.clicked.connect(lambda: self.MovingMotorThread("Motor_move_downwards")) # self.stage_down.setShortcut('s') self.ObjMotor_target = QDoubleSpinBox(self) self.ObjMotor_target.setMinimum(-10000) self.ObjMotor_target.setMaximum(10000) self.ObjMotor_target.setDecimals(6) # self.ObjMotor_target.setValue(3.45) self.ObjMotor_target.setSingleStep(0.001) self.ObjMotorcontrolLayout.addWidget(self.ObjMotor_target, 1, 1) self.ObjMotorcontrolLayout.addWidget(QLabel("Target:"), 1, 0) self.ObjMotor_current_pos_Label = QLabel("Current position: ") self.ObjMotorcontrolLayout.addWidget(self.ObjMotor_current_pos_Label, 2, 0, 1, 2) self.ObjMotor_goto = QPushButton() self.ObjMotor_goto.setIcon(QIcon('./Icons/move_coord.png')) self.ObjMotor_goto.setToolTip("Move to absolute position") self.ObjMotor_goto.setStyleSheet("QPushButton {color:white;background-color: #CCFFFF;}" "QPushButton:hover:!pressed {color:white;background-color: #FFE5CC;}") self.ObjMotor_goto.setFixedWidth(35) self.ObjMotor_goto.setFixedHeight(35) self.ObjMotorcontrolLayout.addWidget(self.ObjMotor_goto, 1, 2) self.ObjMotor_goto.clicked.connect(lambda: self.MovingMotorThread("Motor_move_target")) self.ObjMotor_step = QDoubleSpinBox(self) self.ObjMotor_step.setMinimum(-10000) self.ObjMotor_step.setMaximum(10000) self.ObjMotor_step.setDecimals(6) self.ObjMotor_step.setValue(0.003) self.ObjMotor_step.setSingleStep(0.001) self.ObjMotorcontrolLayout.addWidget(self.ObjMotor_step, 3, 1) self.ObjMotorcontrolLayout.addWidget(QLabel("Step: "), 3, 0) self.FocusSlider = QScrollBar(Qt.Horizontal) self.FocusSlider.setMinimum(2500000) self.FocusSlider.setMaximum(4500000) # self.FocusSlider.setTickPosition(QSlider.TicksBothSides) # self.FocusSlider.setTickInterval(1000000) self.FocusSlider.setStyleSheet('color:white; background: lightblue') self.FocusSlider.setSingleStep(10000) # self.line640 = QLineEdit(self) # self.line640.setFixedWidth(60) # self.FocusSlider.sliderReleased.connect(lambda:self.updatelinevalue(640)) self.FocusSlider.valueChanged.connect(lambda:self.MovingMotorThread("Motor_move_slider")) self.FocusSlider.setTracking(False) # self.line640.returnPressed.connect(lambda:self.updatesider(640)) self.ObjMotorcontrolLayout.addWidget(self.FocusSlider, 4, 0, 1, 3) self.ObjMotorcontrolContainer.setLayout(self.ObjMotorcontrolLayout) self.ObjMotorcontrolContainer.setMaximumHeight(300) self.layout.addWidget(self.ObjMotorcontrolContainer, 4, 0) #************************************************************************************************************************************** #-------------------------------------------------------------------------------------------------------------------------------------- #-----------------------------------------------------------Fucs for Motor movement---------------------------------------------------- #-------------------------------------------------------------------------------------------------------------------------------------- #************************************************************************************************************************************** def ConnectMotor(self): self.ObjMotorcontrolContainer.setEnabled(False) self.ObjMotor_disconnect.setEnabled(True) self.ObjMotor_connect.setEnabled(False) self.device_instance = ConnectObj_Thread() self.device_instance.start() self.device_instance.finished.connect(self.getmotorhandle) def getmotorhandle(self): self.pi_device_instance = self.device_instance.getInstance() print('Objective motor connected.') self.connect_status = True # self.normalOutputWritten('Objective motor connected.'+'\n') self.ObjCurrentPos = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes) self.ObjMotor_current_pos_Label.setText("Current position: {:.4f}".format(self.ObjCurrentPos['1'])) # Axis here is a string. self.ObjMotor_target.setValue(self.ObjCurrentPos['1']) decimal_places = len(str(self.ObjCurrentPos['1']).split('.')[1]) print(int(self.ObjCurrentPos['1']*(10**decimal_places))) self.FocusSlider.setValue(int(self.ObjCurrentPos['1']*(10**6))) self.ObjMotorcontrolContainer.setEnabled(True) def MovingMotorThread(self, target): if target == "Motor_move_target": MoveMotorThread = threading.Thread(target = self.MoveMotor, args=('Target',)) MoveMotorThread.start() elif target == "Motor_move_upwards": MoveMotorThread = threading.Thread(target = self.MoveMotor, args=('UP',)) MoveMotorThread.start() elif target == "Motor_move_downwards": MoveMotorThread = threading.Thread(target = self.MoveMotor, args=('DOWN',)) MoveMotorThread.start() elif target == "Motor_move_slider": MoveMotorThread = threading.Thread(target = self.MoveMotor, args=('Slider',)) MoveMotorThread.start() def MoveMotor(self, direction): if direction == "Target": pos = PIMotor.move(self.pi_device_instance.pidevice, self.ObjMotor_target.value()) elif direction == "UP": self.MotorStep = self.ObjMotor_step.value() pos = PIMotor.move(self.pi_device_instance.pidevice, (self.ObjCurrentPos['1'] + self.MotorStep)) elif direction == "DOWN": self.MotorStep = self.ObjMotor_step.value() pos = PIMotor.move(self.pi_device_instance.pidevice, (self.ObjCurrentPos['1'] - self.MotorStep)) elif direction == "Slider": pos = PIMotor.move(self.pi_device_instance.pidevice, self.FocusSlider.value()/1000000) self.ObjCurrentPos = self.pi_device_instance.pidevice.qPOS(self.pi_device_instance.pidevice.axes) self.ObjMotor_current_pos_Label.setText("Current position: {:.4f}".format(self.ObjCurrentPos['1'])) # Axis here is a string. self.ObjMotor_target.setValue(self.ObjCurrentPos['1']) # decimal_places = len(str(self.ObjCurrentPos['1']).split('.')[1]) self.FocusSlider.setValue(int(self.ObjCurrentPos['1']*(10**6))) def DisconnectMotor(self): self.ObjMotor_connect.setEnabled(True) self.ObjMotor_disconnect.setEnabled(False) PIMotor.CloseMotorConnection(self.pi_device_instance.pidevice) print('Disconnected') self.connect_status = False # self.normalOutputWritten('Objective motor disconnected.'+'\n') def closeEvent(self, event): # ## Because the software combines both PyQt and PyQtGraph, using the # ## closeEvent() from PyQt will cause a segmentation fault. Calling # ## also the exit() from PyQtGraph solves this problem. # pg.exit() if self.connect_status == True: self.DisconnectMotor() QtWidgets.QApplication.quit() event.accept()
class Slider(QWidget): def __init__(self, parent, name): super().__init__(parent) self.name = name self.layout = QHBoxLayout(self) self.setLayout(self.layout) self.slider = QScrollBar(self) self.spin_box = QDoubleSpinBox(self) self.spin_box.setMaximumWidth(70) self.layout.addWidget(self.slider) self.layout.addWidget(self.spin_box) self.slider.setOrientation(QtCore.Qt.Horizontal) self.slider.setPageStep(1) self._slider_mult = 1 self._spin_val = QtPropertyVar(self.spin_box, 'value') self._slider_val = QtPropertyVar(self.slider, 'value') self._var = None self.set_from_value = None self._step = None self._min = None self._max = None self.var = Var(name='var') def _uses_integer(self): return isinstance(self._slider_mult, int) @reactive def _set_all_to(self, value): #print("set all to ", value) if self._min is not None and self._max is not None and self._min > self._max: set_if_inequal(self._var, None) return if self._uses_integer() and value is not None: value = int(round(value)) set_if_inequal(self._slider_val, value * self._slider_mult) set_if_inequal(self._spin_val, value) set_if_inequal(self._var, value) @property def var(self): return self._var @var.setter def var(self, var): with ScopedName(name=self.name): self._var = var if var is not None else Var(name='var') self.set_from_value = volatile(self._set_all_to(self._var)) def set_params(self, min, max, step=1): self._step = step self._min = min self._max = max if isinstance(min, float) or isinstance(max, float) or isinstance( step, float): self._slider_mult = 1.0 / step self.spin_box.setDecimals(int(ceil(-log10(step)))) else: self._slider_mult = 1 self.spin_box.setDecimals(0) self.slider.setRange(int(min * self._slider_mult), int(max * self._slider_mult)) self.slider.setSingleStep(int(step * self._slider_mult)) self.spin_box.setRange(min, max) self.spin_box.setSingleStep(step) with ScopedName(name=self.name): self.refs = [ volatile(self._set_all_to(self._spin_val)), volatile(self._set_all_to(self._slider_val / self._slider_mult)) ] val = unwrap_def(self._var, None) self.fix_value(max, min, val) def fix_value(self, max, min, val): if min > max: new_val = None elif val is None: new_val = min elif val > max: new_val = max elif val < min: new_val = min else: return set_if_inequal(self._var, new_val) def dump_state(self): return dict( # min=self._min, # max=self._max, # step=self._step, value=unwrap(self._var)) def load_state(self, state: dict): # self.set_params(state['min'], state['max'], state['step']) value = state['value'] if self._uses_integer() and value is not None: value = int(round(value)) self._var.set(value)
class MainWindow(MainWindowBase, MainWindowUI): VIDEOS = ('front_video_file', 'eyes_video_file') def __init__(self, manager, parent=None): MainWindowBase.__init__(self, parent) self.manager = manager self.current_segment = None self.current_video = 0 self.nav_hide_empty = True self.setupUi(self) self.setupConnections() def setupUi(self, parent): MainWindowUI.setupUi(self, parent) # content area layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.content.setLayout(layout) # add video widget self.contentWidget = VideoWidget() self.content.layout().addWidget(self.contentWidget) self.prev_code = 'def f(img):\n return img' self.te_code = PyCodeEdit() self.te_code.setPlainText(self.prev_code) self.content.layout().addWidget(self.te_code) # footer area layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.footer.setLayout(layout) self.bar_index = QScrollBar(Qt.Horizontal) self.bar_index.setFocusPolicy(Qt.WheelFocus) self.bar_index.setMinimum(0) self.bar_index.setSingleStep(1) self.bar_index.valueChanged.connect(self.indexChanged) layout.addWidget(self.bar_index) self.info = QLabel() layout.addWidget(self.info) # construct navigation tree self.refreshNavigation() # design the view self.treeView.header().hide() # hide header self.treeView.expandToDepth(0) # expand first level def setupConnections(self): # shortcuts self.sc_next = QShortcut(QKeySequence("Right"), self) self.sc_next.activated.connect(self.nextImage) self.sc_prev = QShortcut(QKeySequence("Left"), self) self.sc_prev.activated.connect(self.prevImage) self.treeView.doubleClicked.connect(self.navigation_doubleClicked) self.pb_video_toggle.clicked.connect(self.toggleVideo) self.pb_hide_toggle.clicked.connect(self.toggleHideEmpty) def toggleVideo(self): self.current_video = (self.current_video + 1) % len(MainWindow.VIDEOS) self.setSegment(self.current_segment) def toggleHideEmpty(self): self.nav_hide_empty = not self.nav_hide_empty self.refreshNavigation() def refreshNavigation(self): items = [] for project_id in self.manager.getProjectNames(): project = self.manager.getProject(project_id) p_node = NavigationNode(project.info['Name']) p_node.obj_data = project items.append(p_node) for r_id in sorted(p_node.obj_data.getRecordingNames()): print(r_id) recording = p_node.obj_data.getRecording(r_id) print(recording) if recording: r_node = NavigationNode(r_id) r_node.obj_data = recording p_node.addChild(r_node) for segment_id in r_node.obj_data.getSegmentIDs(): s_node = NavigationNode(segment_id) s_node.obj_data = r_node.obj_data.getSegment( segment_id) r_node.addChild(s_node) self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows) self.treeView.setUniformRowHeights(True) self.treeView.setModel(NavigationModel(items)) def navigation_doubleClicked(self, _): item = self.treeView.selectedIndexes()[0] obj = item.internalPointer().obj_data if hasattr(obj, 'segments') and obj.segments_data: obj = obj.segments_data[0] if hasattr(obj, 'eyes_video_file'): self.setSegment(obj) def applyCode(self): code = self.te_code.toPlainText() if self.prev_code != code: try: exec(code, globals(), locals()) self.contentWidget.onImage = locals()['f'] except Exception as e: print(e) def prevImage(self): self.bar_index.setValue(self.bar_index.value() - 1) def nextImage(self): self.bar_index.setValue(self.bar_index.value() + 1) def setVideo(self, path): self.contentWidget.openVideo(path) self.bar_index.setMaximum(self.contentWidget.video.length) def indexChanged(self, value): self.applyCode() video = self.contentWidget.video video.pos_frame = value self.contentWidget.updateImage() info_msg = [] info_msg.append('FPS: %s' % video.fps) info_msg.append('Frame: %d / %d (%.4f)' % (video.pos_frame + 1, video.length, video.pos_msec)) self.info.setText('\n'.join(info_msg)) def setSegment(self, segment): try: self.current_segment = segment self.setVideo( getattr(self.current_segment, MainWindow.VIDEOS[self.current_video])) self.bar_index.setValue(0) self.indexChanged(0) except: pass