Creating quick/simple QT-based GUIs in Python

28
Creating quick/simple QT-based GUIs in Python Pete R. Jemian Advanced Photon Source, Argonne National Laboratory 2012 EPICS Collaboration Meeting SLAC, 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.htm l

description

Creating quick/simple QT-based GUIs in Python. Pete R. Jemian Advanced Photon Source, Argonne National Laboratory 2012 EPICS Collaboration Meeting SLAC, Menlo Park, CA 2012-04-24. svn co https:// subversion.xor.aps.anl.gov/bcdaext/qtprobe-demo / qtprobe-demo - PowerPoint PPT Presentation

Transcript of Creating quick/simple QT-based GUIs in Python

Page 1: 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

Page 2: Creating  quick/simple  QT-based  GUIs in Python

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

Page 3: Creating  quick/simple  QT-based  GUIs in Python

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

Page 4: Creating  quick/simple  QT-based  GUIs in Python

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

Page 5: Creating  quick/simple  QT-based  GUIs in Python

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

Page 6: Creating  quick/simple  QT-based  GUIs in Python

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

Page 7: Creating  quick/simple  QT-based  GUIs in Python

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

Page 8: Creating  quick/simple  QT-based  GUIs in Python

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

Page 9: Creating  quick/simple  QT-based  GUIs in Python

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

Page 10: Creating  quick/simple  QT-based  GUIs in Python

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

Page 11: Creating  quick/simple  QT-based  GUIs in Python

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

Page 12: Creating  quick/simple  QT-based  GUIs in Python

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.

Page 13: Creating  quick/simple  QT-based  GUIs in Python

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

Page 14: Creating  quick/simple  QT-based  GUIs in Python

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

Page 15: Creating  quick/simple  QT-based  GUIs in Python

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

Page 16: Creating  quick/simple  QT-based  GUIs in Python

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

Page 17: Creating  quick/simple  QT-based  GUIs in Python

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

Page 18: Creating  quick/simple  QT-based  GUIs in Python

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'

Page 19: Creating  quick/simple  QT-based  GUIs in Python

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

Page 20: Creating  quick/simple  QT-based  GUIs in Python

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

Page 21: Creating  quick/simple  QT-based  GUIs in Python

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

Page 22: Creating  quick/simple  QT-based  GUIs in Python

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

Page 23: Creating  quick/simple  QT-based  GUIs in Python

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

Page 24: Creating  quick/simple  QT-based  GUIs in Python

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

Page 25: Creating  quick/simple  QT-based  GUIs in Python

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

Page 26: Creating  quick/simple  QT-based  GUIs in Python

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

Page 27: Creating  quick/simple  QT-based  GUIs in Python

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

Page 28: Creating  quick/simple  QT-based  GUIs in Python

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