Changeset 760 for moxy/trunk
- Timestamp:
- Jan 7, 2012 2:50:40 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified moxy/trunk/src/moxy/vc_axis.py ¶
r757 r760 70 70 "Do you really want to close this application?", 71 71 "Confirm Exit", wx.OK|wx.CANCEL|wx.ICON_QUESTION) 72 result = wx.ID_OK # development72 #result = wx.ID_OK # development 73 73 result = dlg.ShowModal() # production 74 74 dlg.Destroy() … … 98 98 99 99 wx.Panel.__init__(self, id=wx.ID_ANY, parent=parent) 100 self.SetToolTipString( self.axis.val.pvname)100 self.SetToolTipString( u'SingleAxisPanel' ) 101 101 102 102 # tabbed notebook: Operate | Setup 103 103 self.notebook = wx.Notebook( self ) 104 104 105 # TODO: make each page (panel) a separate class so each can be called from vc_set.py 106 operate_panel = self._Make_Operate_Panel( self.notebook ) 107 setup_panel = self._Make_Setup_Panel( self.notebook ) 108 109 self.notebook.AddPage( operate_panel, "operate" ) 110 self.notebook.AddPage( setup_panel, "setup" ) 105 self.operate_panel = SingleAxisOperatePanel(self.notebook, 106 axis, show_buttons, 107 handler = None) 108 self.setup_panel = SingleAxisSetupPanel(self.notebook, 109 axis, show_buttons, 110 operate_panel = self.operate_panel, 111 handler = None) 112 113 self.notebook.AddPage( self.operate_panel, "operate" ) 114 self.notebook.AddPage( self.setup_panel, "setup" ) 111 115 112 116 sizer = wx.BoxSizer( orient=wx.VERTICAL ) … … 114 118 self.SetSizer( sizer ) 115 119 116 self.connect() 117 self._Set_All_PvWidgetBackgroundColours() 118 119 def _Make_Operate_Panel(self, parent): 120 ''' Create (and return) a panel to operate this axis ''' 121 # TODO: make into separate class so can be callable from vc_set.py 122 panel = wx.Panel( parent ) 123 120 self.operate_panel.connect() 121 self.setup_panel._Set_All_PvWidgetBackgroundColours() 122 123 124 class SingleAxisOperatePanel(wx.Panel): 125 ''' 126 Show the widgets to operate a single motion axis in a panel. 127 128 Some buttons (Connect, Disconnect, ...) are optional 129 and can be suppressed by adding ``show_buttons = False`` 130 131 :param obj parent: panel or frame that contains this panel 132 :param axis: set of PVs that describe the operation of this axis 133 :type axis: m_axis.SingleAxis object 134 :param bool show_buttons: suppress display of certain buttons 135 :param obj handler: callback routine for TextCtrl widget accept events 136 ''' 137 138 def __init__(self, parent, axis, show_buttons = True, handler = None): 139 self.parent = parent 140 self.axis = axis 141 self.show_buttons = show_buttons 142 self.handler = {True: handler, 143 False: self.callback}[handler is not None] 144 self.connected = False 145 146 wx.Panel.__init__(self, id=wx.ID_ANY, parent=parent) 147 self.SetToolTipString( self.axis.val.pvname ) 148 self._init_panel(self) 149 150 def _init_panel(self, panel): 124 151 description_sizer = self._Make_Description_Sizer( panel ) 125 152 position_sizer = self._Make_Positions_Sizer( panel ) 126 self.stopButton = self._Make_My_Button(panel, 127 label=u'Stop', name='stopButton', 128 tip=u'Stop this axis from moving', 129 binding=self.doStopButton) 153 self.stopButton = Make_My_Button(panel, 154 label=u'Stop', 155 name='stopButton', 156 tip=u'Stop this axis from moving', 157 binding=self.doStopButton) 130 158 self.stopButton.SetBackgroundColour('red') 131 159 self.stopButton.SetForegroundColour('yellow') … … 138 166 sizer.AddSizer(position_sizer, 1, flag=wx.EXPAND) 139 167 sizer.AddSizer(self.stopButton, 0, flag=wx.EXPAND) 140 141 return panel142 168 143 169 def _Make_Description_Sizer(self, parent): … … 178 204 self.w_readback.SetToolTipString(u'readback value') 179 205 180 self.w_target = self._Make_My_TextEntry(parent, '',181 False, u'target value', self.do ConfigureHandler)206 self.w_target = Make_My_TextEntry(parent, '', 207 False, u'target value', self.doTargetEntry) 182 208 183 209 self.w_status = wx.lib.stattext.GenStaticText(parent, wx.ID_ANY, 'status') … … 199 225 return sbs 200 226 201 def _Make_Setup_Panel(self, parent): 202 ''' Create (and return) a panel to configure this axis ''' 203 # TODO: make into separate class so can be callable from vc_set.py 204 panel = wx.Panel( parent ) 205 227 def doTargetEntry(self, event): 228 ''' [Enter] was pressed in target field, need to tell axis to move ''' 229 obj = event.EventObject 230 if obj == self.w_target: 231 if self.axis.val.channel.connected: 232 s = obj.GetValue() 233 try: 234 value = float( s ) 235 self.axis.val.channel.put( value ) 236 except ValueError: 237 msg = '''"%s" is not a floating point number!''' % s 238 AcknowledgeDialog( msg ) 239 240 def doStopButton(self, event): 241 '''stop this axis from moving''' 242 self.axis.stopMotion() 243 244 def SetStatus(self, value): 245 '''describe what's what''' 246 #wx.CallAfter(self.w_status.SetLabel, value) 247 print "status: ", value 248 249 def connect(self): 250 '''connect the PVs of this axis with EPICS''' 251 if not self.connected: 252 self.axis.connect(ext_handler=self.callback) 253 self.SetStatus( 'connected' ) 254 #self.w_name.SetEditable(False) 255 self.w_target.SetEditable(True) 256 self.connected = True 257 self.gst_name.SetLabel( self.axis.name ) 258 self.SetToolTipString( self.axis.val.pvname ) 259 260 def disconnect(self): 261 '''connect the PVs of this axis from EPICS''' 262 if self.connected: 263 self.axis.disconnect() 264 self.SetStatus( 'disconnected' ) 265 #self.w_name.SetEditable(True) 266 self.w_target.SetEditable(False) 267 self.connected = False 268 269 def SetVAL(self, value): 270 '''put the value into the widget text''' 271 wx.CallAfter(self.w_target.SetValue, str(value) ) 272 273 def SetRBV(self, value): 274 '''put the value into the widget text''' 275 wx.CallAfter(self.w_readback.SetLabel, str(value) ) 276 277 def SetEGU(self, value): 278 '''put the value into the widget text''' 279 wx.CallAfter(self.w_egu.SetLabel, value) 280 281 def SetDESC(self, value): 282 '''put the value into the widget text''' 283 wx.CallAfter(self.w_desc.SetLabel, value) 284 285 def SetDMOV(self, value): 286 '''set the widget background color based on moving state''' 287 moving = not value 288 color = {False: COLOR_NOT_MOVING, True: COLOR_MOVING}[moving] 289 wx.CallAfter(self.w_target.SetBackgroundColour, color ) 290 wx.CallAfter(self.w_readback.SetBackgroundColour, color ) 291 292 def SetSTOP(self, value): 293 '''a no-op''' 294 pass 295 296 def callback(self, **kw): 297 "PyEPICS CA monitor callback" 298 #print kw 299 if 'conn' in kw.keys(): 300 print "connection event", kw 301 choices = {True: 'connected event received', 302 False: 'disconnect received, IOC is unavailable?'} 303 self.SetStatus( choices[ kw['conn'] ] ) 304 else: 305 #print "PV update event" 306 if 'field' in kw: 307 #print kw['field'] 308 {'VAL': self.SetVAL, 309 'RBV': self.SetRBV, 310 'EGU': self.SetEGU, 311 'DESC': self.SetDESC, 312 'DMOV': self.SetDMOV, 313 'STOP': self.SetSTOP, 314 }[ kw['field'] ]( kw['value'] ) 315 316 317 class SingleAxisSetupPanel(wx.Panel): 318 ''' 319 Show the widgets to setup and configure a single motion axis in a panel. 320 321 Some buttons (Connect, Disconnect, ...) are optional 322 and can be suppressed by adding ``show_buttons = False`` 323 324 :param obj parent: panel or frame that contains this panel 325 :param axis: set of PVs that describe the operation of this axis 326 :type axis: m_axis.SingleAxis object 327 :param bool show_buttons: suppress display of certain buttons 328 :param obj handler: callback routine for TextCtrl widget accept events 329 :param obj operate_panel: SingleAxisOperatePanel object to use with this class 330 ''' 331 332 def __init__(self, parent, axis, show_buttons = True, handler = None, operate_panel = None): 333 self.parent = parent 334 self.axis = axis 335 self.show_buttons = show_buttons 336 self.handler = handler 337 self.operate_panel = operate_panel 338 339 wx.Panel.__init__(self, id=wx.ID_ANY, parent=parent) 340 self.SetToolTipString( self.axis.val.pvname ) 341 self._init_panel(self) 342 343 def _init_panel(self, panel): 206 344 if self.show_buttons: 207 345 connect_buttons = self._Make_Connect_Buttons_Sizer( panel ) … … 216 354 sizer.AddSizer(accept_buttons, 0, flag=wx.EXPAND) 217 355 sizer.AddSizer(connect_buttons, 0, flag=wx.EXPAND) 218 219 return panel220 356 221 357 def _Make_Configure_Sizer(self, parent): … … 232 368 label_STOP = wx.lib.stattext.GenStaticText(parent, wx.ID_ANY, 'STOP') 233 369 234 self.w_name = self._Make_My_TextEntry(parent, self.axis.name,370 self.w_name = Make_My_TextEntry(parent, self.axis.name, 235 371 True, u'local name for this axis', 236 372 self.doConfigureHandler) … … 241 377 self.w_isMotor.Bind(wx.EVT_CHECKBOX, self.doCheckboxClick) 242 378 243 self.w_VAL_pv = self._Make_My_TextEntry(parent, self.axis.val.pvname,379 self.w_VAL_pv = Make_My_TextEntry(parent, self.axis.val.pvname, 244 380 True, u'EPICS PV name for target position', 245 381 self.doConfigureHandler) 246 self.w_RBV_pv = self._Make_My_TextEntry(parent, self.axis.rbv.pvname,382 self.w_RBV_pv = Make_My_TextEntry(parent, self.axis.rbv.pvname, 247 383 True, u'EPICS PV name for readback position', 248 384 self.doConfigureHandler) 249 self.w_EGU_pv = self._Make_My_TextEntry(parent, self.axis.egu.pvname,385 self.w_EGU_pv = Make_My_TextEntry(parent, self.axis.egu.pvname, 250 386 True, u'EPICS PV name for engineering units', 251 387 self.doConfigureHandler) 252 self.w_DESC_pv = self._Make_My_TextEntry(parent, self.axis.desc.pvname,388 self.w_DESC_pv = Make_My_TextEntry(parent, self.axis.desc.pvname, 253 389 True, u'EPICS PV name for description', 254 390 self.doConfigureHandler) 255 self.w_DMOV_pv = self._Make_My_TextEntry(parent, self.axis.dmov.pvname,391 self.w_DMOV_pv = Make_My_TextEntry(parent, self.axis.dmov.pvname, 256 392 True, u'EPICS PV name for motion is done', 257 393 self.doConfigureHandler) 258 self.w_STOP_pv = self._Make_My_TextEntry(parent, self.axis.stop.pvname,394 self.w_STOP_pv = Make_My_TextEntry(parent, self.axis.stop.pvname, 259 395 True, u'EPICS PV name for STOP moving command', 260 396 self.doConfigureHandler) … … 267 403 sbs.Add(fgs, 0, wx.EXPAND|wx.ALIGN_CENTRE|wx.ALL, 5) 268 404 269 fgs.Add(label_name, flag=wx.EXPAND|wx.GROW) 270 fgs.Add(self.w_name, flag=wx.EXPAND|wx.GROW) 271 fgs.Add(label_VAL, flag=wx.EXPAND|wx.GROW) 272 fgs.Add(self.w_VAL_pv, flag=wx.EXPAND|wx.GROW) 273 fgs.Add(label_isMotor, flag=wx.EXPAND|wx.GROW) 274 fgs.Add(self.w_isMotor, flag=wx.EXPAND|wx.GROW) 275 fgs.Add(label_RBV, flag=wx.EXPAND|wx.GROW) 276 fgs.Add(self.w_RBV_pv, flag=wx.EXPAND|wx.GROW) 277 fgs.Add(label_EGU, flag=wx.EXPAND|wx.GROW) 278 fgs.Add(self.w_EGU_pv, flag=wx.EXPAND|wx.GROW) 279 fgs.Add(label_DESC, flag=wx.EXPAND|wx.GROW) 280 fgs.Add(self.w_DESC_pv, flag=wx.EXPAND|wx.GROW) 281 fgs.Add(label_DMOV, flag=wx.EXPAND|wx.GROW) 282 fgs.Add(self.w_DMOV_pv, flag=wx.EXPAND|wx.GROW) 283 fgs.Add(label_STOP, flag=wx.EXPAND|wx.GROW) 284 fgs.Add(self.w_STOP_pv, flag=wx.EXPAND|wx.GROW) 405 for obj in (label_name, self.w_name, 406 label_VAL, self.w_VAL_pv, 407 label_isMotor, self.w_isMotor, 408 label_RBV, self.w_RBV_pv, 409 label_EGU, self.w_EGU_pv, 410 label_DESC, self.w_DESC_pv, 411 label_DMOV, self.w_DMOV_pv, 412 label_STOP, self.w_STOP_pv 413 ): 414 fgs.Add(obj, flag=wx.EXPAND|wx.GROW) 285 415 286 416 return sbs 287 417 288 def _Make_My_TextEntry(self, parent, value='',289 editable=True, tooltip='', handler=None):290 '''291 Create and return a TextCtrl object292 293 :param obj parent: widget panel that will contain this TextCtrl294 :param str|float value: initial value to set in the entry field295 :param bool editable: should the entry field be editable?296 :param str tooltip: short description of this field297 :param obj handler: None or method to be called when [Enter] is pressed in this field298 :return: wx.TextCtrl object299 '''300 # TODO: decide the best trigger for _Make_My_TextEntry301 # see doConfigureHandler() for choices302 style = wx.TE_PROCESS_ENTER303 entry = wx.TextCtrl(parent=parent, id=wx.ID_ANY, style=style)304 entry.SetEditable( editable )305 if value is not None:306 entry.SetValue( str(value) )307 entry.SetToolTipString( tooltip )308 if handler is not None:309 entry.Bind(wx.EVT_TEXT_ENTER, handler)310 return entry311 312 418 def _Make_Connect_Buttons_Sizer(self, parent): 313 419 ''' 314 420 build a buttons row and place it in a sizer, return the sizer 315 421 ''' 316 self.connectButton = self._Make_My_Button(parent,422 self.connectButton = Make_My_Button(parent, 317 423 label=u'Connect', name='connectButton', 318 424 tip=u'Connect this axis with EPICS', 319 425 binding=self.doConnnectButton) 320 self.disconnectButton = self._Make_My_Button(parent,426 self.disconnectButton = Make_My_Button(parent, 321 427 label=u'Disconnect', name='disconnectButton', 322 428 tip=u'Disconnect this axis from EPICS', … … 332 438 build a buttons row and place it in a sizer, return the sizer 333 439 ''' 334 self.acceptButton = self._Make_My_Button(parent,440 self.acceptButton = Make_My_Button(parent, 335 441 label=u'Accept', name='acceptButton', 336 442 tip=u'Accept the new PV names', 337 443 binding=self.doAcceptButton) 338 self.revertButton = self._Make_My_Button(parent,444 self.revertButton = Make_My_Button(parent, 339 445 label=u'Revert', name='revertButton', 340 446 tip=u'Revert to previous PV names', … … 345 451 sizer.AddWindow(self.revertButton, proportion=1, flag=wx.EXPAND) 346 452 return sizer 347 348 def _Make_My_Button(self, parent, label, name, tip, binding):349 '''350 Create a button and bind it to a method.351 Return the button object352 '''353 button = wx.lib.buttons.GenButton(id=wx.ID_ANY,354 label=label, name=name, parent=parent,)355 button.SetToolTipString(tip)356 button.Bind(wx.EVT_BUTTON, binding)357 return button358 359 def doStopButton(self, event):360 '''stop this axis from moving'''361 self.axis.stopMotion()362 453 363 454 def doConnnectButton(self, event): 364 455 '''user clicked button to connect''' 365 self. connect()456 self.operate_panel.connect() 366 457 367 458 def doDisconnnectButton(self, event): 368 459 '''user clicked button to disconnect''' 369 self.disconnect() 460 self.operate_panel.disconnect() 461 462 def doAcceptButton(self, event): 463 '''user clicked button to accept PV names''' 464 # filter out any cases why we should not accept 465 result = self._Verify_Fields_Before_Accepting() 466 if result is not None: 467 AcknowledgeDialog( result ) 468 return 469 470 self.operate_panel.disconnect() 471 self.axis.name = self.w_name.GetValue() 472 self.axis.val.pvname = self.w_VAL_pv.GetValue() 473 self.axis.rbv.pvname = self.w_RBV_pv.GetValue() 474 self.axis.egu.pvname = self.w_EGU_pv.GetValue() 475 self.axis.desc.pvname = self.w_DESC_pv.GetValue() 476 self.axis.dmov.pvname = self.w_DMOV_pv.GetValue() 477 self.axis.stop.pvname = self.w_STOP_pv.GetValue() 478 self.axis.isMotorRecord = self.w_isMotor.GetValue() 479 self.operate_panel.connect() 480 self.operate_panel.SetVAL( self.axis.val.channel.get(as_string = True) ) 481 482 def doRevertButton(self, event): 483 '''user clicked button to revert to existing PV name''' 484 self.w_VAL_pv.SetValue( self.axis.val.pvname ) 485 self.w_RBV_pv.SetValue( self.axis.rbv.pvname ) 486 self.w_EGU_pv.SetValue( self.axis.egu.pvname ) 487 self.w_DESC_pv.SetValue( self.axis.desc.pvname ) 488 self.w_DMOV_pv.SetValue( self.axis.dmov.pvname ) 489 self.w_STOP_pv.SetValue( self.axis.stop.pvname ) 490 self.w_isMotor.SetValue( self.axis.isMotorRecord ) 491 self.w_name.SetValue( self.operate_panel.gst_name.GetLabel() ) 492 self._Set_All_PvWidgetBackgroundColours() 493 494 def doCheckboxClick(self, event): 495 ''' isMotorRecord checkbox was clicked ''' 496 #print "isMotorRecord checkbox was clicked" 497 pass 498 499 def doConfigureHandler(self, event): 500 ''' 501 User pressed [Enter] key in a configure panel TextCtrl. 502 Indicate with background color if the given PV name can be connected. 503 504 Consider the best binding/trigger to call ``doConfigureHandler()``. 505 For now, we use choice #1. 506 Choices include: 507 508 # [Enter] key (as used in ``wxmtxy`` tool) 509 # wx.EVT_TEXT events after a time delay 510 ''' 511 obj = event.EventObject 512 if obj in (self.w_VAL_pv, 513 self.w_RBV_pv, 514 self.w_EGU_pv, 515 self.w_DESC_pv, 516 self.w_DMOV_pv, 517 self.w_STOP_pv): 518 self._SetPvWidgetBackgroundColour( obj ) 519 520 def _SetPvWidgetBackgroundColour(self, obj): 521 ''' 522 Decide the background color of a PV widget 523 based on whether or not a PV connection can be 524 established from this client 525 and set the background color of that widget. 526 IF a connection attempt with a given PV name string 527 does not succeed within ``CONNECT_TEST_TIMEOUT`` seconds, 528 the PV will be considered as unavailable. 529 530 ======================= ========================================= 531 color meaning 532 ======================= ========================================= 533 COLOR_PV_NOT_DEFINED no string given for PV name 534 COLOR_PV_OK string given can be connected as a PV 535 COLOR_PV_NOT_OK PV connection timed out for string given 536 ======================= ========================================= 537 ''' 538 pv = obj.GetValue().strip() 539 if len(pv) == 0: 540 color = COLOR_PV_NOT_DEFINED 541 else: 542 valid = m_pv.pvIsAvailable( pv, CONNECT_TEST_TIMEOUT ) 543 color = {True: COLOR_PV_OK, False: COLOR_PV_NOT_OK}[valid] 544 wx.CallAfter( obj.SetBackgroundColour, color ) 545 546 def _Set_All_PvWidgetBackgroundColours(self): 547 ''' 548 Walk through all the PV name widgets and check if they 549 can be connected. Set the background color of each widget 550 accordingly. 551 ''' 552 for obj in (self.w_VAL_pv, 553 self.w_RBV_pv, 554 self.w_EGU_pv, 555 self.w_DESC_pv, 556 self.w_DMOV_pv, 557 self.w_STOP_pv): 558 self._SetPvWidgetBackgroundColour( obj ) 370 559 371 560 def _Verify_Fields_Before_Accepting(self): … … 412 601 return '''cannot connect to PV "%s"''' % val_pv 413 602 return None 414 415 def doAcceptButton(self, event):416 '''user clicked button to accept PV names'''417 # filter out any cases why we should not accept418 result = self._Verify_Fields_Before_Accepting()419 if result is not None:420 self.AcknowledgeDialog( result )421 return422 423 self.disconnect()424 self.axis.val.pvname = self.w_VAL_pv.GetValue()425 self.axis.rbv.pvname = self.w_RBV_pv.GetValue()426 self.axis.egu.pvname = self.w_EGU_pv.GetValue()427 self.axis.desc.pvname = self.w_DESC_pv.GetValue()428 self.axis.dmov.pvname = self.w_DMOV_pv.GetValue()429 self.axis.stop.pvname = self.w_STOP_pv.GetValue()430 self.axis.isMotorRecord = self.w_isMotor.GetValue()431 self.connect()432 self.SetVAL( self.axis.val.channel.get(as_string = True) )433 self.gst_name.SetLabel( self.w_name.GetValue() )434 435 def doRevertButton(self, event):436 '''user clicked button to revert to existing PV name'''437 self.w_VAL_pv.SetValue( self.axis.val.pvname )438 self.w_RBV_pv.SetValue( self.axis.rbv.pvname )439 self.w_EGU_pv.SetValue( self.axis.egu.pvname )440 self.w_DESC_pv.SetValue( self.axis.desc.pvname )441 self.w_DMOV_pv.SetValue( self.axis.dmov.pvname )442 self.w_STOP_pv.SetValue( self.axis.stop.pvname )443 self.w_isMotor.SetValue( self.axis.isMotorRecord )444 self.w_name.SetValue( self.gst_name.GetLabel() )445 self._Set_All_PvWidgetBackgroundColours()446 447 def doCheckboxClick(self, event):448 ''' isMotorRecord checkbox was clicked '''449 #print "isMotorRecord checkbox was clicked"450 pass451 452 def doConfigureHandler(self, event):453 '''user pressed [Enter] key in a configure panel TextCtrl'''454 # TODO: decide the best trigger for doConfigureHandler455 # choices are [Enter] key or wx.EVT_TEXT events after a time delay456 # [Enter] was used in wxmtxy tool457 obj = event.EventObject458 if obj in (self.w_VAL_pv,459 self.w_RBV_pv,460 self.w_EGU_pv,461 self.w_DESC_pv,462 self.w_DMOV_pv,463 self.w_STOP_pv):464 self._SetPvWidgetBackgroundColour( obj )465 else:466 if obj == self.w_target:467 if self.axis.val.channel.connected:468 s = obj.GetValue()469 try:470 value = float( s )471 self.axis.val.channel.put( value )472 except ValueError:473 msg = '''"%s" is not a floating point number!''' % s474 self.AcknowledgeDialog( msg )475 elif obj == self.w_name:476 self.gst_name.SetLabel( obj.GetValue() )477 478 def AcknowledgeDialog(self, msg):479 ''' present a modal dialog box with a message to be acknowledged '''480 dlg = wx.MessageDialog(self, msg,481 "Acknowledge", wx.OK|wx.ICON_EXCLAMATION)482 dlg.ShowModal()483 dlg.Destroy()484 485 def _SetPvWidgetBackgroundColour(self, obj):486 '''487 Decide the background color of a PV widget488 based on whether or not a PV connection can be489 established from this client490 and set the background color of that widget.491 IF a connection attempt with a given PV name string492 does not succeed within ``CONNECT_TEST_TIMEOUT`` seconds,493 the PV will be considered as unavailable.494 495 ======================= =========================================496 color meaning497 ======================= =========================================498 COLOR_PV_NOT_DEFINED no string given for PV name499 COLOR_PV_OK string given can be connected as a PV500 COLOR_PV_NOT_OK PV connection timed out for string given501 ======================= =========================================502 '''503 pv = obj.GetValue().strip()504 if len(pv) == 0:505 color = COLOR_PV_NOT_DEFINED506 else:507 valid = m_pv.pvIsAvailable( pv, CONNECT_TEST_TIMEOUT )508 color = {True: COLOR_PV_OK, False: COLOR_PV_NOT_OK}[valid]509 wx.CallAfter( obj.SetBackgroundColour, color )510 511 def _Set_All_PvWidgetBackgroundColours(self):512 '''513 Walk through all the PV name widgets and check if they514 can be connected. Set the background color of each widget515 accordingly.516 '''517 for obj in (self.w_VAL_pv,518 self.w_RBV_pv,519 self.w_EGU_pv,520 self.w_DESC_pv,521 self.w_DMOV_pv,522 self.w_STOP_pv):523 self._SetPvWidgetBackgroundColour( obj )524 525 def connect(self):526 '''connect the PVs of this axis with EPICS'''527 if not self.connected:528 self.axis.connect(ext_handler=self.callback)529 self.SetStatus( 'connected' )530 #self.w_name.SetEditable(False)531 self.w_target.SetEditable(True)532 self.connected = True533 534 def disconnect(self):535 '''connect the PVs of this axis from EPICS'''536 if self.connected:537 self.axis.disconnect()538 self.SetStatus( 'disconnected' )539 #self.w_name.SetEditable(True)540 self.w_target.SetEditable(False)541 self.connected = False542 543 def SetVAL(self, value):544 '''put the value into the widget text'''545 wx.CallAfter(self.w_target.SetValue, str(value) )546 547 def SetRBV(self, value):548 '''put the value into the widget text'''549 wx.CallAfter(self.w_readback.SetLabel, str(value) )550 551 def SetEGU(self, value):552 '''put the value into the widget text'''553 wx.CallAfter(self.w_egu.SetLabel, value)554 555 def SetDESC(self, value):556 '''put the value into the widget text'''557 wx.CallAfter(self.w_desc.SetLabel, value)558 559 def SetDMOV(self, value):560 '''set the widget background color based on moving state'''561 moving = not value562 color = {False: COLOR_NOT_MOVING, True: COLOR_MOVING}[moving]563 wx.CallAfter(self.w_target.SetBackgroundColour, color )564 wx.CallAfter(self.w_readback.SetBackgroundColour, color )565 566 def SetSTOP(self, value):567 '''a no-op'''568 pass569 570 def SetStatus(self, value):571 '''describe what's what'''572 wx.CallAfter(self.w_status.SetLabel, value)573 574 def callback(self, **kw):575 "PyEPICS CA monitor callback"576 #print kw577 if 'conn' in kw.keys():578 print "connection event", kw579 choices = {True: 'connected event received',580 False: 'disconnect received, IOC is unavailable?'}581 self.SetStatus( choices[ kw['conn'] ] )582 else:583 #print "PV update event"584 if 'field' in kw:585 #print kw['field']586 {'VAL': self.SetVAL,587 'RBV': self.SetRBV,588 'EGU': self.SetEGU,589 'DESC': self.SetDESC,590 'DMOV': self.SetDMOV,591 'STOP': self.SetSTOP,592 }[ kw['field'] ]( kw['value'] )593 603 594 604 595 605 # - - - - - - - - - - - - - - - - - - methods 606 607 608 609 def AcknowledgeDialog(parent, msg): 610 ''' present a modal dialog box with a message to be acknowledged ''' 611 dlg = wx.MessageDialog(parent, msg, 612 "Acknowledge", wx.OK|wx.ICON_EXCLAMATION) 613 dlg.ShowModal() 614 dlg.Destroy() 615 616 617 def Make_My_Button(parent, label, name, tip, binding): 618 ''' 619 Create a button and bind it to a method. 620 Return the button object 621 ''' 622 button = wx.lib.buttons.GenButton(id=wx.ID_ANY, 623 label=label, name=name, parent=parent,) 624 button.SetToolTipString(tip) 625 button.Bind(wx.EVT_BUTTON, binding) 626 return button 627 628 629 def Make_My_TextEntry(parent, value='', 630 editable=True, tooltip='', handler=None): 631 ''' 632 Create and return a TextCtrl object. 633 [Enter] key event is bound to widget to call handler. 634 635 :param obj parent: widget panel that will contain this TextCtrl 636 :param str|float value: initial value to set in the entry field 637 :param bool editable: should the entry field be editable? 638 :param str tooltip: short description of this field 639 :param obj handler: None or method to be called when [Enter] is pressed in this field 640 :return: wx.TextCtrl object 641 ''' 642 style = wx.TE_PROCESS_ENTER 643 entry = wx.TextCtrl(parent=parent, id=wx.ID_ANY, style=style) 644 entry.SetEditable( editable ) 645 if value is not None: 646 entry.SetValue( str(value) ) 647 entry.SetToolTipString( tooltip ) 648 if handler is not None: 649 entry.Bind(wx.EVT_TEXT_ENTER, handler) 650 return entry 596 651 597 652
Note: See TracChangeset
for help on using the changeset viewer.