class _Execute(QtCore.QThread): sig_error = QtCore.pyqtSignal(str) sig_update_row_color = QtCore.pyqtSignal(str, int) sig_highlight_row = QtCore.pyqtSignal(int) sig_update_reply = QtCore.pyqtSignal(int, str) sig_show_execute_icon = QtCore.pyqtSignal() def __init__(self, parent): QtCore.QThread.__init__(self) self.parent = parent self._error = False def run(self): if self._error: return for index, action, delay, message in self.parent._command_list: if self._error or self.parent._abort_execution: self.sig_show_execute_icon.emit() break self.sig_highlight_row.emit(index) try: if action == 'read': if delay > 0: time.sleep(delay) reply = self.parent._conn.read() elif action == 'write': num_bytes = self.parent._conn.write(message) reply = '<sent {} bytes>'.format(num_bytes) elif action == 'query': reply = self.parent._conn.query(message, delay) elif action == 'delay': time.sleep(delay) reply = '' else: assert False, 'Method "{}" not implemented'.format(action) self.sig_update_reply.emit(index, reply.strip()) except Exception: self._error = True self.sig_error.emit('Row {}: {}({})\n\n{}'.format( index + 1, action, message, traceback.format_exc())) break finally: self.sig_update_row_color.emit(action, index)
class _Settings(QtWidgets.QDialog): sig_update_jog_tooltip = QtCore.pyqtSignal() def __init__(self, parent): """Display a QDialog to edit the settings""" super(_Settings, self).__init__(flags=QtCore.Qt.WindowCloseButtonHint) self.conn = parent._connection info = self.conn.get_hardware_info() self.setWindowTitle( info.modelNumber.decode('utf-8') + ' || ' + info.notes.decode('utf-8')) # move info max_vel, max_acc = self.conn.get_motor_velocity_limits() vel, acc = self.conn.get_vel_params() vel = self.conn.get_real_value_from_device_unit(vel, UnitType.VELOCITY) acc = self.conn.get_real_value_from_device_unit( acc, UnitType.ACCELERATION) backlash = self.conn.get_real_value_from_device_unit( self.conn.get_backlash(), UnitType.DISTANCE) # move widgets self.acc_spinbox = QtWidgets.QDoubleSpinBox() self.acc_spinbox.setMinimum(0) self.acc_spinbox.setMaximum(max_acc) self.acc_spinbox.setValue(acc) self.acc_spinbox.setToolTip( '<html><b>Range:</b><br>0 - {} mm/s<sup>2</sup></html>'.format( max_acc)) self.vel_spinbox = QtWidgets.QDoubleSpinBox() self.vel_spinbox.setMinimum(0) self.vel_spinbox.setMaximum(max_vel) self.vel_spinbox.setValue(vel) self.vel_spinbox.setToolTip( '<html><b>Range:</b><br>0 - {} mm/s</html>'.format(max_vel)) self.backlash_spinbox = QtWidgets.QDoubleSpinBox() self.backlash_spinbox.setMinimum(0) self.backlash_spinbox.setMaximum(5) self.backlash_spinbox.setValue(backlash) self.backlash_spinbox.setToolTip( '<html><b>Range:</b><br>0 - 5 mm</html>') move_group = QtWidgets.QGroupBox('Move Parameters') move_grid = QtWidgets.QGridLayout() move_grid.addWidget(QtWidgets.QLabel('Backlash'), 0, 0, alignment=QtCore.Qt.AlignRight) move_grid.addWidget(self.backlash_spinbox, 0, 1) move_grid.addWidget(QtWidgets.QLabel('mm'), 0, 2, alignment=QtCore.Qt.AlignLeft) move_grid.addWidget(QtWidgets.QLabel('Maximum Velocity'), 1, 0, alignment=QtCore.Qt.AlignRight) move_grid.addWidget(self.vel_spinbox, 1, 1) move_grid.addWidget(QtWidgets.QLabel('mm/s'), 1, 2, alignment=QtCore.Qt.AlignLeft) move_grid.addWidget(QtWidgets.QLabel('Acceleration'), 2, 0, alignment=QtCore.Qt.AlignRight) move_grid.addWidget(self.acc_spinbox, 2, 1) move_grid.addWidget(QtWidgets.QLabel('mm/s<sup>2</sup>'), 2, 2, alignment=QtCore.Qt.AlignLeft) move_group.setLayout(move_grid) # jog info jog_size = self.conn.get_real_value_from_device_unit( self.conn.get_jog_step_size(), UnitType.DISTANCE) vel, acc = self.conn.get_jog_vel_params() jog_vel = self.conn.get_real_value_from_device_unit( vel, UnitType.VELOCITY) jog_acc = self.conn.get_real_value_from_device_unit( acc, UnitType.ACCELERATION) # jog widgets min_jog, max_jog = 0.002, parent._max_pos_mm / 2.0 self.jog_size_spinbox = QtWidgets.QDoubleSpinBox() self.jog_size_spinbox.setMinimum(min_jog) self.jog_size_spinbox.setMaximum(max_jog) self.jog_size_spinbox.setDecimals(3) self.jog_size_spinbox.setValue(jog_size) self.jog_size_spinbox.setToolTip( '<html><b>Range:</b><br>{} - {} mm</html>'.format( min_jog, max_jog)) self.jog_acc_spinbox = QtWidgets.QDoubleSpinBox() self.jog_acc_spinbox.setMinimum(0) self.jog_acc_spinbox.setMaximum(max_acc) self.jog_acc_spinbox.setValue(jog_acc) self.jog_acc_spinbox.setToolTip( '<html><b>Range:</b><br>0 - {} mm/s<sup>2</sup></html>'.format( max_acc)) self.jog_vel_spinbox = QtWidgets.QDoubleSpinBox() self.jog_vel_spinbox.setMinimum(0) self.jog_vel_spinbox.setMaximum(max_vel) self.jog_vel_spinbox.setValue(jog_vel) self.jog_vel_spinbox.setToolTip( '<html><b>Range:</b><br>0 - {} mm/s</html>'.format(max_vel)) jog_group = QtWidgets.QGroupBox('Jog Parameters') jog_grid = QtWidgets.QGridLayout() jog_grid.addWidget(QtWidgets.QLabel('Step Size'), 0, 0, alignment=QtCore.Qt.AlignRight) jog_grid.addWidget(self.jog_size_spinbox, 0, 1) jog_grid.addWidget(QtWidgets.QLabel('mm'), 0, 2, alignment=QtCore.Qt.AlignLeft) jog_grid.addWidget(QtWidgets.QLabel('Maximum Velocity'), 1, 0, alignment=QtCore.Qt.AlignRight) jog_grid.addWidget(self.jog_vel_spinbox, 1, 1) jog_grid.addWidget(QtWidgets.QLabel('mm/s'), 1, 2, alignment=QtCore.Qt.AlignLeft) jog_grid.addWidget(QtWidgets.QLabel('Acceleration'), 2, 0, alignment=QtCore.Qt.AlignRight) jog_grid.addWidget(self.jog_acc_spinbox, 2, 1) jog_grid.addWidget(QtWidgets.QLabel('mm/s<sup>2</sup>'), 2, 2, alignment=QtCore.Qt.AlignLeft) jog_group.setLayout(jog_grid) hbox = QtWidgets.QHBoxLayout() hbox.addWidget(move_group) hbox.addWidget(jog_group) update_button = QtWidgets.QPushButton('Update') update_button.setToolTip('Update the device settings') update_button.clicked.connect(self.update_settings) cancel_button = QtWidgets.QPushButton('Cancel') cancel_button.setToolTip('Update the device settings') cancel_button.clicked.connect(self.close) info_button = QtWidgets.QPushButton() info_button.setIcon(get_icon('imageres|109')) info_button.clicked.connect( lambda: show_hardware_info(parent._connection)) info_button.setToolTip('Display the hardware information') button_layout = QtWidgets.QGridLayout() button_layout.addWidget(cancel_button, 0, 0) button_layout.addItem( QtWidgets.QSpacerItem(1, 1, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding), 0, 1) button_layout.addWidget(update_button, 0, 2) button_layout.addWidget(info_button, 0, 3) vbox = QtWidgets.QVBoxLayout() vbox.addLayout(hbox) vbox.addLayout(button_layout) self.setLayout(vbox) def update_settings(self): vel = self.conn.get_device_unit_from_real_value( self.vel_spinbox.value(), UnitType.VELOCITY) acc = self.conn.get_device_unit_from_real_value( self.acc_spinbox.value(), UnitType.ACCELERATION) self.conn.set_vel_params(vel, acc) backlash = self.conn.get_device_unit_from_real_value( self.backlash_spinbox.value(), UnitType.DISTANCE) self.conn.set_backlash(backlash) jog_vel = self.conn.get_device_unit_from_real_value( self.jog_vel_spinbox.value(), UnitType.VELOCITY) jog_acc = self.conn.get_device_unit_from_real_value( self.jog_acc_spinbox.value(), UnitType.ACCELERATION) self.conn.set_jog_vel_params(jog_vel, jog_acc) jog_size = self.conn.get_device_unit_from_real_value( self.jog_size_spinbox.value(), UnitType.DISTANCE) self.conn.set_jog_step_size(jog_size) self.sig_update_jog_tooltip.emit() self.close()
class _Signaler(QtCore.QObject): """Used for sending a signal of the current position.""" signal = QtCore.pyqtSignal()
class _Tree(QtWidgets.QTreeWidget): sig_selected = QtCore.pyqtSignal(str) def __init__(self, equipment_table, connection_table): """A Tree view of the options to use as filters for the devices.""" super(_Tree, self).__init__() # configure the super class self.setColumnCount(1) self.header().close() self.header().setStretchLastSection(False) self.header().setSectionResizeMode( QtWidgets.QHeaderView.ResizeToContents) self.itemDoubleClicked.connect(self._item_clicked) self.equipment_table = equipment_table self.connection_table = connection_table self.skip_names = ('Alias', 'Asset Number', 'Description', 'Latest Report Number', 'Model', 'Serial') self.rename_map = {'Date Calibrated': 'Year Calibrated'} self.create_top_level() def create_top_level(self): top_level_names = [] for name in self.equipment_table.header: if name in self.skip_names: continue if name in self.rename_map: name = self.rename_map[name] top_level_names.append(name) top_level_names.extend(['Backend', 'Interface']) # for ConnectionRecord's for item in sorted(top_level_names): QtWidgets.QTreeWidgetItem(self, [item]) def populate_tree(self): self.clear() self.create_top_level() for index in range(self.topLevelItemCount()): item = self.topLevelItem(index) name = item.text(0) if name == 'Manufacturer': values = {} for record in self.equipment_table.records_all: if record.manufacturer and record.manufacturer not in values: values[record.manufacturer] = [record.model] else: if record.model and record.model not in values[ record.manufacturer]: values[record.manufacturer].append(record.model) item.setText(0, name + ' ({})'.format(len(values))) for manufacturer in sorted(values): model_item = QtWidgets.QTreeWidgetItem( item, [manufacturer]) for model in sorted(values[manufacturer]): QtWidgets.QTreeWidgetItem(model_item, [model]) elif name == 'Year Calibrated': years = [] for record in self.equipment_table.records_all: year = record.date_calibrated.year if year > 1 and year not in years: years.append(year) item.setText(0, name + ' ({})'.format(len(years))) for year in sorted(years)[::-1]: QtWidgets.QTreeWidgetItem(item, [str(year)]) elif name == 'Connection': bools = {'True': 0, 'False': 0} for record in self.equipment_table.records_all: bools[str(record.connection is not None)] += 1 item.setText(0, name + ' (2)') for key in sorted(bools): QtWidgets.QTreeWidgetItem(item, [key]) elif name == 'Calibration Cycle': cycles = [] for record in self.equipment_table.records_all: if record.calibration_cycle == 0: continue if int(record.calibration_cycle ) == record.calibration_cycle: cycle = int(record.calibration_cycle) else: cycle = record.calibration_cycle if cycle not in cycles: cycles.append(cycle) item.setText(0, name + ' ({})'.format(len(cycles))) for c in sorted(cycles): QtWidgets.QTreeWidgetItem(item, [str(c)]) else: if name == 'Backend' or name == 'Interface': values = self._get_distinct_connection_records(name) else: values = self._get_distinct_equipment_records(name) item.setText(0, name + ' ({})'.format(len(values))) for value in sorted(values): QtWidgets.QTreeWidgetItem(item, [value]) def _get_distinct_equipment_records(self, name): out = [] attrib = name.lower().replace(' ', '_') for record in self.equipment_table.records_all: value = u'{}'.format(getattr(record, attrib)) if value and value not in out: out.append(value) return out def _get_distinct_connection_records(self, name): out = [] attrib = name.lower().replace(' ', '_') for record in self.connection_table.records_all: value = getattr(record, attrib).name if value and value not in out: out.append(value) return out def _item_clicked(self, item, column): num_parents = 0 parent = item.parent() while parent is not None: parent = parent.parent() num_parents += 1 if num_parents == 0: # then a top-level item was clicked return if num_parents == 1: attrib_name = item.parent().text(column).split( ' (')[column].lower().replace(' ', '_') text = u'{}={}'.format(attrib_name, item.text(column)) else: attrib_name = item.parent().parent().text(column).split( ' (')[column].lower().replace(' ', '_') text = u'{}={}, model={}'.format(attrib_name, item.parent().text(column), item.text(column)) self.sig_selected.emit(text)