Creating quick/simple QT-based GUIs in Python
-
Upload
renee-barlow -
Category
Documents
-
view
91 -
download
3
description
Transcript of Creating quick/simple QT-based GUIs in Python
Creating quick/simple QT-based GUIs in Python
Pete R. JemianAdvanced Photon Source, Argonne National Laboratory
2012 EPICS Collaboration MeetingSLAC, Menlo Park, CA
2012-04-24
svn co https://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo / qtprobe-demo documentation: https://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo/docs/build/html/index.html
2
Outline
My tool set A few basics about PyEpics Our target application: EPICS Probe
– PySide Probe, from Matt Newville, CARS– Enthought Tool Suite (ETS) Traits Probe, simple– ETS Traits Probe, more features
NOTE: all code shown in this presentation is available from subversion– svn co http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo ./qtprobe-demo
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
3
Development Tools
OS– Windows 7– Linux: RHEL5, RHEL6, Ubuntu 10.04, 11.04, 11.10– Mac OSX– SunOS 5.10
Python 2.7– Enthought Python Distribution 7.2-2 (http://www.enthought.com/products/epd.php)
• 90+ packages including PyQt and wxPython backends, plus numpy, scipy, matplotlib• Traits (http://code.enthought.com/projects/traits/)
– PyEpics (http://cars9.uchicago.edu/software/python/pyepics3/) eclipse 3.7 (http://eclipse.org)
– PyDev (http://pydev.org/updates)
Usual disclaimers apply here: This is not an endorsement. I just use these tools.
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
4
PyEpics basicshttp://cars9.uchicago.edu/software/python/pyepics3/
PyEpics is a Python interface for Channel Access (CA) Provides EPICS package
– fairly complete– ca module: thin layer over the low-level Channel Access library – PV module: abstraction of EPICS Process Variable as an easy-to-use Python object– Device module: create higher-level abstractions such as Motor or Scaler – Requires EPICS libca & libCom libraries, numpy package is optional
Simple, functional approach to CA (similar to EZCA) Examples of simple commands
– epics.caget()– epics.caput()– epics.camonitor()– epics.cainfo()
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
5
Quick PyEpics demo
jemian@como-ubuntu64:~/...se/qtprobe-demo$ pythonEnthought Python Distribution -- www.enthought.comVersion: 7.2-2 (64-bit)
Python 2.7.2 |EPD 7.2-2 (64-bit)| (default, Jul 3 2011, 15:17:51) [GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2Type "packages", "demo" or "enthought" for more information.>>> import epics>>> print epics.caget('prj:datetime')2012-04-24 08:39:37>>> epics.caput('prj:m1.DESC', 'This is motor 1')1 >>>
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
6
Quick PyEpics demo …
>>> print epics.cainfo('prj:m1.DESC')== prj:m1.DESC (native_string) == value = This is motor 1 char_value = 'This is motor 1' count = 1 nelm = 1 type = string host = dhcpvisitor218180.slac.stanford.edu:5064 access = read/write status = 0 severity = 0 timestamp = 1335274922.470 (2012-04-24 08:42:02.470303) PV is internally monitored, with 0 user-defined callbacks:=============================None>>>
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
7
Our target application: EPICS Probe
Basic Features– Displays current value of any EPICS process variable– Provides a text entry widget for use to change to a different PV
Options– Display metadata about PV– Display alarm status– Display engineering units– Change display format– Change current value of PV– Display timestamp of PV
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
8
PySide (http://www.pyside.org/)
What is PySide?– “The PySide project provides LGPL-licensed Python bindings for the Qt cross-platform
application and UI framework. PySide Qt bindings allow both free open source and proprietary software development and ultimately aim to support all of the platforms as Qt itself.”
– Alternative to PyQt4 package Why?
– PySide is LGPL, more permissive license than PyQt4 which uses GPL– See also: http://stackoverflow.com/questions/1297660/pyside-vs-pyqt
• PySide (LGPL) allows linking from closed source software• PyQt (GPL) does not, and requires separate commercial license.
Key differences from PyQt4– http://qt-project.org/wiki/Differences_Between_PySide_and_PyQt– Different import name (PySide instead of PyQt4)– New-style signals and slots use slightly different syntax (PSEP 100)
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
9
HelloWorld using PySide
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
10
pyside_probe.py : preamble
#!/usr/bin/env python
########### SVN repository information #################### $Date: 2012-04-24 09:42:01 -0500 (Tue, 24 Apr 2012) $# $Author: jemian $# $Revision: 819 $# $URL: https://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo/pyside_probe.py $# $Id: pyside_probe.py 819 2012-04-24 14:42:01Z jemian $########### SVN repository information ###################
# from Matt Newville, CARS, University of Chicago
import epicsimport sysfrom PySide.QtGui import QWidget, QLabel, QLineEdit, QGridLayout, QApplication
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
11
pyside_probe.py : “main”
if __name__ == '__main__': app = QApplication(sys.argv) probe = PVProbe() probe.show() sys.exit(app.exec_())
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
12
pyside_probe.py : PvProbe class and initializationclass PVProbe(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent)
name_label = QLabel("PV Name:") self.pvname = QLineEdit() value_label = QLabel("PV Value:") self.value = QLabel(" "*4)
self.pvname.returnPressed.connect(self.onPVNameReturn) self.pv = None
grid = QGridLayout() grid.addWidget(name_label, 0, 0) grid.addWidget(self.pvname, 0, 1) grid.addWidget(value_label, 1, 0) grid.addWidget(self.value, 1, 1)
self.setLayout(grid) self.setWindowTitle("PySide PV Probe:")
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
A signal is emitted when a particular event occurs. A slot can be any Python callable. A slot is called when a signal connected to it is emitted.
13
pyside_probe.py : PvProbe class action handlers
def onPVNameReturn(self): if self.pv is not None: self.pv.remove_callback() self.pv.disconnect() self.pv = epics.PV(self.pvname.text(), callback=self.onPVChange)
def onPVChange(self, pvname=None, char_value=None, **kws): self.value.setText(char_value)
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
14
pyside_probe.py : run it
jemian@como-ubuntu64:~/...se/qtprobe-demo$ ./pyside_probe.py &[1] 10323
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
15
PyEpics: camonitor() callback handlerhttp://cars9.uchicago.edu/software/python/pyepics3/pv.html#user-supplied-callback-functions
def ca_callback(self, **kw): ''' process an EPICS CA monitor callback event, event information will be in kw dictionary ''' logger = logging.getLogger(__name__) logger.debug(
"callback: %s = %s" % (kw['pvname'], kw['char_value']))
Callback functions will be called with several keyword arguments. Prepare to handle them as a dictionary: **kw See the online docs for other variations and the complete list of keywords
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
16
Traits basicshttp://code.enthought.com/projects/traits
“Python does not require the data type of variables to be declared. As any experienced Python programmer knows, this flexibility has both good and bad points. The Traits package was developed to address some of the problems caused by not having declared variable types, in those cases where problems might arise.”
Huh?– Provides strongly-typed objects for Python
The TraitsUI package is a set of user interface tools designed to complement Traits Used in ETC plotting package: Chaco
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
17
Traits example: simpleton.py
from enthought.traits.api import HasTraits, String, Int, Float
class Simpleton(HasTraits): desc = String quantity = Int alpha = Float beta = Float gamma = Float
if __name__ == '__main__': example = Simpleton() result = example.configure_traits()
print result print example.desc, example.quantity print example.alpha, example.beta, example.gamma
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo 18
Starting Traits with Qt4 backend
Traits supports either wxPython (default) or Qt4 backends Here’s how to enforce use of the Qt4 backend
– MUST put this code before any other Traits imports!
from traits.etsconfig.api import ETSConfigETSConfig.toolkit = 'qt4'
19
traits_probe.py : main
import argparse
if __name__ == '__main__': #pv = '' #if len(sys.argv) == 2: # pv = sys.argv[1] parser = argparse.ArgumentParser( description="traits_probe") parser.add_argument( 'pv', action='store', nargs='?', help="EPICS PV name", default="EpicsDemo1“) results = parser.parse_args()
probe = Probe(name=results.pv) probe.configure_traits()
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
20
traits_probe.py : Probe class
class Probe( HasTraits ): name = Str value = Str _chid = Instance( epics.PV, value = None )
def do_callback(self, value=None, **kwds): "simple monitor callback" self.value = str(value)
traits_view = View( Item('name'), Readonly('value'), resizable=True,
width = 250, title='Traits-based EPICS Probe', key_bindings = key_bindings, handler = CodeHandler() )
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
21
traits_probe.py : CodeHandler class
# TraitsUI Handler class for bound methodsclass CodeHandler ( Handler ): def connect ( self, info ): if len(info.object.name) > 0: try: if info.object._chid is not None: info.object._chid.cancel_callback() info.object._chid.disconnect() except: pass info.object._chid = epics.PV( str(info.object.name), callback=info.object.do_callback )
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
22
traits_probe.py : preamble
import argparseimport epicsimport sys #@UnusedImportfrom traits.etsconfig.api import ETSConfigETSConfig.toolkit = 'qt4'from traits.api import * #@UnusedWildImportfrom traitsui.api import * #@UnusedWildImport
from traitsui.key_bindings import KeyBinding, KeyBindings
key_bindings = KeyBindings( KeyBinding( binding1 = 'Enter', method_name = 'connect‘, description = 'Connect to new PV',), KeyBinding( binding1 = 'Return', method_name = 'connect‘, description = 'Connect to new PV', ),)
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
23
traits_probe.py : example
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
24
traits_probe_more.py : structure
Four classes: ActionHandler, SimpleEpicsTraitsTest, ShowInfo, ShowAbout
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
25
traits_probe_more.py : implementing “info” my_button_actions = [. . ., Action(name="Info", action="show_info", desc="show PV info"), . . . ]
class ActionHandler(Handler): . . . def show_info(self, uinfo): '''information about the EPICS PV''' self.define_gui(uinfo) if self._watching and self._ch is not None: self._gui.SetStatus('showing PV info') ShowInfo(text=self._ch.info).edit_traits() else: self._gui.SetStatus('must Watch a PV first')
class ShowInfo( HasTraits ): '''dead simple PV Info box''' text = Str view = View( UReadonly('text'), title='PV info ...' )
view = View(. . ., handler = ActionHandler(), buttons = my_button_actions, . . .,)
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
26
traits_probe_more.py : run it
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo 27
Take-home Remarks: Traits
– Works really well for simple things, good choice for simple GUIs– Easy to add new GUI elements– Program execution flow is not obvious– Some unresolved threading challenges encountered on Win7 and RHEL– Supports both wxPython and Qt4 backends
PySide– Regular Qt4 implementation– Easier to debug– Best choice for GUI with any complexity– LGPL license allows greater use (than PyQt4)
Eclipse + PyDev is a great combination for a developer Use of EPD allows to define minimum configuration for users
28
Thank you for your attention!
EPICS 2012 @ SLAC: Jemian: Creating quick/simple QT-based GUIs in Python -- http://subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo