def __init__(self, parent=None): super(ComboBoxDialog, self).__init__() self.number = 0 vbox = QVBoxLayout(self) self.combo_box = QComboBox(self) self.combo_box.activated.connect(self.onActivated) vbox.addWidget(self.combo_box) button = QPushButton() button.setText("Done") button.clicked.connect(self.buttonCallback) vbox.addWidget(button) self.setLayout(vbox)
def _create_cell_push_button(self, text, clicked_cb, icon=None): widget = QWidget() button = QPushButton() button.setText(text) if icon: button.setIcon(icon) button.clicked[bool].connect(clicked_cb) hlayout = QHBoxLayout(widget) hlayout.addWidget(button) hlayout.setAlignment(Qt.AlignCenter) hlayout.setContentsMargins(0, 0, 0, 0) widget.setLayout(hlayout) return widget
def create_button(self, name, callback=None, image_path=None, size=(128, 160), always_enabled=False): """Create a push button which the mock input device can register. :param name: Name of the button :param callback: The callback to attach to the button when pressed :param image_path: The name of the image file :param size: Default size of the button :param always_enabled: Never disable the button if it's not in possible gaits :return: A QPushButton object which contains the passed arguments """ if image_path is None: qt_button = QPushButton() text = check_string(name) qt_button.setText(text) else: qt_button = ImageButton(get_image_path(image_path)) qt_button.setObjectName(name) if always_enabled: self._always_enabled_buttons.append(name) qt_button.setEnabled(True) qt_button.setMinimumSize(QSize(*size)) qt_button.setMaximumSize(QSize(*size)) if callback: qt_button.clicked.connect(callback) return qt_button
def create_button(text, callback=None, image_path=None, size=(125, 150), visible=True, color_code='#1F1E24'): """Create a push button which the mock input device can register. :param text: Possible name of the button :param callback: The callback to attach to the button when pressed :param image_path: The name of the image file :param size: Default size of the button :param visible: Turn button invisible on the gui :param color_code: Possible background color of the button :return: A QPushButton object which contains the passed arguments """ qt_button = QPushButton() if image_path: qt_button.setStyleSheet( create_image_button_css(get_image_path(image_path))) else: text = check_string(text) qt_button.setStyleSheet(create_color_button_css(color_code)) qt_button.setText(text) qt_button.setMinimumSize(QSize(*size)) if not visible: qt_button.setVisible(False) if callback: qt_button.clicked.connect(callback) return qt_button
def __init__(self, parent=None): super(LineEditDialog, self).__init__() self.value = None vbox = QVBoxLayout(self) # combo box model = QtGui.QStandardItemModel(self) for elm in rospy.get_param_names(): model.setItem(model.rowCount(), 0, QtGui.QStandardItem(elm)) self.combo_box = QComboBox(self) self.line_edit = QLineEdit() self.combo_box.setLineEdit(self.line_edit) self.combo_box.setCompleter(QCompleter()) self.combo_box.setModel(model) self.combo_box.completer().setModel(model) self.combo_box.lineEdit().setText('') vbox.addWidget(self.combo_box) # button button = QPushButton() button.setText("Done") button.clicked.connect(self.buttonCallback) vbox.addWidget(button) self.setLayout(vbox)
class JointStatePublisherGui(QWidget): def __init__(self, title, jsp, num_rows=0): super(JointStatePublisherGui, self).__init__() font = QFont("Helvetica", 9, QFont.Bold) self.hlayout = QHBoxLayout(self) vlayout = QVBoxLayout() glayout = QGridLayout() right_l_lauout = QVBoxLayout() self.listVeiw = QListWidget() self.checkbox = [] self.value_line_edit = [] self.sliders = [] self.positions = [] self.progressbars = [] self.value_last = [] speed_max = enviromnt_conf['joint_speed'] slider_max = speed_max * 1000 position_max = enviromnt_conf['joint_max_position'] progress_max = position_max * 1000 #create joints widget for i in range(0, num_rows): if config[i][0]: g_in_g = QGridLayout() checkbox = QCheckBox(config[i][1]) checkbox.setFont(font) self.checkbox.append(checkbox) value_line_edit = QLineEdit() value_line_edit.setFont(font) value_line_edit.setText("0.0") self.value_line_edit.append(value_line_edit) display_lable = QLabel() display_lable.setFont(font) display_lable.setText("Position:") position_label = QLabel() position_label.setFont(font) position_label.setText("0.0") self.positions.append(position_label) position_progress_bar = QProgressBar() position_progress_bar.setMaximum(progress_max) position_progress_bar.setMinimum(-progress_max) position_progress_bar.setValue(0) self.progressbars.append(position_progress_bar) slider = QSlider() slider.setMaximum(slider_max) slider.setMinimum(-slider_max) slider.setOrientation(Qt.Horizontal) slider.valueChanged.connect(self.slider_value_changed) self.sliders.append(slider) g_in_g.addWidget(checkbox, 0, 0) g_in_g.addWidget(value_line_edit, 0, 1) g_in_g.addWidget(display_lable, 0, 2) g_in_g.addWidget(position_label, 0, 3) g_in_g.addWidget(slider, 1, 0, 1, 2) g_in_g.addWidget(position_progress_bar, 1, 2, 1, 2) glayout.addLayout(g_in_g, i, 0) #create v layout self.import_Btn = QPushButton('Import') self.import_Btn.setFont(font) self.import_Btn.clicked.connect(self.import_Btn_clecked) self.export_Btn = QPushButton('Export') self.export_Btn.setFont(font) self.export_Btn.clicked.connect(self.export_Btn_clicked) self.start_Btn = QPushButton("Start") self.start_Btn.setFont(font) self.start_Btn.clicked.connect(self.start_Btn_clicked) self.reset_Btn = QPushButton('Reset') self.reset_Btn.setFont(font) self.reset_Btn.clicked.connect(self.reset_Btn_clicked) self.record_Btn = QPushButton('Record') self.record_Btn.setFont(font) self.record_Btn.clicked.connect(self.record_Btn_clicked) self.replay_Btn = QPushButton('Repaly') self.replay_Btn.setFont(font) self.replay_Btn.clicked.connect(self.replay_Btn_clicked) self.delete_Btn = QPushButton("Delete") self.delete_Btn.setFont(font) self.delete_Btn.clicked.connect(self.delete_Btn_clicked) self.debug_Btn = QPushButton("Debug") self.debug_Btn.setFont(font) self.debug_Btn.clicked.connect(self.debug_Btn_clicked) vlayout.addWidget(self.import_Btn) vlayout.addWidget(self.export_Btn) vlayout.addWidget(self.start_Btn) vlayout.addWidget(self.reset_Btn) vlayout.addWidget(self.record_Btn) vlayout.addWidget(self.delete_Btn) vlayout.addWidget(self.replay_Btn) vlayout.addWidget(self.debug_Btn) self.master_url = QLineEdit("http://192.168.0.91:11311") self.master_url.setFont(font) self.master_ip = QLineEdit("192.168.0.91") self.master_ip.setFont(font) self.listVeiw.clicked.connect(self.listVeiw_clicked) self.listVeiw.currentRowChanged.connect( self.listVeiw_itemSelectionChanged) self.description = QTextEdit("") self.description.setFont(font) #self.description.setGeometry(0,100,100,500) right_l_lauout.addWidget(self.master_url) right_l_lauout.addWidget(self.master_ip) right_l_lauout.addWidget(self.listVeiw) right_l_lauout.addWidget(self.description) right_l_lauout.setStretch(0, 1) right_l_lauout.setStretch(1, 1) right_l_lauout.setStretch(2, 3) right_l_lauout.setStretch(3, 1) self.num_rows = len(self.checkbox) self.hlayout.addLayout(glayout) self.hlayout.addLayout(vlayout) self.hlayout.addLayout(right_l_lauout) self.setLayout(self.hlayout) self.callback_start = None self.callback_pause = None self.callback_record = None self.callback_reset = None self.callback_replay = None self.callback_replay_stop = None self.callback_delete = None self.callback_debug = None self.callback_import = None self.callback_export = None self.callback_list_clicked = None self.listVeiw_isClicked = False self.listVeiw_current_item = 0 self.listVeiw_len = 0 self.f = QFileDialog() def who_data_changed(self): for i in range(0, self.num_rows): value_last = self.value_line_edit[i].text() value_last = float(value_last) * 1000 value = self.sliders[i].value() if value != value_last: return i def change_line_edit(self, change_index): value = self.sliders[change_index].value() value = float(value) / 1000 value = str(value) self.value_line_edit[change_index].setText(value) def change_position_edit(self, change_index): value = self.progressbars[change_index].value() value += self.sliders[change_index].value() self.progressbars[change_index].setValue(value) self.positions[change_index].setText(str(float(value) / 1000)) def reset_speed(self, change_index): self.sliders[change_index].setValue(0) def reset_speed_all(self): for i in range(0, self.num_rows): self.reset_speed(i) def set_speed(self, index, data): self.sliders[index].setValue(data) def import_Btn_clecked(self): self.file_path = self.f.getOpenFileName(caption='Import excel data', directory='', filter='*.xlsx', initialFilter='') self.file_path = self.file_path[0] if self.callback_import: self.callback_import() pass def export_Btn_clicked(self): self.file_path = self.f.getSaveFileName(caption='Save as excel data', directory='', filter='*.xlsx', initialFilter='') self.file_path = self.file_path[0] if self.callback_export: self.callback_export() pass def set_callback_start(self, func): self.callback_start = func def start_Btn_clicked(self): if self.start_Btn.text() == "Start": if self.callback_start: self.callback_start() self.start_Btn.setText("Pause") else: if self.callback_pause: self.callback_pause() self.start_Btn.setText("Start") def reset_Btn_clicked(self): self.reset_speed_all() self.reset_postion_all() if self.callback_reset: self.callback_reset() def replay_Btn_clicked(self): if self.replay_Btn.text() == "Replay": self.replay_Btn.setText("Stop") if self.callback_replay: self.callback_replay() else: self.replay_Btn.setText("Replay") if self.callback_replay_stop: self.callback_replay_stop() def debug_Btn_clicked(self): if self.callback_debug: self.callback_debug() def record_Btn_clicked(self): self.set_postion() self.listVeiw_len += 1 if self.callback_record: self.callback_record() self.reset_speed_all() def listVeiw_itemSelectionChanged(self, index): self.listVeiw_isClicked = True self.listVeiw_current_item = index if self.callback_list_clicked: self.callback_list_clicked() def listVeiw_clicked(self, index): #print "index", index.row() if self.listVeiw_current_item != index.row(): description_text = self.description.toPlainText() #self.listVeiw.item(self.listVeiw_current_item).setData(1,"123") #print self.listVeiw.item(self.listVeiw_current_item).data self.listVeiw_isClicked = True self.listVeiw_current_item = index.row() if self.callback_list_clicked: self.callback_list_clicked() def update_listView(self): print "update", self.listVeiw_len for i in range(0, self.listVeiw_len): view = self.listVeiw.item(i) view.setText(str(i)) def get_listVeiw_current_item(self): return self.listVeiw_current_item def delete_Btn_clicked(self): if self.listVeiw_isClicked: print self.listVeiw_current_item self.listVeiw.removeItemWidget( self.listVeiw.takeItem(self.listVeiw_current_item)) self.listVeiw_len -= 1 if self.listVeiw_current_item != self.listVeiw_len: self.update_listView() if self.callback_delete: self.callback_delete() if self.listVeiw_current_item == 0: self.listVeiw_current_item = 0 else: self.listVeiw_current_item -= 1 self.listVeiw.setCurrentRow(self.listVeiw_current_item) if self.listVeiw_len == 0: self.listVeiw_isClicked = False def listView_add_item(self, index): self.listVeiw.addItem(str(index)) def listView_inset_item(self, index, label): self.listVeiw.insertItem(index, str(label)) def slider_value_changed(self, data): change_index = self.who_data_changed() self.change_line_edit(change_index) def get_speed(self): speed = [] for i in range(0, self.num_rows): value = self.sliders[i].value() value = float(value) / 1000 speed.append(value) return speed def get_position(self): position = [] for i in range(0, self.num_rows): value = self.progressbars[i].value() value += self.sliders[i].value() value = float(value) / 1000 position.append(value) return position def set_postion(self): for i in range(0, self.num_rows): self.change_position_edit(i) def set_positions(self, data): print len(data) for i in range(0, len(data)): self.progressbars[i].setValue(data[i] * 1000) self.positions[i].setText(str(data[i])) def reset_position(self, change_index): value = 0 self.progressbars[change_index].setValue(value) self.positions[change_index].setText(str(float(value) / 1000)) def reset_postion_all(self): for i in range(0, self.num_rows): self.reset_position(i)
def init_sliders(self): sliderbox = self._widget.findChild(QLayout, 'Sliders') graph_button = QPushButton() graph_button.setCheckable(True) graph_button.setText("Graph Off") graph_button.toggle() graph_button.clicked.connect(self.set_graph_state) self.graph_button = graph_button firstCol = QVBoxLayout() firstCol.addWidget(graph_button) sliderbox.addLayout(firstCol) self.sliders = [] all_rows_layout = QVBoxLayout() chan_idx = 0 for num_channels_row in self.settings['num_channels']: row_layout = QHBoxLayout() for i in range(num_channels_row): idx = chan_idx * 1 slider_group = { 'slider_p': None, 'number_p': None, 'slider_v': None, 'number_v': None, 'on_off': None } layout_cluster = QVBoxLayout() slider_cluster = QHBoxLayout() label = QLabel() label.setText("Chan. %d" % (idx + 1)) label.setAlignment(Qt.AlignCenter) layout_cluster.addWidget(label) for j in range(2): layout = QVBoxLayout() layout.setAlignment(Qt.AlignHCenter) slider = QSlider(Qt.Vertical) slider.setMinimum(0) slider.setMaximum(255) slider.setValue( self.settings['valve_offsets'][chan_idx][j]) slider.setTickPosition(QSlider.TicksRight) slider.setTickInterval(5) spinbox = QSpinBox() spinbox.setRange(0, 255) spinbox.setValue( self.settings['valve_offsets'][chan_idx][j]) slider.valueChanged.connect(spinbox.setValue) spinbox.valueChanged.connect(slider.setValue) cb_function_curr = lambda value, idx=idx: self.send_slider_value( idx, value) slider.valueChanged.connect(cb_function_curr) label = QLabel() label.setAlignment(Qt.AlignCenter) if j == 0: slider_group['slider_p'] = slider slider_group['number_p'] = spinbox label.setText("P") else: slider_group['slider_v'] = slider slider_group['number_v'] = spinbox label.setText("V") labelmax = QLabel() labelmax.setAlignment(Qt.AlignCenter) labelmax.setText("255") labelmin = QLabel() labelmin.setAlignment(Qt.AlignCenter) labelmin.setText("0") layout.addWidget(label) layout.addWidget(labelmax) layout.addWidget(slider, Qt.AlignHCenter) layout.addWidget(labelmin) layout.addWidget(spinbox, Qt.AlignHCenter) layout.setAlignment(slider, Qt.AlignHCenter) layout.setAlignment(spinbox, Qt.AlignHCenter) slider_cluster.addLayout(layout) on_button = QPushButton() on_button.setCheckable(True) on_button.setText("Off") if self.settings['channel_states'][chan_idx]: on_button.toggle() on_button.setText("On") on_button.clicked.connect( lambda state, idx=idx: self.send_channel_state(idx, state)) slider_group['on_off'] = on_button layout_cluster.addLayout(slider_cluster) layout_cluster.addWidget(on_button) row_layout.addLayout(layout_cluster) row_layout.addSpacing(20) self.sliders.append(slider_group) chan_idx += 1 all_rows_layout.addLayout(row_layout) sliderbox.addLayout(all_rows_layout)
def init_sliders(self): sliderbox = self._widget.findChild(QLayout, 'Sliders') firstCol = QVBoxLayout() graph_button = QPushButton() graph_button.setCheckable(True) graph_button.setText("Graph Off") graph_button.toggle() graph_button.clicked.connect(self.set_graph_state) reset_button = QPushButton() reset_button.setCheckable(False) reset_button.setText("Reset") reset_button.clicked.connect(self.set_reset) self.graph_button = graph_button self.reset_button = reset_button firstCol.addWidget(graph_button) firstCol.addWidget(reset_button) firstCol.setAlignment(graph_button, Qt.AlignVCenter) firstCol.setAlignment(reset_button, Qt.AlignVCenter) zero_button = QPushButton() zero_button.setCheckable(False) zero_button.setText("Set All Zero") zero_button.clicked.connect(self.set_pressure_zero) self.zero_button = zero_button firstCol.addWidget(zero_button) firstCol.setAlignment(zero_button, Qt.AlignVCenter) transition_box = QVBoxLayout() label = QLabel() label.setAlignment(Qt.AlignCenter) label.setText("Transition Time") spinbox = QDoubleSpinBox() spinbox.setMinimum(0) spinbox.setMaximum(10) spinbox.setValue(self.settings['transitions']) spinbox.setDecimals(1) spinbox.setSingleStep(0.1) spinbox.setSuffix(" sec") spinbox.valueChanged.connect(self.set_transition_value) transition_box.addWidget(label) transition_box.addWidget(spinbox) transition_box.setAlignment(label, Qt.AlignBottom) transition_box.setAlignment(spinbox, Qt.AlignTop) firstCol.addLayout(transition_box) self.sliders = [] sliderbox.addLayout(firstCol) all_rows_layout = QVBoxLayout() chan_idx = 0 for num_channels_row in self.settings['num_channels']: row_layout = QHBoxLayout() for i in range(num_channels_row): idx = chan_idx * 1 slider_group = {'slider': None, 'number': None, 'on_off': None} layout_cluster = QVBoxLayout() layout = QVBoxLayout() layout.setAlignment(Qt.AlignHCenter) slider = QSlider(Qt.Vertical) slider.setMinimum(self.settings['min_pressure'][idx] * 10.0) slider.setMaximum(self.settings['max_pressure'][idx] * 10.0) slider.setValue(0) slider.setTickPosition(QSlider.TicksRight) slider.setTickInterval(20) spinbox = QDoubleSpinBox() spinbox.setMinimum(self.settings['min_pressure'][idx]) spinbox.setMaximum(self.settings['max_pressure'][idx]) spinbox.setValue(0) spinbox.setDecimals(1) spinbox.setSingleStep(0.1) cb_function_curr = lambda value, idx=idx, slider=False: self.send_slider_value( idx, value, slider) cb_function_curr2 = lambda value, idx=idx, slider=True: self.send_slider_value( idx, value, slider) slider.valueChanged.connect(cb_function_curr2) spinbox.valueChanged.connect(cb_function_curr) labelmax = QLabel() labelmax.setAlignment(Qt.AlignCenter) labelmax.setText("%0.1f" % (self.settings['max_pressure'][idx])) labelmin = QLabel() labelmin.setAlignment(Qt.AlignCenter) labelmin.setText("%0.1f" % (self.settings['min_pressure'][idx])) layout.addWidget(labelmax) layout.addWidget(slider) layout.addWidget(labelmin) layout.addWidget(spinbox) layout.setAlignment(slider, Qt.AlignHCenter) layout.setAlignment(spinbox, Qt.AlignHCenter) label = QLabel() label.setText("Chan. %d" % (chan_idx + 1)) label.setAlignment(Qt.AlignCenter) layout_cluster.addWidget(label) layout_cluster.addLayout(layout) slider_group['slider'] = slider slider_group['number'] = spinbox on_button = QPushButton() on_button.setCheckable(True) on_button.setText("Off") if self.settings['channel_states'][idx]: on_button.toggle() on_button.setText("On") on_button.clicked.connect( lambda state, idx=idx: self.send_channel_state(idx, state)) slider_group['on_off'] = on_button layout_cluster.addWidget(on_button) row_layout.addLayout(layout_cluster) row_layout.addSpacing(20) self.sliders.append(slider_group) chan_idx += 1 all_rows_layout.addLayout(row_layout) sliderbox.addLayout(all_rows_layout)
def init_sliders(self): sliderbox = self._widget.findChild(QLayout, 'Sliders') graph_button = QPushButton() graph_button.setCheckable(True) graph_button.setText("Graph Off") graph_button.toggle() graph_button.clicked.connect(self.set_graph_state) self.graph_button = graph_button firstCol = QVBoxLayout() firstCol.addWidget(graph_button) sliderbox.addLayout(firstCol) self.sliders = [] all_rows_layout = QVBoxLayout() chan_idx = 0 for num_channels_row in self.settings['num_channels']: row_layout = QHBoxLayout() for i in range(num_channels_row): idx = chan_idx * 1 slider_group = { 'slider_p': None, 'number_p': None, 'slider_i': None, 'number_i': None, 'slider_d': None, 'number_d': None, 'on_off': None } layout_cluster = QVBoxLayout() slider_cluster = QHBoxLayout() label = QLabel() label.setText("Chan. %d" % (idx + 1)) label.setAlignment(Qt.AlignCenter) layout_cluster.addWidget(label) for j in range(3): layout = QVBoxLayout() layout.setAlignment(Qt.AlignHCenter) if j == 0: maxrange = 1.0 elif j == 1: maxrange = 10 elif j == 2: maxrange = 10 slider = QSlider(Qt.Vertical) slider.setMinimum(0) slider.setMaximum(maxrange * 100) slider.setValue(self.settings['pid_gains'][chan_idx][j] * 100) slider.setTickPosition(QSlider.TicksRight) slider.setTickInterval(maxrange / 100.0) spinbox = QDoubleSpinBox() spinbox.setMinimum(0) spinbox.setMaximum(maxrange) spinbox.setValue(self.settings['pid_gains'][chan_idx][j]) spinbox.setDecimals(2) spinbox.setSingleStep(maxrange / 100.0) cb_function_number = lambda value, idx=idx, gain_idx=j, slider=False: self.send_slider_value( idx, gain_idx, value, slider) cb_function_slider = lambda value, idx=idx, gain_idx=j, slider=True: self.send_slider_value( idx, gain_idx, value, slider) slider.valueChanged.connect(cb_function_slider) spinbox.valueChanged.connect(cb_function_number) label = QLabel() label.setAlignment(Qt.AlignCenter) if j == 0: slider_group['slider_p'] = slider slider_group['number_p'] = spinbox label.setText("P") elif j == 1: slider_group['slider_i'] = slider slider_group['number_i'] = spinbox label.setText("I") elif j == 2: slider_group['slider_d'] = slider slider_group['number_d'] = spinbox label.setText("D") labelmax = QLabel() labelmax.setAlignment(Qt.AlignCenter) labelmax.setText("%0.1f" % (maxrange)) labelmin = QLabel() labelmin.setAlignment(Qt.AlignCenter) labelmin.setText("0") layout.addWidget(label) layout.addWidget(labelmax) layout.addWidget(slider, Qt.AlignHCenter) layout.addWidget(labelmin) layout.addWidget(spinbox, Qt.AlignHCenter) layout.setAlignment(slider, Qt.AlignHCenter) layout.setAlignment(spinbox, Qt.AlignHCenter) slider_cluster.addLayout(layout) on_button = QPushButton() on_button.setCheckable(True) on_button.setText("Off") if self.settings['channel_states'][chan_idx]: on_button.toggle() on_button.setText("On") on_button.clicked.connect( lambda state, idx=idx: self.send_channel_state(idx, state)) slider_group['on_off'] = on_button layout_cluster.addLayout(slider_cluster) layout_cluster.addWidget(on_button) row_layout.addLayout(layout_cluster) row_layout.addSpacing(20) self.sliders.append(slider_group) chan_idx += 1 all_rows_layout.addLayout(row_layout) sliderbox.addLayout(all_rows_layout)
def init_sliders(self): sliderbox = self._widget.findChild(QLayout,'Sliders') firstCol = QVBoxLayout() graph_button=QPushButton() graph_button.setCheckable(True) graph_button.setText("Graph Off") graph_button.toggle() graph_button.clicked.connect(self.set_graph_state) self.graph_button = graph_button reset_button=QPushButton() reset_button.setCheckable(False) reset_button.setText("Reset") reset_button.clicked.connect(self.set_reset) self.graph_button = graph_button self.reset_button = reset_button firstCol.addWidget(graph_button) firstCol.addWidget(reset_button) firstCol.addWidget(graph_button) firstCol.setAlignment(graph_button,Qt.AlignVCenter) zero_button=QPushButton() zero_button.setCheckable(False) zero_button.setText("Set All Zero") zero_button.clicked.connect(self.set_pressure_zero) self.zero_button = zero_button firstCol.addWidget(zero_button) firstCol.setAlignment(zero_button,Qt.AlignVCenter) transition_box = QVBoxLayout() label = QLabel() label.setAlignment(Qt.AlignCenter) label.setText("Transition Time") spinbox = QDoubleSpinBox() spinbox.setMinimum(0) spinbox.setMaximum(10) spinbox.setValue(self.settings['transitions']) spinbox.setDecimals(1) spinbox.setSingleStep(0.1) spinbox.setSuffix(" sec") spinbox.valueChanged.connect(self.set_transition_value) transition_box.addWidget(label) transition_box.addWidget(spinbox) transition_box.setAlignment(label,Qt.AlignBottom) transition_box.setAlignment(spinbox,Qt.AlignTop) firstCol.addLayout(transition_box) self.sliders = [] sliderbox.addLayout(firstCol) all_rows_layout = QVBoxLayout() g_idx = 0 for row in self.settings['gui_config']: num_groups_row = len(row) row_layout = QHBoxLayout() for gr_idx, s_group in enumerate(row): g_channels = s_group['channels'] g_layout = s_group['layout'] if 'horiz' in g_layout: group_layout = QHBoxLayout() else: group_layout = QVBoxLayout() control_group = {'sliders': [], 'on_off': None} label = QLabel() label.setText("Group. %d"%(g_idx+1)) label.setAlignment(Qt.AlignCenter) group_layout.addWidget(label) for c_idx, s_idx in enumerate(g_channels): idx = s_idx*1 slider_group={'slider':None, 'number':None} layout_cluster = QVBoxLayout() labelfirst = QLabel() labelfirst.setAlignment(Qt.AlignCenter) labellast = QLabel() labellast.setAlignment(Qt.AlignCenter) layout = QVBoxLayout() if 'diff' in g_layout and c_idx == 0: sublayout=QHBoxLayout() layout.setAlignment(Qt.AlignVCenter) slider = QSlider(Qt.Horizontal) slider.setMinimum(-100) slider.setMaximum(100) slider.setValue(0) slider.setTickPosition(QSlider.TicksRight) slider.setTickInterval(20) spinbox = QDoubleSpinBox() spinbox.setMinimum(-10) spinbox.setMaximum(10) spinbox.setValue(0) spinbox.setDecimals(1) spinbox.setSingleStep(0.1) labellast.setText("%0.1f"%(10)) # These are flipped becasue of order labelfirst.setText("%0.1f"%(-10)) max_label = labellast min_label = labelfirst else: layout.setAlignment(Qt.AlignHCenter) slider = QSlider(Qt.Vertical) slider.setMinimum(self.settings['min_pressure'][idx]*10.0) slider.setMaximum(self.settings['max_pressure'][idx]*10.0) slider.setValue(0) slider.setTickPosition(QSlider.TicksRight) slider.setTickInterval(20) spinbox = QDoubleSpinBox() spinbox.setMinimum(self.settings['min_pressure'][idx]) spinbox.setMaximum(self.settings['max_pressure'][idx]) spinbox.setValue(0) spinbox.setDecimals(1) spinbox.setSingleStep(0.1) labelfirst.setText("%0.1f"%(self.settings['max_pressure'][idx])) labellast.setText("%0.1f"%(self.settings['min_pressure'][idx])) max_label = labelfirst min_label = labellast cb_function_number = lambda value, g_idx=g_idx, s_idx=c_idx, slider=False: self.send_slider_value(g_idx,s_idx,value,slider) cb_function_slider = lambda value, g_idx=g_idx, s_idx=c_idx, slider=True: self.send_slider_value(g_idx,s_idx,value,slider) slider.valueChanged.connect(cb_function_slider) spinbox.valueChanged.connect(cb_function_number) if 'diff' in g_layout and c_idx == 0: sublayout.addWidget(labelfirst) sublayout.addWidget(slider) sublayout.addWidget(labellast) layout.addWidget(spinbox) layout.addLayout(sublayout) else: layout.addWidget(labelfirst) layout.addWidget(slider) layout.addWidget(labellast) layout.addWidget(spinbox) layout.setAlignment(slider, Qt.AlignHCenter) layout.setAlignment(spinbox, Qt.AlignHCenter) layout_cluster.addLayout(layout) slider_group['slider'] = slider slider_group['number'] = spinbox slider_group['max_label'] = max_label slider_group['min_label'] = min_label control_group['sliders'].append(slider_group) group_layout.addLayout(layout_cluster) on_button=QPushButton() on_button.setCheckable(True) on_button.setText("Off") if self.settings['channel_states'][idx]: on_button.toggle() on_button.setText("On") on_button.clicked.connect(lambda state, g_idx=g_idx: self.send_channel_state(g_idx,state)) group_layout.addWidget(on_button) row_layout.addLayout(group_layout) row_layout.addSpacing(20) control_group['on_off'] = on_button self.sliders.append(control_group) g_idx+=1 all_rows_layout.addLayout(row_layout) sliderbox.addLayout(all_rows_layout)
class MetricsRefboxWidget(QWidget): status_signal = pyqtSignal(object) timeout_signal = pyqtSignal(object) result_signal = pyqtSignal(object) bagfile_signal = pyqtSignal(object) def __init__(self): super(MetricsRefboxWidget, self).__init__() self.status_signal.connect(self.update_status) self.timeout_signal.connect(self._handle_timeout) self.result_signal.connect(self.update_result) self.bagfile_signal.connect(self._update_bagfile_name) self.timer = QElapsedTimer() self.timer_interrupt = QTimer(self) self.timer_interrupt.timeout.connect(self.update_timer) self.timer_interrupt.start(100) self.metrics_refbox = metrics_refbox.MetricsRefbox( self._status_cb, self._start_cb, self._result_cb) self.trial_configs = {} self.current_benchmark = None self.current_benchmark_enum = -1 # once we receive confirmation from robot self.benchmark_running = False # once we send the start message to robot self.benchmark_started = False # set to True if we're not recording individual trials # but rather continuously recording all data (hence no timeouts) self.continuous_recording = False self.timeout = False self.stopped = False self.result_msg = None self.config_locked = True self.config = self.metrics_refbox.get_config() self.setup() self.show() def setup(self): layout = QGridLayout() # Sidebar self.benchmark_combo_box = QComboBox() for key in self.config['benchmarks'].keys(): self.benchmark_combo_box.addItem( self.config['benchmarks'][key]['name']) self.benchmark_combo_box.currentIndexChanged.connect( self._handle_benchmark_selected) self.benchmark_combo_box.setMaximumWidth(SIDEBAR_WIDTH) self.set_current_benchmark() self.team_combo_box = QComboBox() for key in self.config['teams']: self.team_combo_box.addItem(key) self.team_combo_box.setMaximumWidth(SIDEBAR_WIDTH) self.test_communication_button = QPushButton('Test communication') self.test_communication_button.clicked.connect(self._handle_test_comm) self.trial_list_widget = QListWidget() self.trial_list_widget.currentItemChanged.connect( self._handle_trial_change) self.trial_list_widget.setMaximumWidth(SIDEBAR_WIDTH) sidebar_layout = QVBoxLayout() sidebar_layout.addWidget(QLabel("Team")) sidebar_layout.addWidget(self.team_combo_box) sidebar_layout.addWidget(self.test_communication_button) sidebar_layout.addWidget(QLabel("Benchmark")) sidebar_layout.addWidget(self.benchmark_combo_box) sidebar_layout.addWidget(QLabel("Trial")) sidebar_layout.addWidget(self.trial_list_widget) self.generate_button = QPushButton('Generate') self.generate_button.clicked.connect(self._handle_generate) self.delete_button = QPushButton('Delete') self.delete_button.clicked.connect(self._handle_delete) self.save_trials_button = QPushButton('Save') self.save_trials_button.clicked.connect(self._handle_save_trial_config) self.lock_button = QPushButton('Lock') if self.config_locked: self.lock_button.setText('Unlock') self.lock_button.clicked.connect(self._handle_lock) sidebar_button_layout = QGridLayout() sidebar_button_layout.addWidget(self.generate_button, 0, 0) sidebar_button_layout.addWidget(self.delete_button, 0, 1) sidebar_button_layout.addWidget(self.save_trials_button, 1, 0) sidebar_button_layout.addWidget(self.lock_button, 1, 1) sidebar_layout.addLayout(sidebar_button_layout) layout.addLayout(sidebar_layout, 0, 0) # Status box self.status = QPlainTextEdit() self.status.setReadOnly(True) self.status.setMaximumHeight(200) # row 1, col 0, rowspan 1, colspan 2 layout.addWidget(self.status, 1, 0, 1, 2) # trial config and results trial_layout = QVBoxLayout() self.trial_config_layout = QHBoxLayout() self.trial_results_layout = QVBoxLayout() self.setup_trial_config() # benchmark trial controls benchmark_controls_group_box = QGroupBox('Controls') benchmark_controls_layout = QHBoxLayout() self.start_trial_button = QPushButton('Start') self.start_trial_button.clicked.connect(self._handle_start_trial) self.stop_trial_button = QPushButton('Stop') self.stop_trial_button.clicked.connect(self._handle_stop_trial) self.prev_trial_button = QPushButton('Previous') self.prev_trial_button.clicked.connect(self._handle_prev_trial) self.next_trial_button = QPushButton('Next') self.next_trial_button.clicked.connect(self._handle_next_trial) self.start_continuous_recording_button = QPushButton( 'Start continuous recording') self.start_continuous_recording_button.clicked.connect( self._handle_continuous_recording) self.timer_field = QLabel() font = QFont("Arial", 20, QFont.Bold) self.timer_field.setFont(font) self.timer_field.setAutoFillBackground(True) benchmark_controls_layout.addWidget(self.start_trial_button) benchmark_controls_layout.addWidget(self.stop_trial_button) benchmark_controls_layout.addWidget(self.prev_trial_button) benchmark_controls_layout.addWidget(self.next_trial_button) benchmark_controls_layout.addWidget( self.start_continuous_recording_button) benchmark_controls_layout.addWidget(self.timer_field) benchmark_controls_group_box.setLayout(benchmark_controls_layout) trial_layout.addLayout(self.trial_config_layout) trial_layout.addWidget(benchmark_controls_group_box) trial_layout.addLayout(self.trial_results_layout) self.save_results_button = QPushButton('Save results') self.save_results_button.clicked.connect(self._handle_save_result) trial_layout.addWidget(self.save_results_button) layout.addLayout(trial_layout, 0, 1) self.setLayout(layout) self.show() self.show_env_var('ROS_MASTER_URI') self.show_env_var('ROS_IP') self.show_env_var('ROS_HOSTNAME') def show_env_var(self, var): env_str = os.getenv(var) if os.getenv(var) is not None else '' msg = var + ': ' + env_str + '\n' self.update_status(msg) def set_current_benchmark(self): ''' Sets the current benchmark type based on user selection Load config file for selected benchmark and setup GUI to show config and results based on that ''' benchmark_index = self.benchmark_combo_box.currentIndex() benchmark_name = list( self.config['benchmarks'].keys())[benchmark_index] benchmark_result_type = getattr( metrics_refbox_msgs.msg, self.config['benchmarks'][benchmark_name]['type']) config_file_name = benchmark_name + '.json' config_file = os.path.join(self.metrics_refbox.get_config_file_path(), config_file_name) stream = open(config_file, 'r') benchmark_config = json.load(stream) module = importlib.import_module(benchmark_config['module']) self.current_benchmark = getattr(module, benchmark_config['class'])( benchmark_config, self.metrics_refbox.get_config_file_path(), benchmark_name, benchmark_result_type) self.current_benchmark_enum = self.config['benchmarks'][ benchmark_name]['enum'] def setup_trial_config(self): ''' set up the benchmark specific part of the GUI related to the configuration of the benchmark (for example, which objects will be used for object detection) the specific configuration is loaded based on the selected trial_index ''' for i in reversed(range(self.trial_config_layout.count())): self.trial_config_layout.itemAt(i).widget().setParent(None) for i in reversed(range(self.trial_results_layout.count())): self.trial_results_layout.itemAt(i).widget().setParent(None) self.current_benchmark.setup(self.trial_config_layout, self.trial_results_layout, self.config_locked) self.trial_list_widget.clear() self.trial_configs.clear() path = os.path.join(self.metrics_refbox.get_config_file_path(), 'trials') trial_config_file = os.path.join( path, self.current_benchmark.config['trial_config']) if os.path.exists(trial_config_file): with open(trial_config_file, "r") as fp: trial_config = json.load(fp) for key in sorted(trial_config.keys()): trial_item = QListWidgetItem(key) trial_item.setFlags(trial_item.flags() | Qt.ItemIsEditable) self.trial_list_widget.addItem(trial_item) self.trial_configs[key] = trial_config[key] self.trial_list_widget.setCurrentRow(0) def _handle_test_comm(self): ''' 'Test communication' button ''' self.metrics_refbox.test_communication() self.status_signal.emit('Sent test message to all clients\n') def _handle_benchmark_selected(self, idx): ''' benchmark selection has changed ''' self._handle_save_trial_config(None) self.set_current_benchmark() self.setup_trial_config() def _handle_trial_change(self, current_item, previous_item): ''' Trial selection has changed ''' if previous_item is not None: self.trial_configs[previous_item.text( )] = self.current_benchmark.get_current_selections() self.current_benchmark.clear_results() if current_item is not None and current_item.text( ) in self.trial_configs.keys() and self.trial_configs[ current_item.text()] is not None: self.current_benchmark.apply_selections( self.trial_configs[current_item.text()]) else: self.current_benchmark.clear_selections() def _handle_generate(self, button): ''' generate a new trial config ''' trial_config = self.current_benchmark.generate() names = [] for key in self.trial_configs.keys(): names.append(key) msg = 'Select a name for this trial configuration' text = '' while True: text, ok = QInputDialog.getText(self, 'Trial name', msg) if text not in names: break QMessageBox.critical(self, "Error", "Name exists already") if ok: trial_item = QListWidgetItem(text) trial_item.setFlags(trial_item.flags() | Qt.ItemIsEditable) self.trial_list_widget.addItem(trial_item) self.trial_configs[text] = trial_config self.trial_list_widget.setCurrentItem(trial_item) def _handle_delete(self, button): ''' delete current trial config ''' selected_items = self.trial_list_widget.selectedItems() for item in selected_items: self.trial_list_widget.takeItem(self.trial_list_widget.row(item)) del self.trial_configs[item.text()] def _handle_save_trial_config(self, button): ''' save trial config in case it has been edited ''' if self.trial_list_widget.currentItem() is not None: self.trial_configs[self.trial_list_widget.currentItem().text( )] = self.current_benchmark.get_current_selections() path = os.path.join(self.metrics_refbox.get_config_file_path(), 'trials') trial_config_file = os.path.join( path, self.current_benchmark.config['trial_config']) with open(trial_config_file, "w") as fp: json.dump(self.trial_configs, fp) def _handle_lock(self, button): ''' Lock trial config settings so they are not changed accidentally ''' if self.config_locked: self.current_benchmark.unlock_config() self.config_locked = False self.lock_button.setText('Lock') else: self.current_benchmark.lock_config() self.config_locked = True self.lock_button.setText('Unlock') def _handle_start_trial(self, button): ''' Trial start button; send command to refbox client via ROS node ''' if self.benchmark_running or self.benchmark_started: self.update_status( "Benchmark has already started. Stop and start the benchmark if you want to restart it\n" ) else: self.metrics_refbox.start( self.current_benchmark_enum, self.current_benchmark.get_task_info_for_robot()) self.benchmark_started = True self.current_benchmark.clear_results() self.update_status("Sent start command\n") self.timer_field.setText('') self.disable_buttons() def _handle_stop_trial(self, button): ''' Trial stop button ''' self.metrics_refbox.stop() self.elapsed_time = self.timer.elapsed() self.stopped = True self.benchmark_running = False self.benchmark_started = False self.status_signal.emit("Sent stop command\n") self.result_signal.emit(None) self.enable_buttons() def _handle_next_trial(self, button): ''' Select next trial ''' row = self.trial_list_widget.currentRow() if (row + 1 < self.trial_list_widget.count()): self.trial_list_widget.setCurrentRow(row + 1) def _handle_prev_trial(self, button): ''' Select previous trial ''' row = self.trial_list_widget.currentRow() if (row - 1 >= 0): self.trial_list_widget.setCurrentRow(row - 1) def _handle_continuous_recording(self, button): ''' Start recording button, not tied to any benchmark, and requires user to stop recording ''' if self.benchmark_running or self.benchmark_started: self.metrics_refbox.stop() self.elapsed_time = self.timer.elapsed() self.stopped = True self.benchmark_running = False self.benchmark_started = False self.status_signal.emit("Sent stop command\n") self.start_continuous_recording_button.setText( 'Start continuous recording') self.enable_buttons() self.stop_trial_button.setEnabled(True) self.continuous_recording = False else: self.metrics_refbox.start_recording() self.continuous_recording = True self.start_continuous_recording_button.setText('Stop recording') self.benchmark_started = True self.update_status("Sent start command\n") self.timer_field.setText('') self.disable_buttons() self.stop_trial_button.setEnabled(False) def _handle_save_result(self, button): ''' Save results again in case notes were added ''' self.result_signal.emit(self.result_msg) def _start_cb(self, msg): ''' called when we get confirmation that the robot received the start message; official start of trial time ''' if msg.data == True: self.elapsed_time = 0.0 self.timer.start() self.benchmark_running = True self.timeout = False self.stopped = False self.result_msg = None if msg.rosbag_filename == '': self.status_signal.emit( 'Error: rosbag filename not specified although start message confirmed\n' ) self._handle_stop_trial(None) return self.status_signal.emit('Started trial and recording to %s\n' % msg.rosbag_filename) self.bagfile_signal.emit(msg.rosbag_filename) else: self.status_signal.emit( 'Error: Benchmark did not start, probably because the rosbag recorder is not running\n' ) self._handle_stop_trial(None) def _result_cb(self, msg): ''' called when we get a result from the robot official end of trial time ''' if self.benchmark_running: self.elapsed_time = self.timer.elapsed() self.benchmark_running = False self.benchmark_started = False self.status_signal.emit("Trial completed in %.2f seconds\n" % (self.elapsed_time / 1000.0)) self.result_msg = msg self.result_signal.emit(msg) self.enable_buttons() def _status_cb(self, msg): ''' callback to send text to status box ''' self.status_signal.emit(msg) def update_status(self, msg): ''' signal handler for status box ''' timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') m = '[' + timestamp + '] ' + msg self.status.insertPlainText(m) self.status.ensureCursorVisible() def _update_bagfile_name(self, name): self.current_benchmark.set_bagfile_name(name) def update_result(self, msg): ''' signal handler for result message; process and save result ''' self.current_benchmark.show_results(msg, self.timeout, self.stopped) current_trial_name = self.trial_list_widget.currentItem().text() current_team_name = self.team_combo_box.currentText() results_dict = self.current_benchmark.get_trial_result_dict( msg, current_trial_name, current_team_name, self.timeout, self.stopped, self.elapsed_time / 1000.0) filename = self.current_benchmark.get_bagfile_name( )[:-4] + '_' + self.current_benchmark.benchmark_name + '.json' path = os.path.join(self.metrics_refbox.get_results_file_path(), filename) with open(path, "w") as fp: json.dump(results_dict, fp) def update_timer(self): ''' Timer callback; update GUI, and also check if timeout has expired ''' if not self.benchmark_running: return self.timer_field.setText("Time: %.1f s" % (self.timer.elapsed() / 1000.0)) # if we're in continuous recording mode, no need to check timeout if self.continuous_recording: return if self.timer.hasExpired(self.current_benchmark.get_timeout() * 1000.0): self.status_signal.emit( "Trial timeout of %.2f seconds has expired\n" % self.current_benchmark.get_timeout()) self.timeout_signal.emit('timeout expired') def _handle_timeout(self, msg): ''' timeout has expired, so stop the trial ''' self.timeout = True self._handle_stop_trial(None) def closeEvent(self, event): ''' make sure we save trial configs when window is closed ''' self.metrics_refbox.stop() self._handle_save_trial_config(None) event.accept() def disable_buttons(self): ''' disable buttons when trial is running ''' self.team_combo_box.setEnabled(False) self.benchmark_combo_box.setEnabled(False) self.trial_list_widget.setEnabled(False) self.next_trial_button.setEnabled(False) self.prev_trial_button.setEnabled(False) self.delete_button.setEnabled(False) self.generate_button.setEnabled(False) self.save_trials_button.setEnabled(False) self.lock_button.setEnabled(False) self.start_trial_button.setEnabled(False) def enable_buttons(self): self.team_combo_box.setEnabled(True) self.benchmark_combo_box.setEnabled(True) self.trial_list_widget.setEnabled(True) self.next_trial_button.setEnabled(True) self.prev_trial_button.setEnabled(True) self.delete_button.setEnabled(True) self.generate_button.setEnabled(True) self.save_trials_button.setEnabled(True) self.lock_button.setEnabled(True) self.start_trial_button.setEnabled(True)