def on_reset_motors(self): # if any of the breakers is not enabled ask if they'd like to enable them if (self._dashboard_message is not None and self._dashboard_message.power_board_state_valid): all_breakers_enabled = reduce(lambda x, y: x and y, [ state == PowerBoardState.STATE_ON for state in self._dashboard_message.power_board_state.circuit_state ]) if (not all_breakers_enabled): if (QMessageBox.question( self._breakers[0], self.tr('Enable Breakers?'), self. tr("Resetting the motors may not work because not all breakers are enabled. Enable all the breakers first?" ), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) == QMessageBox.Yes): [breaker.set_enable() for breaker in self._breakers] reset = rospy.ServiceProxy("pr2_etherCAT/reset_motors", std_srvs.srv.Empty) try: reset() except rospy.ServiceException, e: QMessageBox.critical( self._breakers[0], "Error", "Failed to reset the motors: service call failed with error: %s" % (e))
def click_btn_apply(self): if self.validate_checked(): quit_msg = "Are you sure you want to Apply this configuration?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) self.get_selected_robot_checked() if reply == QMessageBox.Yes: xml_info = XmlInfo() env_os = EnvOs() dialog_xml = DialogXml() deleted_general_items = xml_info.get_deleted_general_variable() #get deleted general items (deleted status = 1 in xml) variable_general_items = xml_info.get_general_variables() dialog_xml.get_deleted_variable_robot() deleted_robots_items=dialog_xml.get_deleted_variable_robot() variable_robot_items,active_robot=dialog_xml.get_general_variable_robot() deleted_robot=dialog_xml.get_deleted_robot() asociative_variable_robot = dialog_xml.get_asociative_robot_variable() env_os.unset_to_htbash(deleted_robots_items+deleted_robots_items) env_os.export_to_general_htbash(variable_general_items) env_os.export_to_robot_htbash(variable_robot_items,active_robot) dialog_xml.remove_asociative_robot_variable(asociative_variable_robot) for item in deleted_robot: dialog_xml.remove_robot_list_variable(item) for item in deleted_general_items: xml_info.remove_general_variable(item) env_os.include_htbash() self.lblmsg.setText("write file .htbash successfully") else: pass else: QMessageBox.information(self, 'Checked validate',"You only must select one active robot")
def mouseReleaseEvent(self, event): ''' Opens the new editor, if the user clicked on the included file and sets the default cursor. ''' if event.modifiers() == Qt.ControlModifier or event.modifiers() == Qt.ShiftModifier: cursor = self.cursorForPosition(event.pos()) index = self.index(cursor.block().text()) if index > -1: startIndex = cursor.block().text().find('"', index) if startIndex > -1: endIndex = cursor.block().text().find('"', startIndex + 1) fileName = cursor.block().text()[startIndex + 1:endIndex] if len(fileName) > 0: try: qf = QFile(interpret_path(fileName)) if not qf.exists(): # create a new file, if it does not exists result = QMessageBox.question(self, "File not found", '\n\n'.join(["Create a new file?", qf.fileName()]), QMessageBox.Yes | QMessageBox.No) if result == QMessageBox.Yes: d = os.path.dirname(qf.fileName()) if not os.path.exists(d): os.makedirs(d) with open(qf.fileName(), 'w') as f: if qf.fileName().endswith('.launch'): f.write('<launch>\n\n</launch>') event.setAccepted(True) self.load_request_signal.emit(qf.fileName()) else: event.setAccepted(True) self.load_request_signal.emit(qf.fileName()) except Exception, e: WarningMessageBox(QMessageBox.Warning, "File not found %s" % fileName, str(e)).exec_()
def closeEvent(self, event): ''' Test the open files for changes and save this if needed. ''' changed = [] # get the names of all changed files for i in range(self.tabWidget.count()): w = self.tabWidget.widget(i) if w.document().isModified(): changed.append(self.__getTabName(w.filename)) if changed: # ask the user for save changes if self.isHidden(): buttons = QMessageBox.Yes | QMessageBox.No else: buttons = QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel result = QMessageBox.question(self, "Unsaved Changes", '\n\n'.join(["Save the file before closing?", '\n'.join(changed)]), buttons) if result == QMessageBox.Yes: for i in range(self.tabWidget.count()): w = self.tabWidget.widget(i).save() event.accept() elif result == QMessageBox.No: event.accept() else: event.ignore() else: event.accept() if event.isAccepted(): self.storeSetting() self.finished_signal.emit(self.init_filenames)
def on_close_tab(self, tab_index): ''' Signal handling to close single tabs. @param tab_index: tab index to close @type tab_index: C{int} ''' try: doremove = True w = self.tabWidget.widget(tab_index) if w.document().isModified(): name = self.__getTabName(w.filename) result = QMessageBox.question(self, "Unsaved Changes", '\n\n'.join(["Save the file before closing?", name]), QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) if result == QMessageBox.Yes: self.tabWidget.currentWidget().save() elif result == QMessageBox.No: pass else: doremove = False if doremove: # remove the indexed files if w.filename in self.files: self.files.remove(w.filename) # close tab self.tabWidget.removeTab(tab_index) # close editor, if no tabs are open if not self.tabWidget.count(): self.close() except: import traceback rospy.logwarn("Error while close tab %s: %s", str(tab_index), traceback.format_exc(1))
def killScreens(cls, node, host, auto_ok_request=True, user=None, pw=None): ''' Searches for the screen associated with the given node and kill this screens. @param node: the name of the node those screen output to show @type node: C{str} @param host: the host name or ip where the screen is running @type host: C{str} ''' if node is None or len(node) == 0: return False try: # get the available screens screens = cls._getActiveScreens(host, cls.createSessionName(node), auto_ok_request, user=user, pwd=pw) # user=user, pwd=pwd if screens: do_kill = True if auto_ok_request: try: from python_qt_binding.QtGui import QMessageBox except: from python_qt_binding.QtWidgets import QMessageBox result = QMessageBox.question( None, "Kill SCREENs?", '\n'.join(screens), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok) if result & QMessageBox.Ok: do_kill = True if do_kill: for s in screens: pid, _, _ = s.partition('.') if pid: try: nm.starter()._kill_wo(host, int(pid), auto_ok_request, user, pw) except: import traceback rospy.logwarn( "Error while kill screen (PID: %s) on host '%s': %s", str(pid), str(host), traceback.format_exc(1)) if nm.is_local(host): SupervisedPopen( [cls.SCREEN, '-wipe'], object_id='screen -wipe', description="screen: clean up the socket with -wipe" ) else: nm.ssh().ssh_exec(host, [cls.SCREEN, '-wipe'], close_stdin=True, close_stdout=True, close_stderr=True) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError(e, cls.killScreens, (node, host, auto_ok_request))
def click_btnApply(self): self.clear_checked() quit_msg = "Are you sure you want to Apply this configuration?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) if reply == QMessageBox.Yes: pass else: pass
def click_btnRemoveRobot(self): quit_msg = "Are you sure you want to remove this element?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) item = self.env_robot_tree_widget.currentItem() if reply == QMessageBox.Yes: xml_info = XmlInfo() #xml_info.remove_robot_list_variable(item.text(0)) xml_info.modify_deleted_robot_list_variable(item.text(0)) self.removeSelectedItemWidgetTree()
def msg_type_changed(self, type_name): if not type_name: if hasattr(self, 'message_info'): self._widget.msg_type_combo_box.setEditText( self.message_info['type_name']) return # initialization with empty string; just ignore if self._create_message_instance(type_name) is None: QMessageBox.critical(self._widget, 'Change Message Type', 'Unrecognized message type', QMessageBox.Ok) if hasattr(self, 'message_info'): self._widget.msg_type_combo_box.setEditText( self.message_info['type_name']) else: self._widget.msg_type_combo_box.setEditText('') return if hasattr(self, 'message_info'): if self.message_info['type_name'] == type_name: return # selected same type as current, just ignore answer = QMessageBox.question(self._widget, 'Change Message Type', 'Are you sure you want to change current message type?\n'\ 'All changes will be discarded!', QMessageBox.Ok, QMessageBox.Cancel) if answer != QMessageBox.Ok: self._widget.msg_type_combo_box.setEditText( self.message_info['type_name']) return self.clean_up_message() self.message_info = { 'type_name': str(type_name), 'instance': self._create_message_instance(str(type_name)) } # Ask for filling the message with annotation's fields likely to be the same answer = QMessageBox.question(self._widget, "Fill Message's Fields", "Do you want to copy matching fields from the annotation?\n" \ "You can change the suggested values later", QMessageBox.Yes, QMessageBox.No) if answer == QMessageBox.Yes: self._set_message(self.message_info, self.annotation) else: self._set_message(self.message_info)
def _stop_teleop_cb(self): ''' Sends the stop teleop command IGC ''' msg = Bool() msg.data = True ret = QMessageBox.question(self._widget, "Stop Arm Teleop", 'Do you want to stop the arm teleoperation?', QMessageBox.Ok, QMessageBox.Cancel) if ret == QMessageBox.Ok: self.teleop_done_pub.publish(msg)
def msg_type_changed(self, type_name): if not type_name: if hasattr(self, 'message_info'): self._widget.msg_type_combo_box.setEditText(self.message_info['type_name']) return # initialization with empty string; just ignore if self._create_message_instance(type_name) is None: QMessageBox.critical(self._widget, 'Change Message Type', 'Unrecognized message type', QMessageBox.Ok) if hasattr(self, 'message_info'): self._widget.msg_type_combo_box.setEditText(self.message_info['type_name']) else: self._widget.msg_type_combo_box.setEditText('') return if hasattr(self, 'message_info'): if self.message_info['type_name'] == type_name: return # selected same type as current, just ignore answer = QMessageBox.question(self._widget, 'Change Message Type', 'Are you sure you want to change current message type?\n'\ 'All changes will be discarded!', QMessageBox.Ok, QMessageBox.Cancel) if answer != QMessageBox.Ok: self._widget.msg_type_combo_box.setEditText(self.message_info['type_name']) return self.clean_up_message() self.message_info = { 'type_name': str(type_name), 'instance': self._create_message_instance(str(type_name)) } # Ask for filling the message with annotation's fields likely to be the same answer = QMessageBox.question(self._widget, "Fill Message's Fields", "Do you want to copy matching fields from the annotation?\n" \ "You can change the suggested values later", QMessageBox.Yes, QMessageBox.No) if answer == QMessageBox.Yes: self._set_message(self.message_info, self.annotation) else: self._set_message(self.message_info)
def _handle_custom_keypress(self, event, old_keyPressEvent=QTableView.keyPressEvent): """ Handles the delete key. The delete key removes the tableview's selected rows from the datamodel """ if event.key() == Qt.Key_Delete and len(self._model._messages) > 0: delete = QMessageBox.Yes if len(self.table_view.selectionModel().selectedIndexes()) == 0: delete = QMessageBox.question(self, self.tr('Message'), self.tr("Are you sure you want to delete all messages?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if delete == QMessageBox.Yes and event.key() == Qt.Key_Delete and event.modifiers() == Qt.NoModifier: if self._delete_selected_rows(): event.accept() return old_keyPressEvent(self.table_view, event)
def click_btnRemoveRos(self): quit_msg = "Are you sure you want to remove this element?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) item = self.env_ros_tree_widget.currentItem() if reply == QMessageBox.Yes: xml_info = XmlInfo() xml_info.modify_deleted_status_general_variable(item.text(0)) self.remove_Selected_Item_WidgetTree_ros() self.txtVariableRos.setText("") self.txtValueRos.setText("") self.txtVariableRos.setEnabled(True) self.btnRemoveRos.setEnabled(False) self.btnNewRos.setFocus() self.btnSaveRos.setEnabled(False)
def _handle_custom_keypress(self, event, old_keyPressEvent=QTableView.keyPressEvent): """ Handles the delete key. The delete key removes the tableview's selected rows from the datamodel """ if event.key() == Qt.Key_Delete and len(self._datamodel.get_message_list()) > 0: delete = QMessageBox.Yes if len(self.table_view.selectionModel().selectedIndexes()) == 0: delete = QMessageBox.question(self, self.tr('Message'), self.tr("Are you sure you want to delete all messages?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if delete == QMessageBox.Yes and event.key() == Qt.Key_Delete and event.modifiers() == Qt.NoModifier: if self._delete_selected_rows(): self.update_status() event.accept() return old_keyPressEvent(self.table_view, event)
def _reset_steering_encoder_cb(self): ''' Resets the steering encoder ''' msg = Empty() ret = QMessageBox.question(self._widget, "Reset Encoder", 'Are you sure of resetting the encoder?', QMessageBox.Ok, QMessageBox.Cancel) if ret == QMessageBox.Ok: try: self._reset_steering_encoder_service_client() except rospy.ROSInterruptException,e: rospy.logerr('MissionCommanderGUI:_reset_steering_encoder_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command') except rospy.ServiceException,e: rospy.logerr('MissionCommanderGUI:_reset_steering_encoder_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command')
def click_btnRemoveRobot(self): quit_msg = "Are you sure you want to remove this element?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) item = self.treeWidgetRobot.currentItem() if reply == QMessageBox.Yes: xml_dialog = DialogXml() xml_dialog.remove_robot_variable(item.text(0),self.txtAlias.text().strip()) self.remove_selected_item_widgetTree() self.txtVariableRobot.setText("") self.txtValueRobot.setText("") self.txtVariableRobot.setEnabled(True) self.btnRemoveRobot.setEnabled(False) self.btnAddRobot.setEnabled(True) self.btnAddRobot.setFocus() else: pass
def accept(self): if hasattr(self, 'message_info'): self.user_action = EditAnnotationsDataResponse.UPDATE else: # User pressed accept buy we have not message under edition; # if the user confirms, the current data will be discarded answer = QMessageBox.question(self._widget, 'Delete Existing Message', 'No message under edition. Continue will delete any existing data\n'\ 'Are you sure?', QMessageBox.Yes, QMessageBox.Cancel) if answer != QMessageBox.Yes: return self.user_action = EditAnnotationsDataResponse.DELETE # Both on cancel and accept we let some margin for the service handler to complete rospy.sleep(0.5) self.shutdown_plugin() sys.exit(0)
def click_btnRemoveRobot(self): quit_msg = "Are you sure you want to remove this element?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) item = self.treeWidgetRobot.currentItem() if reply == QMessageBox.Yes: xml_dialog = DialogXml() xml_dialog.modify_deleted_status_variable( item.text(0), self.txtAlias.text().strip()) self.remove_selected_item_widgetTree() self.txtVariableRobot.setText("") self.txtValueRobot.setText("") self.txtVariableRobot.setEnabled(True) self.btnRemoveRobot.setEnabled(False) self.btnAddRobot.setEnabled(True) self.btnAddRobot.setFocus()
def focusInEvent(self, event): # check for file changes try: if self.filename and self.file_info: if self.file_info.lastModified() != QFileInfo(self.filename).lastModified(): self.file_info = QFileInfo(self.filename) result = QMessageBox.question(self, "File changed", "File was changed, reload?", QMessageBox.Yes | QMessageBox.No) if result == QMessageBox.Yes: f = QFile(self.filename) if f.open(QIODevice.ReadOnly | QIODevice.Text): self.setText(unicode(f.readAll(), "utf-8")) self.document().setModified(False) self.textChanged.emit() else: QMessageBox.critical(self, "Error", "Cannot open launch file%s" % self.filename) except: pass QTextEdit.focusInEvent(self, event)
def _initialize_platform_cb(self): ''' Initialize platform encoders ''' msg = Empty() ret = QMessageBox.question(self._widget, "Init platform", 'Are you sure of initializing?', QMessageBox.Ok, QMessageBox.Cancel) if ret == QMessageBox.Ok: try: self._initialize_platform_service_client() except rospy.ROSInterruptException,e: rospy.logerr('MissionCommanderGUI:_initialize_platform_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command') except rospy.ServiceException,e: rospy.logerr('MissionCommanderGUI:_initialize_platform_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command')
def _stop_vehicle_cb(self): ''' Sends the stopcommand to the platform ''' msg = PlatformCommand() msg.command = 'cancel' ret = QMessageBox.question(self._widget, "Stop Vehicle", 'Do you want to stop the vehicle?', QMessageBox.Ok, QMessageBox.Cancel) if ret == QMessageBox.Ok: try: self._platform_command_service_client(msg) except rospy.ROSInterruptException,e: rospy.logerr('MissionCommanderGUI:_stop_vehicle_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command') except rospy.ServiceException,e: rospy.logerr('MissionCommanderGUI:_stop_vehicle_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command')
def _fold_crane_cb(self): ''' Sends the foldCrane command to the platform ''' msg = PlatformCommand() msg.command = 'foldCrane' ret = QMessageBox.question(self._widget, "Fold Crane", 'Do you want to fold the crane?', QMessageBox.Ok, QMessageBox.Cancel) if ret == QMessageBox.Ok: try: self._platform_command_service_client(msg) except rospy.ROSInterruptException,e: rospy.logerr('MissionCommanderGUI:_fold_crane_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command') except rospy.ServiceException,e: rospy.logerr('MissionCommanderGUI:_fold_crane_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command')
def _set_control_mode_cb(self): ''' Sets the platform control mode ''' msg = SetControlMode() msg.mode = self._widget.comboBox_control_mode.currentText() ret = QMessageBox.question(self._widget, "Set Control Mode", 'Set control mode to %s?'%msg.mode, QMessageBox.Ok, QMessageBox.Cancel) if ret == QMessageBox.Ok: try: self._set_control_mode_service_client(msg.mode) except rospy.ROSInterruptException,e: rospy.logerr('MissionCommanderGUI:_set_control_mode_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command') except rospy.ServiceException,e: rospy.logerr('MissionCommanderGUI:_set_control_mode_cb: %s',e) QMessageBox.warning(self._widget, 'Error', 'Error sending the command')
def mouseReleaseEvent(self, event): ''' Opens the new editor, if the user clicked on the included file and sets the default cursor. ''' if event.modifiers() == Qt.ControlModifier or event.modifiers( ) == Qt.ShiftModifier: cursor = self.cursorForPosition(event.pos()) index = self.index(cursor.block().text()) if index > -1: startIndex = cursor.block().text().find('"', index) if startIndex > -1: endIndex = cursor.block().text().find('"', startIndex + 1) fileName = cursor.block().text()[startIndex + 1:endIndex] if len(fileName) > 0: try: qf = QFile(interpret_path(fileName)) if not qf.exists(): # create a new file, if it does not exists result = QMessageBox.question( self, "File not found", '\n\n'.join( ["Create a new file?", qf.fileName()]), QMessageBox.Yes | QMessageBox.No) if result == QMessageBox.Yes: d = os.path.dirname(qf.fileName()) if not os.path.exists(d): os.makedirs(d) with open(qf.fileName(), 'w') as f: if qf.fileName().endswith('.launch'): f.write('<launch>\n\n</launch>') event.setAccepted(True) self.load_request_signal.emit( qf.fileName()) else: event.setAccepted(True) self.load_request_signal.emit(qf.fileName()) except Exception, e: WarningMessageBox(QMessageBox.Warning, "File not found %s" % fileName, str(e)).exec_()
def click_btn_apply(self): if self.validate_checked(): quit_msg = "Are you sure you want to Apply this configuration?" reply = QMessageBox.question(self, 'Message', quit_msg, QMessageBox.Yes, QMessageBox.No) self.get_selected_robot_checked() if reply == QMessageBox.Yes: xml_info = XmlInfo() env_os = EnvOs() dialog_xml = DialogXml() deleted_general_items = xml_info.get_deleted_general_variable( ) #get deleted general items (deleted status = 1 in xml) variable_general_items = xml_info.get_general_variables() dialog_xml.get_deleted_variable_robot() deleted_robots_items = dialog_xml.get_deleted_variable_robot() variable_robot_items, active_robot = dialog_xml.get_general_variable_robot( ) deleted_robot = dialog_xml.get_deleted_robot() asociative_variable_robot = dialog_xml.get_asociative_robot_variable( ) env_os.unset_to_htbash(deleted_robots_items + deleted_robots_items) env_os.export_to_general_htbash(variable_general_items) env_os.export_to_robot_htbash(variable_robot_items, active_robot) dialog_xml.remove_asociative_robot_variable( asociative_variable_robot) for item in deleted_robot: dialog_xml.remove_robot_list_variable(item) for item in deleted_general_items: xml_info.remove_general_variable(item) env_os.include_htbash() self.lblmsg.setText("write file .htbash successfully") else: pass else: QMessageBox.information(self, 'Checked validate', "You only must select one active robot")
def killScreens(cls, node, host, auto_ok_request=True, user=None, pw=None): ''' Searches for the screen associated with the given node and kill this screens. @param node: the name of the node those screen output to show @type node: C{str} @param host: the host name or ip where the screen is running @type host: C{str} ''' if node is None or len(node) == 0: return False try: # get the available screens screens = cls._getActiveScreens(host, cls.createSessionName(node), auto_ok_request, user=user, pwd=pw) # user=user, pwd=pwd if screens: do_kill = True if auto_ok_request: try: from python_qt_binding.QtGui import QMessageBox except: from python_qt_binding.QtWidgets import QMessageBox result = QMessageBox.question(None, "Kill SCREENs?", '\n'.join(screens), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok) if result & QMessageBox.Ok: do_kill = True if do_kill: for s in screens: pid, _, _ = s.partition('.') if pid: try: nm.starter()._kill_wo(host, int(pid), auto_ok_request, user, pw) except: import traceback rospy.logwarn("Error while kill screen (PID: %s) on host '%s': %s", str(pid), str(host), traceback.format_exc(1)) if nm.is_local(host): SupervisedPopen([cls.SCREEN, '-wipe'], object_id='screen -wipe', description="screen: clean up the socket with -wipe") else: nm.ssh().ssh_exec(host, [cls.SCREEN, '-wipe'], close_stdin=True, close_stdout=True, close_stderr=True) except nm.AuthenticationRequest as e: raise nm.InteractionNeededError(e, cls.killScreens, (node, host, auto_ok_request))
def focusInEvent(self, event): # check for file changes try: if self.filename and self.file_info: if self.file_info.lastModified() != QFileInfo( self.filename).lastModified(): self.file_info = QFileInfo(self.filename) result = QMessageBox.question( self, "File changed", "File was changed, reload?", QMessageBox.Yes | QMessageBox.No) if result == QMessageBox.Yes: f = QFile(self.filename) if f.open(QIODevice.ReadOnly | QIODevice.Text): self.setText(unicode(f.readAll(), "utf-8")) self.document().setModified(False) self.textChanged.emit() else: QMessageBox.critical( self, "Error", "Cannot open launch file%s" % self.filename) except: pass QTextEdit.focusInEvent(self, event)
def on_remove_stiffness(self): reply = QMessageBox.question(self, 'Caution', 'Robot may fall. Continue to remove stiffness?', QMessageBox.Yes, QMessageBox.No) if(reply == QMessageBox.Yes): self.stiffnessDisableClient.call()
def on_remove_stiffness(self): reply = QMessageBox.question( self, 'Caution', 'Robot may fall. Continue to remove stiffness?', QMessageBox.Yes, QMessageBox.No) if (reply == QMessageBox.Yes): self.stiffnessDisableClient.call()