def __init__(self, context, pub, human_pub, pub_processed_inputs, record_pub, pub_end_motion): super(MainWindow, self).__init__() rp = rospkg.RosPack() ui_file = os.path.join(rp.get_path('rqt_franka'), 'resource', 'main.ui') loadUi(ui_file, self) self.pub = pub self.human_pub = human_pub self.pub_processed_inputs = pub_processed_inputs self.record_pub = record_pub self.pub_end_motion = pub_end_motion self.active = False self.kb_interface = RdfManager() self.add_skill() self.windows.setCurrentIndex(0) btn = Button("Send command", self.handle_send_command_clicked) vbox = QVBoxLayout() vbox.addWidget(btn) self.command_actions.setLayout(vbox) self.teach_button.clicked.connect(self.handle_teach_clicked) self.step_done_button.clicked.connect(self.handle_done_clicked) self.execute_button.clicked.connect(lambda: self.handle_execute_clicked("Assemble", "Tool")) self.skill_tree.clicked.connect(self.handle_action_clicked)
def __init__(self, updater, config, nodename): """ :param config: :type config: Dictionary? defined in dynamic_reconfigure.client.Client :type nodename: str """ super(GroupWidget, self).__init__() self.state = config['state'] self.param_name = config['name'] self._toplevel_treenode_name = nodename # TODO: .ui file needs to be back into usage in later phase. # ui_file = os.path.join(rp.get_path('rqt_reconfigure'), # 'resource', 'singlenode_parameditor.ui') # loadUi(ui_file, self) verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(QMargins(0, 0, 0, 0)) _widget_nodeheader = QWidget() _h_layout_nodeheader = QHBoxLayout(_widget_nodeheader) _h_layout_nodeheader.setContentsMargins(QMargins(0, 0, 0, 0)) self.nodename_qlabel = QLabel(self) font = QFont('Trebuchet MS, Bold') font.setUnderline(True) font.setBold(True) # Button to close a node. _icon_disable_node = QIcon.fromTheme('window-close') _bt_disable_node = QPushButton(_icon_disable_node, '', self) _bt_disable_node.setToolTip('Hide this node') _bt_disable_node_size = QSize(36, 24) _bt_disable_node.setFixedSize(_bt_disable_node_size) _bt_disable_node.pressed.connect(self._node_disable_bt_clicked) _h_layout_nodeheader.addWidget(self.nodename_qlabel) _h_layout_nodeheader.addWidget(_bt_disable_node) self.nodename_qlabel.setAlignment(Qt.AlignCenter) font.setPointSize(10) self.nodename_qlabel.setFont(font) grid_widget = QWidget(self) self.grid = QFormLayout(grid_widget) verticalLayout.addWidget(_widget_nodeheader) verticalLayout.addWidget(grid_widget, 1) # Again, these UI operation above needs to happen in .ui file. self.tab_bar = None # Every group can have one tab bar self.tab_bar_shown = False self.updater = updater self.editor_widgets = [] self._param_names = [] self._create_node_widgets(config) logging.debug('Groups node name={}'.format(nodename)) self.nodename_qlabel.setText(nodename)
def __init__(self, parent=None): super(PlotWidget, self).__init__(parent) # create widgets self.canvas = PlotCanvas() vbox = QVBoxLayout() vbox.addWidget(self.canvas) self.setLayout(vbox)
def __init__(self): super(StringLabelWidget, self).__init__() self.lock = Lock() vbox = QVBoxLayout(self) self.label = QLabel() self.label.setAlignment(Qt.AlignLeft) self.label.setSizePolicy( QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)) font = QFont("Helvetica", 14) self.label.setFont(font) self.label.setWordWrap(True) vbox.addWidget(self.label) self.string_sub = None self._string_topics = [] self._update_topic_timer = QTimer(self) self._update_topic_timer.timeout.connect(self.updateTopics) self._update_topic_timer.start(1000) self._active_topic = None # to update label visualization self._dialog = LineEditDialog() self._rosdata = None self._start_time = rospy.get_time() self._update_label_timer = QTimer(self) self._update_label_timer.timeout.connect(self.updateLabel) self._update_label_timer.start(40)
class PID_Tuner(Plugin): ''' PID tunning widget for the velocity and steering PID controllers. ''' def __init__(self, context): ''' Initialie the PID tuner Parameters: N/A Returns: N/A ''' #Initialize with qt_gui plugin for ros super(PID_Tuner, self).__init__(context) self.layout = QVBoxLayout() self._widget = QWidget() self._widget.setLayout(self.layout) #Import a generic pid tunning widget for each pid controller self.velocity_pid_tuner_widget = PID_Tuner_Generic_Widget() self.steering_pid_tuner_widget = PID_Tuner_Generic_Widget() self.pid_tuner_widgets = [ self.velocity_pid_tuner_widget, self.steering_pid_tuner_widget ] #Add button for sending the gains self.update_gains_btn = QPushButton("Update Gains") self.update_gains_btn.clicked.connect(self._update_gains) #Add the pid tuners to a layout for pid_tuner_widget in self.pid_tuner_widgets: self.layout.addWidget(pid_tuner_widget) self.layout.addWidget(self.update_gains_btn) context.add_widget(self._widget) def _update_gains(self): ''' Update the PID gains on the robot by sending them to the robot through the service. Parameters: N/A Returns: N/A ''' vel_k_p = self.velocity_pid_tuner_widget.k_p vel_k_i = self.velocity_pid_tuner_widget.k_i vel_k_d = self.velocity_pid_tuner_widget.k_d steer_k_p = self.steering_pid_tuner_widget.k_p steer_k_i = self.steering_pid_tuner_widget.k_i steer_k_d = self.steering_pid_tuner_widget.k_d update_pid_gains = rospy.ServiceProxy('smile/update_pid_gains', pid_gains) update_pid_gains(vel_k_p, vel_k_i, vel_k_d, steer_k_p, steer_k_i, steer_k_d)
def __init__(self, parent=None, current_values=None): super(BlacklistDialog, self).__init__(parent) self.setWindowTitle("Blacklist") vbox = QVBoxLayout() self.setLayout(vbox) self._blacklist = Blacklist() if isinstance(current_values, list): for val in current_values: self._blacklist.append(val) vbox.addWidget(self._blacklist) controls_layout = QHBoxLayout() add_button = QPushButton(icon=QIcon.fromTheme('list-add')) rem_button = QPushButton(icon=QIcon.fromTheme('list-remove')) ok_button = QPushButton("Ok") cancel_button = QPushButton("Cancel") add_button.clicked.connect(self._add_item) rem_button.clicked.connect(self._remove_item) ok_button.clicked.connect(self.accept) cancel_button.clicked.connect(self.reject) controls_layout.addWidget(add_button) controls_layout.addWidget(rem_button) controls_layout.addStretch(0) controls_layout.addWidget(ok_button) controls_layout.addWidget(cancel_button) vbox.addLayout(controls_layout)
def __init__(self, node): super(Network, self).__init__() layout = QVBoxLayout(self) self.static_canvas = FigureCanvas(Figure(figsize=(5, 3))) layout.addWidget(self.static_canvas) self.ax = self.static_canvas.figure.subplots() self.ax.axis('off') # t = np.linspace(0, 10, 501) # self.ax.plot(t, np.sin(t), ".") # # Create QWidget # # ui_file = os.path.join(rospkg.RosPack().get_path('rqt_dot'), 'resource', 'rqt_dot.ui') # _, package_path = get_resource('packages', 'rqt_dot') # ui_file = os.path.join(package_path, 'share', 'rqt_dot', 'resource', 'rqt_dot.ui') # loadUi(ui_file, self, {'DotWidget':DotWidget}) # self.setObjectName('ROSDot') # # self.refreshButton.clicked[bool].connect(self._handle_refresh_clicked) # self.saveButton.clicked[bool].connect(self._handle_save_button_clicked) # # # flag used to zoom out to fit graph the first time it's received # self.first_time_graph_received = True # # to store the graph msg received in callback, later on is used to save the graph if needed # self.graph = None self.topic_name = 'graph_string' self._node = node self._node.create_subscription(String, self.topic_name, self.ReceivedCallback, 10)
def __init__(self): super(ImageView2Widget, self).__init__() self.left_button_clicked = False self.repaint_trigger.connect(self.redraw) self.lock = Lock() self.need_to_rewrite = False self.bridge = CvBridge() self.image_sub = None self.event_pub = None self.label = ScaledLabel() self.label.setAlignment(Qt.AlignCenter) self.label.setSizePolicy( QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)) # self.label.installEventFilter(self) vbox = QVBoxLayout(self) vbox.addWidget(self.label) self.setLayout(vbox) self._image_topics = [] self._update_topic_thread = Thread(target=self.updateTopics) self._update_topic_thread.start() self._active_topic = None self.setMouseTracking(True) self.label.setMouseTracking(True) self._dialog = ComboBoxDialog() self.show()
def __init__(self, parent=None): super(MatPlot2D, self).__init__(parent) self._canvas = MatPlot2D.Canvas() self._toolbar = NavigationToolbar(self._canvas, self._canvas) vbox = QVBoxLayout() vbox.addWidget(self._toolbar) vbox.addWidget(self._canvas) self.setLayout(vbox)
def __init__(self, context): super(SpectrogramPlugin, self).__init__(context) self.setObjectName('Spectrogram') sns.set(style="whitegrid", palette="bright", color_codes=True) self._widget = QWidget() layout = QVBoxLayout() self._widget.setLayout(layout) layout_ = QHBoxLayout() self.lbl_topic = QLabel('Topic:') layout_.addWidget(self.lbl_topic) self.le_topic = QLineEdit() layout_.addWidget(self.le_topic) self.apply_topic = QPushButton("Apply") self.apply_topic.clicked.connect(self.apply_clicked_topic) layout_.addWidget(self.apply_topic) layout.addLayout(layout_) layout_ = QHBoxLayout() self.lbl_lcf = QLabel('Low-cut Freq.[Hz]:') layout_.addWidget(self.lbl_lcf) self.spb_lcf = QSpinBox() self.spb_lcf.setRange(0, 50) self.spb_lcf.setValue(0) layout_.addWidget(self.spb_lcf) self.apply_lcf = QPushButton("Apply") self.apply_lcf.clicked.connect(self.apply_clicked_lcf) layout_.addWidget(self.apply_lcf) layout.addLayout(layout_) layout_ = QHBoxLayout() self.lbl_hcf = QLabel('High-cut Freq.[Hz]:') layout_.addWidget(self.lbl_hcf) self.spb_hcf = QSpinBox() self.spb_hcf.setRange(50, self.vib_freq / 2) self.spb_hcf.setValue(self.vib_freq / 2) layout_.addWidget(self.spb_hcf) self.apply_hcf = QPushButton("Apply") self.apply_hcf.clicked.connect(self.apply_clicked_hcf) layout_.addWidget(self.apply_hcf) layout.addLayout(layout_) #self.fig, self.axes = plt.subplots(2, 1, sharex=True) self.fig = plt.figure() self.ax = self.fig.add_subplot(1, 1, 1) self.canvas = FigureCanvas(self.fig) self.fig.tight_layout() layout.addWidget(self.canvas) context.add_widget(self._widget) self.update_signal.connect(self.update_spectrogram) self.subscriber_signal.connect(self.update_subscriber) self.subscriber_signal.emit('spectrum')
class PlotDialogWidget(QDialog): newPlotData = QtCore.Signal(object, object) def __init__(self, bagFiles, parent=None): super(PlotDialogWidget, self).__init__() self.parent = parent self.bagFiles = bagFiles self.setWindowTitle("Add new Graph") self.layout = QVBoxLayout() self.resize(600, 400) # init the components self.tabWidget = QTabWidget() self.rawDataTab = RawDataTab(bagFiles, self) self.compareTab = CompareDataTab(bagFiles, self) self.diffTab = DiffTab(bagFiles, self) self.tabWidget.addTab(self.rawDataTab, "Raw Data Graphs") self.tabWidget.addTab(self.compareTab, "Evaluation Graphs") self.tabWidget.addTab(self.diffTab, "Difference Graphs") self.layout.addWidget(self.tabWidget) # init the start button startBtn = QPushButton("Start") startBtn.clicked.connect(self.startPressed) self.layout.addWidget(startBtn) self.setLayout(self.layout) def startPressed(self): ''' is called when the start button is clicked calls the function to get the data to plot dependent on what tab is selected ''' currentTab = self.tabWidget.currentIndex() try: if currentTab == 0: # rawDataTab is active plotData, plotInfo = self.rawDataTab.getPlotData() elif currentTab == 1: # plotData, plotInfo = self.compareTab.getPlotData() elif currentTab == 2: plotData, plotInfo = self.diffTab.getPlotData() # emit signal with data self.newPlotData.emit(plotData, plotInfo) # close dialog self.close() except Exception as e: msg_box = QMessageBox(QMessageBox.Critical, 'Error', str(e)) msg_box.exec_()
def __init__(self, parent=None): super(MatDataPlot, self).__init__(parent) self._canvas = MatDataPlot.Canvas() self._toolbar = NavigationToolbar(self._canvas, self._canvas) vbox = QVBoxLayout() vbox.addWidget(self._toolbar) vbox.addWidget(self._canvas) self.setLayout(vbox) self._curves = {} self._current_vline = None self._canvas.mpl_connect('button_release_event', self._limits_changed)
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 __init__(self, parent=None): super(BagWidget, self).__init__() self.parent = parent # create elements self.bagSelector1 = BagSelector('ground truth bag file') self.bagSelector2 = BagSelector('camera data bag file') # layout layout = QVBoxLayout() layout.addWidget(self.bagSelector1) layout.addWidget(self.bagSelector2) self.setLayout(layout)
def __init__(self, parent=None): super(PyQtGraphDataPlot, self).__init__(parent) self._plot_widget = PlotWidget() self._plot_widget.getPlotItem().addLegend() self._plot_widget.setBackground((255, 255, 255)) self._plot_widget.setXRange(0, 10, padding=0) vbox = QVBoxLayout() vbox.addWidget(self._plot_widget) self.setLayout(vbox) self._plot_widget.getPlotItem().sigRangeChanged.connect(self.limits_changed) self._curves = {} self._current_vline = None
def setup_group_frame(self, group): layout = QVBoxLayout() # grid for buttons for named targets grid = QGridLayout() grid.setSpacing(1) self.button_group = QButtonGroup(self) row = 0 column = 0 named_targets = self.get_named_targets(group) for target in named_targets: button = QPushButton(target) self.button_group.addButton(button) grid.addWidget(button, row, column) column += 1 if column >= self.MAX_COLUMNS: row += 1 column = 0 self.button_group.buttonClicked.connect(self._handle_button_clicked) # grid for show joint value and move arm buttons/text field joint_values_grid = QGridLayout() joint_values_grid.setSpacing(1) button_show_joint_values = QPushButton('Current Joint Values') button_show_joint_values.clicked[bool].connect( self._handle_show_joint_values_clicked) line_edit = QLineEdit() self.text_joint_values.append(line_edit) button_move_to = QPushButton('Move to') button_move_to.clicked[bool].connect(self._handle_move_to_clicked) joint_values_grid.addWidget(button_show_joint_values, 0, 1) joint_values_grid.addWidget(line_edit, 0, 2) joint_values_grid.addWidget(button_move_to, 0, 3) layout.addLayout(grid) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout.addWidget(line) layout.addLayout(joint_values_grid) frame = QFrame() frame.setLayout(layout) return frame
def add_item_to_conversation_view(self, msg, type=0): label_msg = QLabel(msg) label_msg.setWordWrap(True) label_msg.setStyleSheet('font-size:10pt;') inner_text_layout = QHBoxLayout() horizonalSpacer1 = QSpacerItem(0, 0, QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) if type == 0: inner_text_layout.addWidget(label_msg) inner_text_layout.addItem(horizonalSpacer1) elif type == 1: inner_text_layout.addItem(horizonalSpacer1) inner_text_layout.addWidget(label_msg) inner_layout = QVBoxLayout() time_msg = QLabel(str(time.asctime(time.localtime(time.time())))) time_msg.setStyleSheet('font-size:8pt;') inner_layout.addItem(inner_text_layout) inner_layout.addWidget(time_msg) inner_layout.setSizeConstraint(QLayout.SetFixedSize) outer_layout = QHBoxLayout() horizonalSpacer2 = QSpacerItem(0, 0, QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) if type == 0: label_msg.setStyleSheet( 'background: #e5e5ea; padding: 6px; border-radius: 8px;') time_msg.setAlignment(Qt.AlignLeft) outer_layout.addItem(inner_layout) outer_layout.addItem(horizonalSpacer2) elif type == 1: label_msg.setStyleSheet( 'background: #1d86f4; padding: 6px; border-radius: 8px; color:#fff;' ) time_msg.setAlignment(Qt.AlignRight) outer_layout.addItem(horizonalSpacer2) outer_layout.addItem(inner_layout) outer_layout.setSizeConstraint(QLayout.SetMinimumSize) widget = QWidget() widget.setLayout(outer_layout) widget.resize(widget.sizeHint()) item = QListWidgetItem() item.setSizeHint(widget.sizeHint()) self._widget.listWidget.addItem(item) self._widget.listWidget.setItemWidget(item, widget) self._widget.listWidget.scrollToBottom()
def __init__(self, node): super(StateWidget, self).__init__() layout = QVBoxLayout(self) self.static_canvas = FigureCanvas(Figure(figsize=(5, 3))) layout.addWidget(self.static_canvas) self.state_truth = [[], []] self.state_estimate = [[], []] self.state_estimate_means = [[], []] self.state_estimate_stddevs = [[], []] self.state_prediction = [[], []] self.state_prediction_stddevs = [[], []] self.state_prediction_means = [[], []] self.estimate_types = [] self.ax = self.static_canvas.figure.subplots(2, 1) for ax in self.ax: ax.set_xlim(0, 50) ax.set_ylim(-0.1, 4.1) ax.legend() ax.set_yticks([0, 2.5, 5]) ax.set_yticklabels(['0%', '50%', '100%']) ax.set_xlabel('Time') ax.grid() self.ax[0].set_ylabel('Component 1 State') self.ax[1].set_ylabel('Component 2 State') # t = np.linspace(0, 10, 501) # self.ax.plot(t, np.sin(t), ".") # # Create QWidget # # ui_file = os.path.join(rospkg.RosPack().get_path('rqt_dot'), 'resource', 'rqt_dot.ui') # _, package_path = get_resource('packages', 'rqt_dot') # ui_file = os.path.join(package_path, 'share', 'rqt_dot', 'resource', 'rqt_dot.ui') # loadUi(ui_file, self, {'DotWidget':DotWidget}) # self.setObjectName('ROSDot') # # self.refreshButton.clicked[bool].connect(self._handle_refresh_clicked) # self.saveButton.clicked[bool].connect(self._handle_save_button_clicked) # # # flag used to zoom out to fit graph the first time it's received # self.first_time_graph_received = True # # to store the graph msg received in callback, later on is used to save the graph if needed # self.graph = None self._node = node self._node.create_subscription(StateList, 'state_estimate', self.ReceivedEstimateCallback, 10) self._node.create_subscription(StateList, 'state_truth', self.ReceivedTruthCallback, 10)
def add_buttons(self, colors): vbx = QVBoxLayout() i = 1 for color in colors: but = QPushButton('Color {} ({})'.format(color, i)) but.clicked.connect(self.clicked(color)) but_short = QShortcut(QKeySequence("Ctrl+" + str(i)), self) but_short.activated.connect(self.clicked(color)) i += 1 vbx.addWidget(but) vbx.addStretch(1) self.color_buttons.setLayout(vbx)
class ThresholdSetter(QGroupBox): def __init__(self, parent=None): super(ThresholdSetter, self).__init__() self.parent = parent self.setTitle('Select IoU Threshold ') self.layout = QVBoxLayout() self.spinBox = QDoubleSpinBox() self.spinBox.setDecimals(2) self.spinBox.setMaximum(1.0) self.spinBox.setSingleStep(0.1) self.spinBox.setValue(0.5) self.layout.addWidget(self.spinBox) self.setLayout(self.layout) def getThreshold(self): return self.spinBox.value()
def __init__(self, node): super(ControlWidget, self).__init__() layout = QVBoxLayout(self) self.static_canvas = FigureCanvas(Figure(figsize=(5, 3))) layout.addWidget(self.static_canvas) self.control_truth = [] self.control_estimate = [] self.control_estimate_argmax = [] self.control_prediction = [] self.control_prediction_argmax = [] self.estimate_types = [] self.ax = self.static_canvas.figure.subplots() self.ax.set_xlim(0, 50) self.ax.set_ylim(-0.1, 1.1) self.ax.set_title('Control History') self.ax.legend() self.ax.set_yticks([0, 1]) self.ax.set_yticklabels(['2g', '3g']) self.ax.set_xlabel('Time') self.ax.set_ylabel('Control') self.ax.grid() # t = np.linspace(0, 10, 501) # self.ax.plot(t, np.sin(t), ".") # # Create QWidget # # ui_file = os.path.join(rospkg.RosPack().get_path('rqt_dot'), 'resource', 'rqt_dot.ui') # _, package_path = get_resource('packages', 'rqt_dot') # ui_file = os.path.join(package_path, 'share', 'rqt_dot', 'resource', 'rqt_dot.ui') # loadUi(ui_file, self, {'DotWidget':DotWidget}) # self.setObjectName('ROSDot') # # self.refreshButton.clicked[bool].connect(self._handle_refresh_clicked) # self.saveButton.clicked[bool].connect(self._handle_save_button_clicked) # # # flag used to zoom out to fit graph the first time it's received # self.first_time_graph_received = True # # to store the graph msg received in callback, later on is used to save the graph if needed # self.graph = None self.topic_name = 'graph_string' self._node = node self._node.create_subscription(ControlPList, 'control_estimate', self.ReceivedEstimateCallback, 10) self._node.create_subscription(ControlA, 'control_data', self.ReceivedTruthCallback, 10)
def __init__(self, parent=None): super(RawDataSelector, self).__init__() self.parent = parent self.setTitle('Select bag file') # Init the components self.bag1RadioBtn = QRadioButton('ground truth') self.bag2RadioBtn = QRadioButton('camera') # connect the signals to the slots self.bag1RadioBtn.clicked.connect(self.btn1Clicked) self.bag2RadioBtn.clicked.connect(self.btn2Clicked) # layout layout = QVBoxLayout() layout.addWidget(self.bag1RadioBtn) layout.addWidget(self.bag2RadioBtn) self.setLayout(layout)
def __init__(self, parent=None): super(MatDataPlot, self).__init__(parent) # thread safety self._lock = Lock() # initialize QT layout and sub-widgets self._canvas = MatDataPlot.Canvas() self._toolbar = NavigationToolbar(self._canvas, self._canvas) vbox = QVBoxLayout() vbox.addWidget(self._toolbar) vbox.addWidget(self._canvas) self.setLayout(vbox) # initialize data and callbacks self._curves = defaultdict(dict) self._canvas.mpl_connect('button_release_event', lambda _: self.limits_changed.emit()) self._canvas.mpl_connect('motion_notify_event', self._hover)
class OperationSelectorWidget(QGroupBox): selectionChanged = QtCore.Signal(str) operations = [ 'true positive', 'mismatch', 'false positive', 'false negative', 'precision', 'recall' ] def __init__(self, parent=None): super(OperationSelectorWidget, self).__init__() self.parent = parent self.setTitle('Select Value') self.layout = QVBoxLayout() self.initRadioButtons() self._currentSelected = '' self.setLayout(self.layout) def initRadioButtons(self): for operation in self.operations: btn = QRadioButton(operation) btn.clicked.connect(lambda state, x=operation: self.switchOperation(x)) self.layout.addWidget(btn) def switchOperation(self, operation): self._currentSelected = operation self.selectionChanged.emit(operation) def getOperation(self): return self._currentSelected
def __init__(self, parent=None, buffer_length=100, use_poly=True, no_legend=False): super(MatDataPlot3D, self).__init__(parent) self._canvas = MatDataPlot3D.Canvas() self._use_poly = use_poly self._buffer_length = buffer_length self._toolbar = NavigationToolbar(self._canvas, self._canvas) vbox = QVBoxLayout() vbox.addWidget(self._toolbar) vbox.addWidget(self._canvas) self.setLayout(vbox) self._curves_verts = {} self._color_index = 0 self._curves = {} self._no_legend = no_legend self._autoscroll = False
def __init__(self, linesList, parent=None): super(DelPlotDialog, self).__init__() self.linesList = linesList # list of the axes self.parent = parent # init the components: self.setWindowTitle("Delete Graph") self.resize(300, 200) self.linesListWidget = QListWidget(self) self.refreshList(self.linesList) self.__btn = QPushButton("Delete") # connect signals self.__btn.clicked.connect(self.btnPressed) # layout: layout = QVBoxLayout() layout.addWidget(self.linesListWidget) layout.addWidget(self.__btn) self.setLayout(layout)
def add_config(self, title, choices, single_choice=True): ''' create a UI element for selecting options for one variation and put it in a scrollArea ''' scroll = QScrollArea() group_box = QGroupBox(title) group_box.setFlat(True) layout = QVBoxLayout() if len(choices) > 5 and single_choice: combo_box = QComboBox(group_box) for obj in choices: combo_box.addItem(obj) layout.addWidget(combo_box) else: for obj in choices: if single_choice: layout.addWidget(QRadioButton(obj, group_box)) else: layout.addWidget(QCheckBox(obj, group_box)) layout.addStretch(1) group_box.setLayout(layout) scroll.setWidget(group_box) scroll.setWidgetResizable(True) return group_box, scroll
def motor_controller(self): ''' Sets up the GUI in the middle of the Screen to control the motors. Uses self._motorValues to determine which motors are present. ''' i = 0 for k, v in sorted(self._currentGoals.items()): group = QGroupBox() slider = QSlider(Qt.Horizontal) slider.setTickInterval(1) slider.setMinimum(-181) slider.setMaximum(181) slider.valueChanged.connect(self.slider_update) self._sliders[k] = slider textfield = QLineEdit() textfield.setText('0') textfield.textEdited.connect(self.textfield_update) self._textFields[k] = textfield label = QLabel() label.setText(k) layout = QVBoxLayout() layout.addWidget(label) layout.addWidget(self._sliders[k]) layout.addWidget(self._textFields[k]) group.setLayout(layout) self._widget.motorControlLayout.addWidget(group, i / 5, i % 5) i = i+1
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)
def __init__(self, context): super(MoveitCommanderWidget, self).__init__() self.setObjectName('MoveitCommanderWidget') self.groups = self.get_groups() self.commanders = [ moveit_commander.MoveGroupCommander(group) for group in self.groups ] # list of QLineEdit fields used to display joint values self.text_joint_values = [] self.MAX_COLUMNS = 4 self.tab_widget = QTabWidget() for g in self.groups: frame = self.setup_group_frame(g) self.tab_widget.addTab(frame, g) widget_layout = QVBoxLayout() widget_layout.addWidget(self.tab_widget) self.setLayout(widget_layout)
class NodeSelection(QWidget): def __init__(self, parent): super(NodeSelection, self).__init__() self.parent_widget = parent self.selected_nodes = [] self.setWindowTitle("Select the nodes you want to record") self.resize(500, 700) self.area = QScrollArea(self) self.main_widget = QWidget(self.area) self.ok_button = QPushButton("Done", self) self.ok_button.clicked.connect(self.onButtonClicked) self.ok_button.setEnabled(False) self.main_vlayout = QVBoxLayout(self) self.main_vlayout.addWidget(self.area) self.main_vlayout.addWidget(self.ok_button) self.setLayout(self.main_vlayout) self.selection_vlayout = QVBoxLayout(self) self.node_list = rosnode.get_node_names() self.node_list.sort() for node in self.node_list: self.addCheckBox(node) self.main_widget.setLayout(self.selection_vlayout) self.show() def addCheckBox(self, node): item = QCheckBox(node, self) item.stateChanged.connect(lambda x: self.updateNode(x, node)) self.selection_vlayout.addWidget(item) def updateNode(self, state, node): if state == Qt.Checked: self.selected_nodes.append(node) else: self.selected_nodes.remove(node) if len(self.selected_nodes) > 0: self.ok_button.setEnabled(True) else: self.ok_button.setEnabled(False) def onButtonClicked(self): master = rosgraph.Master('rqt_bag_recorder') state = master.getSystemState() subs = [t for t, l in state[1] if len([node_name for node_name in self.selected_nodes if node_name in l]) > 0] for topic in subs: self.parent_widget.changeTopicCheckState(topic, Qt.Checked) self.parent_widget.updateList(Qt.Checked, topic) self.close()
class Top(Plugin): NODE_FIELDS = [ 'pid', 'get_cpu_percent', 'get_memory_percent', 'get_num_threads'] OUT_FIELDS = ['node_name', 'pid', 'cpu_percent', 'memory_percent', 'num_threads' ] FORMAT_STRS = ['%s', '%s', '%0.2f', '%0.2f', '%s' ] NODE_LABELS = ['Node', 'PID', 'CPU %', 'Mem %', 'Num Threads' ] SORT_TYPE = [str, str, float, float, float ] TOOLTIPS = { 0: ('cmdline', lambda x: '\n'.join(textwrap.wrap(' '.join(x)))), 3: ('memory_info', lambda x: ('Resident: %0.2f MiB, Virtual: %0.2f MiB' % (x[0]/2**20, x[1]/2**20))) } _node_info = NodeInfo() name_filter = re.compile('') def __init__(self, context): super(Top, self).__init__(context) # Give QObjects reasonable names self.setObjectName('Top') # Process standalone plugin command-line arguments from argparse import ArgumentParser parser = ArgumentParser() # Add argument(s) to the parser. parser.add_argument("-q", "--quiet", action="store_true", dest="quiet", help="Put plugin in silent mode") args, unknowns = parser.parse_known_args(context.argv()) # if not args.quiet: # print 'arguments: ', args # print 'unknowns: ', unknowns self._selected_node = '' self._selected_node_lock = RLock() # Setup the toolbar self._toolbar = QToolBar() self._filter_box = QLineEdit() self._regex_box = QCheckBox() self._regex_box.setText('regex') self._toolbar.addWidget(QLabel('Filter')) self._toolbar.addWidget(self._filter_box) self._toolbar.addWidget(self._regex_box) self._filter_box.returnPressed.connect(self.update_filter) self._regex_box.stateChanged.connect(self.update_filter) # Create a container widget and give it a layout self._container = QWidget() self._container.setWindowTitle('Process Monitor') self._layout = QVBoxLayout() self._container.setLayout(self._layout) self._layout.addWidget(self._toolbar) # Create the table widget self._table_widget = QTreeWidget() self._table_widget.setObjectName('TopTable') self._table_widget.setColumnCount(len(self.NODE_LABELS)) self._table_widget.setHeaderLabels(self.NODE_LABELS) self._table_widget.itemClicked.connect(self._tableItemClicked) self._table_widget.setSortingEnabled(True) self._table_widget.setAlternatingRowColors(True) self._layout.addWidget(self._table_widget) context.add_widget(self._container) # Add a button for killing nodes self._kill_button = QPushButton('Kill Node') self._layout.addWidget(self._kill_button) self._kill_button.clicked.connect(self._kill_node) # Update twice since the first cpu% lookup will always return 0 self.update_table() self.update_table() self._table_widget.resizeColumnToContents(0) # Start a timer to trigger updates self._update_timer = QTimer() self._update_timer.setInterval(1000) self._update_timer.timeout.connect(self.update_table) self._update_timer.start() def _tableItemClicked(self, item, column): with self._selected_node_lock: self._selected_node = item.text(0) def update_filter(self, *args): if self._regex_box.isChecked(): expr = self._filter_box.text() else: expr = re.escape(self._filter_box.text()) self.name_filter = re.compile(expr) self.update_table() def _kill_node(self): self._node_info.kill_node(self._selected_node) def update_one_item(self, row, info): twi = TopWidgetItem() for col, field in enumerate(self.OUT_FIELDS): val = info[field] twi.setText(col, self.FORMAT_STRS[col] % val) self._table_widget.insertTopLevelItem(row, twi) for col, (key, func) in self.TOOLTIPS.items(): twi.setToolTip(col, func(info[key])) with self._selected_node_lock: if twi.text(0) == self._selected_node: twi.setSelected(True) twi.setHidden(len(self.name_filter.findall(info['node_name'])) == 0) def update_table(self): self._table_widget.clear() infos = self._node_info.get_all_node_fields(self.NODE_FIELDS) for nx, info in enumerate(infos): self.update_one_item(nx, info) def shutdown_plugin(self): self._update_timer.stop() def save_settings(self, plugin_settings, instance_settings): instance_settings.set_value('filter_text', self._filter_box.text()) instance_settings.set_value('is_regex', int(self._regex_box.checkState())) def restore_settings(self, plugin_settings, instance_settings): self._filter_box.setText(instance_settings.value('filter_text')) is_regex_int = instance_settings.value('is_regex') if is_regex_int: self._regex_box.setCheckState(Qt.CheckState(is_regex_int)) else: self._regex_box.setCheckState(Qt.CheckState(0)) self.update_filter()
class NavViewWidget(QWidget): def __init__(self, map_topic='/map', paths=['/move_base/NavFn/plan', '/move_base/TrajectoryPlannerROS/local_plan'], polygons=['/move_base/local_costmap/robot_footprint']): super(NavViewWidget, self).__init__() self._layout = QVBoxLayout() self._button_layout = QHBoxLayout() self.setAcceptDrops(True) self.setWindowTitle('Navigation Viewer') self.paths = paths self.polygons = polygons self.map = map_topic self._tf = tf.TransformListener() self._nav_view = NavView(map_topic, paths, polygons, tf = self._tf, parent = self) self._set_pose = QPushButton('Set Pose') self._set_pose.clicked.connect(self._nav_view.pose_mode) self._set_goal = QPushButton('Set Goal') self._set_goal.clicked.connect(self._nav_view.goal_mode) self._button_layout.addWidget(self._set_pose) self._button_layout.addWidget(self._set_goal) self._layout.addLayout(self._button_layout) self._layout.addWidget(self._nav_view) self.setLayout(self._layout) def dragEnterEvent(self, e): if not e.mimeData().hasText(): if not hasattr(e.source(), 'selectedItems') or len(e.source().selectedItems()) == 0: qWarning('NavView.dragEnterEvent(): not hasattr(event.source(), selectedItems) or len(event.source().selectedItems()) == 0') return item = e.source().selectedItems()[0] topic_name = item.data(0, Qt.UserRole) if topic_name == None: qWarning('NavView.dragEnterEvent(): not hasattr(item, ros_topic_name_)') return else: topic_name = str(e.mimeData().text()) if accepted_topic(topic_name): e.accept() e.acceptProposedAction() def dropEvent(self, e): if e.mimeData().hasText(): topic_name = str(e.mimeData().text()) else: droped_item = e.source().selectedItems()[0] topic_name = str(droped_item.data(0, Qt.UserRole)) topic_type, array = get_field_type(topic_name) if not array: if topic_type is OccupancyGrid: self.map = topic_name # Swap out the nav view for one with the new topics self._nav_view.close() self._nav_view = NavView(self.map, self.paths, self.polygons, self._tf, self) self._layout.addWidget(self._nav_view) elif topic_type is Path: self.paths.append(topic_name) self._nav_view.add_path(topic_name) elif topic_type is PolygonStamped: self.polygons.append(topic_name) self._nav_view.add_polygon(topic_name) def save_settings(self, plugin_settings, instance_settings): self._nav_view.save_settings(plugin_settings, instance_settings) def restore_settings(self, plugin_settings, instance_settings): self._nav_view.restore_settings(plugin_settings, instance_settings)
class TopicSelection(QWidget): recordSettingsSelected = Signal(bool, list) def __init__(self): super(TopicSelection, self).__init__() master = rosgraph.Master('rqt_bag_recorder') self.setWindowTitle("Select the topics you want to record") self.resize(500, 700) self.topic_list = [] self.selected_topics = [] self.items_list = [] self.area = QScrollArea(self) self.main_widget = QWidget(self.area) self.ok_button = QPushButton("Record", self) self.ok_button.clicked.connect(self.onButtonClicked) self.ok_button.setEnabled(False) self.main_vlayout = QVBoxLayout(self) self.main_vlayout.addWidget(self.area) self.main_vlayout.addWidget(self.ok_button) self.setLayout(self.main_vlayout) self.selection_vlayout = QVBoxLayout(self) self.item_all = QCheckBox("All", self) self.item_all.stateChanged.connect(self.updateList) self.selection_vlayout.addWidget(self.item_all) topic_data_list = master.getPublishedTopics('') topic_data_list.sort() for topic, datatype in topic_data_list: self.addCheckBox(topic) self.main_widget.setLayout(self.selection_vlayout) self.area.setWidget(self.main_widget) self.show() def addCheckBox(self, topic): self.topic_list.append(topic) item = QCheckBox(topic, self) item.stateChanged.connect(lambda x: self.updateList(x,topic)) self.items_list.append(item) self.selection_vlayout.addWidget(item) def updateList(self, state, topic = None): if topic is None: # The "All" checkbox was checked / unchecked if state == Qt.Checked: self.item_all.setTristate(False) for item in self.items_list: if item.checkState() == Qt.Unchecked: item.setCheckState(Qt.Checked) elif state == Qt.Unchecked: self.item_all.setTristate(False) for item in self.items_list: if item.checkState() == Qt.Checked: item.setCheckState(Qt.Unchecked) else: if state == Qt.Checked: self.selected_topics.append(topic) else: self.selected_topics.remove(topic) if self.item_all.checkState()==Qt.Checked: self.item_all.setCheckState(Qt.PartiallyChecked) if self.selected_topics == []: self.ok_button.setEnabled(False) else: self.ok_button.setEnabled(True) def onButtonClicked(self): self.close() self.recordSettingsSelected.emit((self.item_all.checkState() == Qt.Checked), self.selected_topics)
def __init__(self, context, node=None): """ This class is intended to be called by rqt plugin framework class. Currently (12/12/2012) the whole widget is splitted into 2 panes: one on left allows you to choose the node(s) you work on. Right side pane lets you work with the parameters associated with the node(s) you select on the left. (12/27/2012) Despite the pkg name is changed to rqt_reconfigure to reflect the available functionality, file & class names remain 'param', expecting all the parameters will become handle-able. """ super(ParamWidget, self).__init__() self.setObjectName(self._TITLE_PLUGIN) self.setWindowTitle(self._TITLE_PLUGIN) rp = rospkg.RosPack() #TODO: .ui file needs to replace the GUI components declaration # below. For unknown reason, referring to another .ui files # from a .ui that is used in this class failed. So for now, # I decided not use .ui in this class. # If someone can tackle this I'd appreciate. _hlayout_top = QHBoxLayout(self) _hlayout_top.setContentsMargins(QMargins(0, 0, 0, 0)) self._splitter = QSplitter(self) _hlayout_top.addWidget(self._splitter) _vlayout_nodesel_widget = QWidget() _vlayout_nodesel_side = QVBoxLayout() _hlayout_filter_widget = QWidget(self) _hlayout_filter = QHBoxLayout() self._text_filter = TextFilter() self.filter_lineedit = TextFilterWidget(self._text_filter, rp) self.filterkey_label = QLabel("&Filter key:") self.filterkey_label.setBuddy(self.filter_lineedit) _hlayout_filter.addWidget(self.filterkey_label) _hlayout_filter.addWidget(self.filter_lineedit) _hlayout_filter_widget.setLayout(_hlayout_filter) self._nodesel_widget = NodeSelectorWidget(self, rp, self.sig_sysmsg) _vlayout_nodesel_side.addWidget(_hlayout_filter_widget) _vlayout_nodesel_side.addWidget(self._nodesel_widget) _vlayout_nodesel_side.setSpacing(1) _vlayout_nodesel_widget.setLayout(_vlayout_nodesel_side) reconf_widget = ParameditWidget(rp) self._splitter.insertWidget(0, _vlayout_nodesel_widget) self._splitter.insertWidget(1, reconf_widget) # 1st column, _vlayout_nodesel_widget, to minimize width. # 2nd col to keep the possible max width. self._splitter.setStretchFactor(0, 0) self._splitter.setStretchFactor(1, 1) # Signal from paramedit widget to node selector widget. reconf_widget.sig_node_disabled_selected.connect( self._nodesel_widget.node_deselected) # Pass name of node to editor widget self._nodesel_widget.sig_node_selected.connect( reconf_widget.show_reconf) if not node: title = self._TITLE_PLUGIN else: title = self._TITLE_PLUGIN + ' %s' % node self.setObjectName(title) #Connect filter signal-slots. self._text_filter.filter_changed_signal.connect( self._filter_key_changed) # Open any clients indicated from command line self.sig_selected.connect(self._nodesel_widget.node_selected) for rn in [rospy.resolve_name(c) for c in context.argv()]: if rn in self._nodesel_widget.get_paramitems(): self.sig_selected.emit(rn) else: rospy.logwarn('Could not find a dynamic reconfigure client named \'%s\'', str(rn))
def __init__(self, title, jsp, num_rows=0): super(JointStatePublisherGui, self).__init__() self.jsp = jsp self.joint_map = {} self.vlayout = QVBoxLayout(self) self.gridlayout = QGridLayout() font = QFont("Helvetica", 9, QFont.Bold) ### Generate sliders ### sliders = [] for name in self.jsp.joint_list: if name not in self.jsp.free_joints: continue joint = self.jsp.free_joints[name] if joint['min'] == joint['max']: continue joint_layout = QVBoxLayout() row_layout = QHBoxLayout() label = QLabel(name) label.setFont(font) row_layout.addWidget(label) display = QLineEdit("0.00") display.setAlignment(Qt.AlignRight) display.setFont(font) display.setReadOnly(True) row_layout.addWidget(display) joint_layout.addLayout(row_layout) slider = QSlider(Qt.Horizontal) slider.setFont(font) slider.setRange(0, RANGE) slider.setValue(RANGE/2) joint_layout.addWidget(slider) self.joint_map[name] = {'slidervalue': 0, 'display': display, 'slider': slider, 'joint': joint} # Connect to the signal provided by QSignal slider.valueChanged.connect(self.onValueChanged) sliders.append(joint_layout) # Determine number of rows to be used in grid self.num_rows = num_rows # if desired num of rows wasn't set, default behaviour is a vertical layout if self.num_rows == 0: self.num_rows = len(sliders) # equals VBoxLayout # Generate positions in grid and place sliders there self.positions = self.generate_grid_positions(len(sliders), self.num_rows) for item, pos in zip(sliders, self.positions): self.gridlayout.addLayout(item, *pos) # Set zero positions read from parameters self.center() # Synchronize slider and displayed value self.sliderUpdate(None) # Set up a signal for updating the sliders based on external joint info self.sliderUpdateTrigger.connect(self.updateSliders) self.vlayout.addLayout(self.gridlayout) # Buttons for randomizing and centering sliders and # Spinbox for on-the-fly selecting number of rows self.randbutton = QPushButton('Randomize', self) self.randbutton.clicked.connect(self.randomize_event) self.vlayout.addWidget(self.randbutton) self.ctrbutton = QPushButton('Center', self) self.ctrbutton.clicked.connect(self.center_event) self.vlayout.addWidget(self.ctrbutton) self.maxrowsupdown = QSpinBox() self.maxrowsupdown.setMinimum(1) self.maxrowsupdown.setMaximum(len(sliders)) self.maxrowsupdown.setValue(self.num_rows) self.maxrowsupdown.lineEdit().setReadOnly(True) # don't edit it by hand to avoid weird resizing of window self.maxrowsupdown.valueChanged.connect(self.reorggrid_event) self.vlayout.addWidget(self.maxrowsupdown)
class InspectorWindow(QWidget): closed = Signal(str) def __init__(self, parent, name, status, timeline): """ :type status: DiagnosticStatus :param close_callback: When the instance of this class (InspectorWindow) terminates, this callback gets called. """ #TODO(Isaac) UI construction that currently is done in this method, # needs to be done in .ui file. super(InspectorWindow, self).__init__() self.setWindowTitle(name) self._name = name self.layout_vertical = QVBoxLayout(self) self.disp = StatusSnapshot(parent=self) self.layout_vertical.addWidget(self.disp, 1) if timeline is not None: self.timeline_pane = TimelinePane(self) self.timeline_pane.set_timeline(timeline, name) self.layout_vertical.addWidget(self.timeline_pane, 0) self.snapshot = QPushButton("Snapshot") self.snapshot.clicked.connect(self._take_snapshot) self.layout_vertical.addWidget(self.snapshot) self.snaps = [] self.setLayout(self.layout_vertical) # TODO better to be configurable where to appear. self.resize(400, 600) self.show() self.message_updated(status) def closeEvent(self, event): """ called when this window is closed Calls close on all snapshots, and emits the closed signal """ # TODO: are snapshots kept around even after they're closed? # this appears to work even if the user closes some snapshots, # and they're still left in the internal array for snap in self.snaps: snap.close() self.closed.emit(self._name) @Slot(DiagnosticArray) def message_updated(self, msg): status = util.get_status_by_name(msg, self._name) scroll_value = self.disp.verticalScrollBar().value() rospy.logdebug('InspectorWin message_updated') self.status = status self.disp.write_status.emit(status) if self.disp.verticalScrollBar().maximum() < scroll_value: scroll_value = self.disp.verticalScrollBar().maximum() self.disp.verticalScrollBar().setValue(scroll_value) def _take_snapshot(self): snap = StatusSnapshot(status=self.status) self.snaps.append(snap)
class LevelSelectorPlugin(Plugin): button_signal = pyqtSignal() button_status_signal = pyqtSignal() def __init__(self, context): super(LevelSelectorPlugin, self).__init__(context) # Give QObjects reasonable names self.setObjectName('LevelSelectorPlugin') # Create QWidget self._widget = QWidget() self._widget.setFont(QFont("Times", 15, QFont.Bold)) self._button_layout = QVBoxLayout(self._widget) self.buttons = [] self.text_label = QLabel("Waiting for MultiLevelMapData...", self._widget) self._button_layout.addWidget(self.text_label) self._widget.setObjectName('LevelSelectorPluginUI') if context.serial_number() > 1: self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number())) context.add_widget(self._widget) self.button_signal.connect(self.update_buttons) self.button_status_signal.connect(self.update_button_status) # Subscribe to the multi level map data to get information about all the maps. self.multimap_subscriber = rospy.Subscriber("map_metadata", MultiLevelMapData, self.process_multimap) self.levels = [] self.current_level = None rospy.loginfo('level selector: subscribed to maps') # Subscribe to the current level we are on. self.status_subscriber = None # Create a service proxy to change the current level. self.level_selector_proxy = rospy.ServiceProxy("level_mux/change_current_level", ChangeCurrentLevel) self.level_selector_proxy.wait_for_service() rospy.loginfo('level selector: found "level_mux/change_current_level" service') def process_multimap(self, msg): """ Map metadata topic callback. """ rospy.loginfo('level selector: map metadata received.') self.levels = msg.levels # update level buttons in the selection window self.button_signal.emit() def update_buttons(self): """ Update buttons in Qt window. """ rospy.loginfo('level selector: update_buttons called') self.clean() for index, level in enumerate(self.levels): button = QPushButton(level.level_id, self._widget) button.clicked[bool].connect(self.handle_button) button.setCheckable(True) self._button_layout.addWidget(button) self.buttons.append(button) # Subscribe to the current level we are on. if self.status_subscriber is None: self.status_subscriber = rospy.Subscriber("level_mux/current_level", LevelMetaData, self.process_level_status) def update_button_status(self): """ Update button status Qt push button callback. """ rospy.loginfo('level selector: update_button_status') if not self.buttons or not self.current_level: rospy.logwarn('level selector: current level not available') return rospy.logdebug('buttons: ' + str(self.buttons)) for index, level in enumerate(self.levels): rospy.logdebug('level[' + str(index) + ']: ' + str(level.level_id)) if self.current_level == level.level_id: self.buttons[index].setChecked(True) else: self.buttons[index].setChecked(False) def process_level_status(self, msg): """ level_mux/current_level topic callback. """ rospy.loginfo('level selector: current_level topic message received') level_found = False for level in self.levels: if msg.level_id == level.level_id: self.current_level = level.level_id level_found = True break if not level_found: self.current_level = None self.button_status_signal.emit() def handle_button(self): source = self.sender() if source.text() == self.current_level: source.setChecked(True) return # Construct a identity pose. The level selector cannot be used # to choose the initialpose, as it does not have the interface # for specifying the position. The position should be # specified via rviz. origin_pose = PoseWithCovarianceStamped() origin_pose.header.frame_id = frameIdFromLevelId(source.text()) origin_pose.pose.pose.orientation.w = 1 # Makes the origin quaternion valid. origin_pose.pose.covariance[0] = 1.0 origin_pose.pose.covariance[7] = 1.0 origin_pose.pose.covariance[14] = 1.0 origin_pose.pose.covariance[21] = 1.0 origin_pose.pose.covariance[28] = 1.0 origin_pose.pose.covariance[35] = 1.0 # Don't actually publish the initial pose via the level # selector. It doesn't know any better. self.level_selector_proxy(source.text(), False, origin_pose) def clean(self): while self._button_layout.count(): item = self._button_layout.takeAt(0) item.widget().deleteLater() def save_settings(self, plugin_settings, instance_settings): pass def restore_settings(self, plugin_settings, instance_settings): pass
class ParameditWidget(QWidget): """ This class represents a pane where parameter editor widgets of multiple nodes are shown. In rqt_reconfigure, this pane occupies right half of the entire visible area. """ # public signal sig_node_disabled_selected = Signal(str) def __init__(self, rospack): """""" super(ParameditWidget, self).__init__() ui_file = os.path.join(rospack.get_path('rqt_reconfigure'), 'resource', 'paramedit_pane.ui') loadUi(ui_file, self, {'ParameditWidget': ParameditWidget}) self._dynreconf_clients = OrderedDict() # Adding the list of Items self.vlayout = QVBoxLayout(self.scrollarea_holder_widget) #self._set_index_widgets(self.listview, paramitems_dict) # causes error self.destroyed.connect(self.close) def _set_index_widgets(self, view, paramitems_dict): """ @deprecated: Causes error """ i = 0 for p in paramitems_dict: view.setIndexWidget(i, p) i += 1 def show_reconf(self, dynreconf_widget): """ Callback when user chooses a node. @param dynreconf_widget: """ node_grn = dynreconf_widget.get_node_grn() rospy.logdebug('ParameditWidget.show str(node_grn)=%s', str(node_grn)) if not node_grn in self._dynreconf_clients.keys(): # Add dynreconf widget if there isn't already one. # Client gets renewed every time different node_grn was clicked. self._dynreconf_clients.__setitem__(node_grn, dynreconf_widget) self.vlayout.addWidget(dynreconf_widget) dynreconf_widget.sig_node_disabled_selected.connect( self._node_disabled) else: # If there has one already existed, remove it. self._remove_node(node_grn) #LayoutUtil.clear_layout(self.vlayout) # Re-add the rest of existing items to layout. #for k, v in self._dynreconf_clients.iteritems(): # rospy.loginfo('added to layout k={} v={}'.format(k, v)) # self.vlayout.addWidget(v) # Add color to alternate the rim of the widget. LayoutUtil.alternate_color(self._dynreconf_clients.itervalues(), [self.palette().background().color().lighter(125), self.palette().background().color().darker(125)]) def close(self): for dc in self._dynreconf_clients: # Clear out the old widget dc.close() dc = None self._paramedit_scrollarea.deleteLater() def filter_param(self, filter_key): """ :type filter_key: """ #TODO Pick nodes that match filter_key. #TODO For the nodes that are kept in previous step, call # DynreconfWidget.filter_param for all of its existing # instances. pass def _remove_node(self, node_grn): try: i = self._dynreconf_clients.keys().index(node_grn) except ValueError: # ValueError occurring here means that the specified key is not # found, most likely already removed, which is possible in the # following situation/sequence: # # Node widget on ParameditWidget removed by clicking disable button # --> Node deselected on tree widget gets updated # --> Tree widget detects deselection # --> Tree widget emits deselection signal, which is captured by # ParameditWidget's slot. Thus reaches this method again. return item = self.vlayout.itemAt(i) if isinstance(item, QWidgetItem): item.widget().close() w = self._dynreconf_clients.pop(node_grn) rospy.logdebug('popped={} Len of left clients={}'.format( w, len(self._dynreconf_clients))) def _node_disabled(self, node_grn): rospy.logdebug('paramedit_w _node_disabled grn={}'.format(node_grn)) # Signal to notify other GUI components (eg. nodes tree pane) that # a node widget is disabled. self.sig_node_disabled_selected.emit(node_grn) # Remove the selected node widget from the internal list of nodes. self._remove_node(node_grn)
def __init__(self, updater, config, nodename): ''' :param config: :type config: Dictionary? defined in dynamic_reconfigure.client.Client :type nodename: str ''' super(GroupWidget, self).__init__() self.state = config['state'] self.param_name = config['name'] self._toplevel_treenode_name = nodename # TODO: .ui file needs to be back into usage in later phase. # ui_file = os.path.join(rp.get_path('rqt_reconfigure'), # 'resource', 'singlenode_parameditor.ui') # loadUi(ui_file, self) verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(QMargins(0, 0, 0, 0)) _widget_nodeheader = QWidget() _h_layout_nodeheader = QHBoxLayout(_widget_nodeheader) _h_layout_nodeheader.setContentsMargins(QMargins(0, 0, 0, 0)) self.nodename_qlabel = QLabel(self) font = QFont('Trebuchet MS, Bold') font.setUnderline(True) font.setBold(True) # Button to close a node. _icon_disable_node = QIcon.fromTheme('window-close') _bt_disable_node = QPushButton(_icon_disable_node, '', self) _bt_disable_node.setToolTip('Hide this node') _bt_disable_node_size = QSize(36, 24) _bt_disable_node.setFixedSize(_bt_disable_node_size) _bt_disable_node.pressed.connect(self._node_disable_bt_clicked) _h_layout_nodeheader.addWidget(self.nodename_qlabel) _h_layout_nodeheader.addWidget(_bt_disable_node) self.nodename_qlabel.setAlignment(Qt.AlignCenter) font.setPointSize(10) self.nodename_qlabel.setFont(font) grid_widget = QWidget(self) self.grid = QFormLayout(grid_widget) verticalLayout.addWidget(_widget_nodeheader) verticalLayout.addWidget(grid_widget, 1) # Again, these UI operation above needs to happen in .ui file. self.tab_bar = None # Every group can have one tab bar self.tab_bar_shown = False self.updater = updater self.editor_widgets = [] self._param_names = [] self._create_node_widgets(config) rospy.logdebug('Groups node name={}'.format(nodename)) self.nodename_qlabel.setText(nodename)
class JointStatePublisherGui(QWidget): sliderUpdateTrigger = Signal() def __init__(self, title, jsp, num_rows=0): super(JointStatePublisherGui, self).__init__() self.jsp = jsp self.joint_map = {} self.vlayout = QVBoxLayout(self) self.gridlayout = QGridLayout() font = QFont("Helvetica", 9, QFont.Bold) ### Generate sliders ### sliders = [] for name in self.jsp.joint_list: if name not in self.jsp.free_joints: continue joint = self.jsp.free_joints[name] if joint['min'] == joint['max']: continue joint_layout = QVBoxLayout() row_layout = QHBoxLayout() label = QLabel(name) label.setFont(font) row_layout.addWidget(label) display = QLineEdit("0.00") display.setAlignment(Qt.AlignRight) display.setFont(font) display.setReadOnly(True) row_layout.addWidget(display) joint_layout.addLayout(row_layout) slider = QSlider(Qt.Horizontal) slider.setFont(font) slider.setRange(0, RANGE) slider.setValue(RANGE/2) joint_layout.addWidget(slider) self.joint_map[name] = {'slidervalue': 0, 'display': display, 'slider': slider, 'joint': joint} # Connect to the signal provided by QSignal slider.valueChanged.connect(self.onValueChanged) sliders.append(joint_layout) # Determine number of rows to be used in grid self.num_rows = num_rows # if desired num of rows wasn't set, default behaviour is a vertical layout if self.num_rows == 0: self.num_rows = len(sliders) # equals VBoxLayout # Generate positions in grid and place sliders there self.positions = self.generate_grid_positions(len(sliders), self.num_rows) for item, pos in zip(sliders, self.positions): self.gridlayout.addLayout(item, *pos) # Set zero positions read from parameters self.center() # Synchronize slider and displayed value self.sliderUpdate(None) # Set up a signal for updating the sliders based on external joint info self.sliderUpdateTrigger.connect(self.updateSliders) self.vlayout.addLayout(self.gridlayout) # Buttons for randomizing and centering sliders and # Spinbox for on-the-fly selecting number of rows self.randbutton = QPushButton('Randomize', self) self.randbutton.clicked.connect(self.randomize_event) self.vlayout.addWidget(self.randbutton) self.ctrbutton = QPushButton('Center', self) self.ctrbutton.clicked.connect(self.center_event) self.vlayout.addWidget(self.ctrbutton) self.maxrowsupdown = QSpinBox() self.maxrowsupdown.setMinimum(1) self.maxrowsupdown.setMaximum(len(sliders)) self.maxrowsupdown.setValue(self.num_rows) self.maxrowsupdown.lineEdit().setReadOnly(True) # don't edit it by hand to avoid weird resizing of window self.maxrowsupdown.valueChanged.connect(self.reorggrid_event) self.vlayout.addWidget(self.maxrowsupdown) @pyqtSlot(int) def onValueChanged(self, event): # A slider value was changed, but we need to change the joint_info metadata. for name, joint_info in self.joint_map.items(): joint_info['slidervalue'] = joint_info['slider'].value() joint = joint_info['joint'] joint['position'] = self.sliderToValue(joint_info['slidervalue'], joint) joint_info['display'].setText("%.2f" % joint['position']) @pyqtSlot() def updateSliders(self): self.update_sliders() def update_sliders(self): for name, joint_info in self.joint_map.items(): joint = joint_info['joint'] joint_info['slidervalue'] = self.valueToSlider(joint['position'], joint) joint_info['slider'].setValue(joint_info['slidervalue']) def center_event(self, event): self.center() def center(self): rospy.loginfo("Centering") for name, joint_info in self.joint_map.items(): joint = joint_info['joint'] joint_info['slider'].setValue(self.valueToSlider(joint['zero'], joint)) def reorggrid_event(self, event): self.reorganize_grid(event) def reorganize_grid(self, number_of_rows): self.num_rows = number_of_rows # Remove items from layout (won't destroy them!) items = [] for pos in self.positions: item = self.gridlayout.itemAtPosition(*pos) items.append(item) self.gridlayout.removeItem(item) # Generate new positions for sliders and place them in their new spots self.positions = self.generate_grid_positions(len(items), self.num_rows) for item, pos in zip(items, self.positions): self.gridlayout.addLayout(item, *pos) def generate_grid_positions(self, num_items, num_rows): if num_rows==0: return [] positions = [(y, x) for x in range(int((math.ceil(float(num_items) / num_rows)))) for y in range(num_rows)] positions = positions[:num_items] return positions def randomize_event(self, event): self.randomize() def randomize(self): rospy.loginfo("Randomizing") for name, joint_info in self.joint_map.items(): joint = joint_info['joint'] joint_info['slider'].setValue( self.valueToSlider(random.uniform(joint['min'], joint['max']), joint)) def sliderUpdate(self, event): for name, joint_info in self.joint_map.items(): joint_info['slidervalue'] = joint_info['slider'].value() self.update_sliders() def valueToSlider(self, value, joint): return (value - joint['min']) * float(RANGE) / (joint['max'] - joint['min']) def sliderToValue(self, slider, joint): pctvalue = slider / float(RANGE) return joint['min'] + (joint['max']-joint['min']) * pctvalue