button_general.py
Go to the documentation of this file.
1 from distutils.version import LooseVersion
2 import math
3 import os
4 import sys
5 
6 import python_qt_binding
7 import python_qt_binding.QtCore as QtCore
8 from python_qt_binding.QtCore import QEvent
9 from python_qt_binding.QtCore import QSize
10 from python_qt_binding.QtCore import Qt
11 from python_qt_binding.QtCore import QTimer
12 from python_qt_binding.QtCore import qWarning
13 from python_qt_binding.QtCore import Slot
14 import python_qt_binding.QtGui as QtGui
15 from python_qt_binding.QtGui import QBrush
16 from python_qt_binding.QtGui import QColor
17 from python_qt_binding.QtGui import QFont
18 from python_qt_binding.QtGui import QIcon
19 from python_qt_binding.QtGui import QPainter
20 from python_qt_binding.QtGui import QPen
21 import yaml
22 
23 from resource_retriever import get_filename
24 import rospy
25 from rqt_gui_py.plugin import Plugin
26 from std_msgs.msg import Bool
27 from std_msgs.msg import Time
28 from std_srvs.srv import Empty
29 from std_srvs.srv import SetBool
30 from std_srvs.srv import Trigger
31 
32 if LooseVersion(python_qt_binding.QT_BINDING_VERSION).version[0] >= 5:
33  from python_qt_binding.QtWidgets import QAction
34  from python_qt_binding.QtWidgets import QComboBox
35  from python_qt_binding.QtWidgets import QCompleter
36  from python_qt_binding.QtWidgets import QDialog
37  from python_qt_binding.QtWidgets import QGroupBox
38  from python_qt_binding.QtWidgets import QHBoxLayout
39  from python_qt_binding.QtWidgets import QLineEdit
40  from python_qt_binding.QtWidgets import QMenu
41  from python_qt_binding.QtWidgets import QMessageBox
42  from python_qt_binding.QtWidgets import QPushButton
43  from python_qt_binding.QtWidgets import QRadioButton
44  from python_qt_binding.QtWidgets import QSizePolicy
45  from python_qt_binding.QtWidgets import QToolButton
46  from python_qt_binding.QtWidgets import QVBoxLayout
47  from python_qt_binding.QtWidgets import QWidget
48 
49 else:
50  from python_qt_binding.QtGui import QAction
51  from python_qt_binding.QtGui import QComboBox
52  from python_qt_binding.QtGui import QCompleter
53  from python_qt_binding.QtGui import QDialog
54  from python_qt_binding.QtGui import QGroupBox
55  from python_qt_binding.QtGui import QHBoxLayout
56  from python_qt_binding.QtGui import QLineEdit
57  from python_qt_binding.QtGui import QMenu
58  from python_qt_binding.QtGui import QMessageBox
59  from python_qt_binding.QtGui import QPushButton
60  from python_qt_binding.QtGui import QRadioButton
61  from python_qt_binding.QtGui import QSizePolicy
62  from python_qt_binding.QtGui import QToolButton
63  from python_qt_binding.QtGui import QVBoxLayout
64  from python_qt_binding.QtGui import QWidget
65 
66 
67 class LineEditDialog(QDialog):
68  def __init__(self, parent=None):
69  super(LineEditDialog, self).__init__()
70  self.value = None
71  vbox = QVBoxLayout(self)
72  # combo box
73  model = QtGui.QStandardItemModel(self)
74  for elm in rospy.get_param_names():
75  model.setItem(model.rowCount(), 0, QtGui.QStandardItem(elm))
76  self.combo_box = QComboBox(self)
77  self.line_edit = QLineEdit()
78  self.combo_box.setLineEdit(self.line_edit)
79  self.combo_box.setCompleter(QCompleter())
80  self.combo_box.setModel(model)
81  self.combo_box.completer().setModel(model)
82  self.combo_box.lineEdit().setText('')
83  vbox.addWidget(self.combo_box)
84  # button
85  button = QPushButton()
86  button.setText("Done")
87  button.clicked.connect(self.buttonCallback)
88  vbox.addWidget(button)
89  self.setLayout(vbox)
90 
91  def buttonCallback(self, event):
92  self.value = self.line_edit.text()
93  self.close()
94 
95 
97  """
98  Qt widget to visualize multiple buttons
99  """
100  def __init__(self, button_type="push"):
101  super(ServiceButtonGeneralWidget, self).__init__()
102  self.button_type = button_type
103  self._layout_param = None
105 
106  if rospy.has_param("~layout_yaml_file"):
107  self.loadLayoutYaml(None)
108 
109  self.show()
110 
111  def showError(self, message):
112  QMessageBox.about(self, "ERROR", message)
113 
114  def loadLayoutYaml(self, layout_param):
115  # Initialize layout of the buttons from yaml file
116  # The yaml file can be specified by rosparam
117  layout_yaml_file = rospy.get_param("~layout_yaml_file", layout_param)
118  resolved_layout_yaml_file = get_filename(
119  layout_yaml_file)[len("file://"):]
120  # check file exists
121  if not os.path.exists(resolved_layout_yaml_file):
122  self.showError("Cannot find %s (%s)" % (
123  layout_yaml_file, resolved_layout_yaml_file))
124  sys.exit(1)
125  self.setupButtons(resolved_layout_yaml_file)
126  self.show()
127 
128  def setupButtons(self, yaml_file):
129  """
130  Parse yaml file and setup Buttons. Format of the yaml file should be:
131  - name: 'button name' (required)
132  image: 'path to image for icon' (optional)
133  image_size: 'width and height of icon' (optional)
134  service: 'service' (required)
135  column: 'column index' (optional, defaults to 0)
136  """
137  self.buttons = []
138  with open(yaml_file) as f:
139  yaml_data = yaml.load(f)
140  # lookup colum direction
141  direction = 'vertical'
142  for d in yaml_data:
143  if d.has_key('direction'):
144  if d['direction'] == 'horizontal':
145  direction = 'horizontal'
146  else: # d['direction'] == 'vertical':
147  direction = 'vertical'
148  yaml_data.remove(d)
149  break
150  # lookup column num
151  column_indices = [d['column'] for d in yaml_data]
152  if len(column_indices) > 1:
153  max_column_index = max(*column_indices)
154  else:
155  max_column_index = column_indices[0]
156  if direction == 'vertical':
157  self.layout = QHBoxLayout()
158  self.layout_boxes = [QVBoxLayout()
159  for i in range(max_column_index + 1)]
160  else: # direction == 'horizontal'
161  self.layout = QVBoxLayout()
162  self.layout_boxes = [QHBoxLayout()
163  for i in range(max_column_index + 1)]
164  self.button_groups = [QGroupBox()
165  for i in range(max_column_index + 1)]
166  for button_data in yaml_data:
167  # check if all the field is available
168  if not button_data.has_key("name"):
169  self.showError("name field is missed in yaml")
170  raise Exception("name field is missed in yaml")
171  if not button_data.has_key("service"):
172  self.showError("service field is missed in yaml")
173  raise Exception("service field is missed in yaml")
174  if self.button_type == "push":
175  button = QToolButton()
176  else: # self.button_type == "radio":
177  button = QRadioButton()
178  button.setSizePolicy(
179  QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred))
180  if button_data.has_key("image"):
181  image_file = get_filename(
182  button_data["image"])[len("file://"):]
183  if os.path.exists(image_file):
184  icon = QtGui.QIcon(image_file)
185  button.setIcon(icon)
186  if button_data.has_key("image_size"):
187  button.setIconSize(QSize(
188  button_data["image_size"][0],
189  button_data["image_size"][1]))
190  else:
191  button.setIconSize(QSize(100, 100))
192  if button_data.has_key("name"):
193  name = button_data['name']
194  button.setText(name)
195  if button_data.has_key('service_type'):
196  if button_data['service_type'] == 'Trigger':
197  service_type = Trigger
198  elif button_data['service_type'] == 'Empty':
199  service_type = Empty
200  elif button_data['service_type'] == 'SetBool':
201  service_type = SetBool
202  else:
203  raise Exception("Unsupported service type: {}".format(
204  button_data['service_type']))
205  else:
206  service_type = Empty
207  if service_type == SetBool:
208  button.setCheckable(True)
209  button.clicked.connect(
210  self.buttonCallback(button_data['service'], service_type, button))
211  if self.button_type == "push":
212  button.setToolButtonStyle(
213  QtCore.Qt.ToolButtonTextUnderIcon)
214  if ((self.button_type == "radio" or service_type == SetBool)
215  and ("default_value" in button_data
216  and button_data['default_value'])):
217  button.setChecked(True)
218  self.layout_boxes[button_data['column']].addWidget(button)
219  self.buttons.append(button)
220  for i in range(len(self.button_groups)):
221  self.button_groups[i].setLayout(self.layout_boxes[i])
222  for group in self.button_groups:
223  self.layout.addWidget(group)
224  self.setLayout(self.layout)
225 
226  def buttonCallback(self, service_name, service_type, button):
227  """
228  return function as callback
229  """
230  return lambda checked: self.buttonCallbackImpl(checked, service_name, service_type, button)
231 
232  def buttonCallbackImpl(self, checked, service_name, service_type=Empty, button=None):
233  srv = rospy.ServiceProxy(service_name, service_type)
234  try:
235  if service_type == SetBool:
236  res = srv(checked)
237  else:
238  res = srv()
239  if hasattr(res, 'success'):
240  success = res.success
241  if not success:
242  self.showError(
243  "Succeeded to call {}, but service response is res.success=False"
244  .format(service_name))
245  if service_type == SetBool and not button is None:
246  button.setChecked(not checked)
247  except rospy.ServiceException as e:
248  self.showError("Failed to call %s" % service_name)
249  if service_type == SetBool and not button is None:
250  button.setChecked(not checked)
251 
252  def save_settings(self, plugin_settings, instance_settings):
253  if self._layout_param:
254  instance_settings.set_value("layout_param", self._layout_param)
255  rospy.loginfo("save setting is called. %s" % self._layout_param)
256 
257  def restore_settings(self, plugin_settings, instance_settings):
258  if instance_settings.value("layout_param"):
259  self._layout_param = instance_settings.value("layout_param")
260  self.loadLayoutYaml(self._layout_param)
261  rospy.loginfo("restore setting is called. %s" % self._layout_param)
262 
264  self._dialog.exec_()
265  self._layout_param = self._dialog.value
266  self.loadLayoutYaml(self._layout_param)
267  rospy.loginfo(
268  "trigger configuration is called. %s" % self._dialog.value)
def buttonCallbackImpl(self, checked, service_name, service_type=Empty, button=None)
def buttonCallback(self, service_name, service_type, button)
def restore_settings(self, plugin_settings, instance_settings)
def save_settings(self, plugin_settings, instance_settings)


jsk_rqt_plugins
Author(s):
autogenerated on Sat Mar 20 2021 03:03:13