Personal tools
You are here: Home HowTos How To use PyQt and TAU

How To use PyQt and TAU

A collection of recipes to make first steps easier ...

How to create a TAU and PyQt GUI or Widgets

Resources

[Controls website, gui framworks] [Qt4 Documentation] [Qt4 Classes reference]

Create a GUI

Copied from http://www.cells.es/Members/srubio/howto/pyqt

  1. open qt designer
  2. create your widget
  3. save the ui_XXX.ui file
  4. > pyuic4 ui_XXX.ui > ui_XXX.py
  5. edit your XXX.py file
  6. Create a new class inheriting from the object that you want to create (QMainWindow or QDialog)
  7. in the __init__ method create an ui_XXX object and call to setupUi and retranslateUi methods
  8. This self.ui object will contain all the widgets and other objects that you added on QtDesigner.
  9. Add to your class the methods (Slots) that you want to execute for each Widget event (Signal)
  10. Connect Signals and Slots
  11. Browse to http://www.riverbankcomputing.com/static/Docs/PyQt4/html/classes.html to see what each PyQt class offers to you.
# This is the contents of the MyGui.py file
# It assumes that you have created ui_MyGui.ui with QtDesigner
# You have to execute >/pyuic4 ui_MyGui.ui > ui_MyGui.py to generate the file to import

from PyQt4 import QtGui,QtCore
from ui_MyGui import ui_MyGui

class MyGUI(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = ui_MyGui()
self.ui.setupUi(self)
self.connect(self.ui.push_button,QtCore.SIGNAL('clicked(bool)'),self.DoAction)

def DoAction(self,arg = None):
print 'What a %s action.' % ('wonderful' if arg else 'sad')

app = QtGui.QApplication(sys.argv[0:1])
gui = MyGui()
gui.show()
sys.exit(app.exec_())


Using TAU Models

Using a Database Model

This explanation is referred to this DbWidget Template.

Methods that has been modified from the raw template are:

  • init: to initialize the model by default (it should be done using Qt Properties!) added: self.setModel('controls01:10000')
  • getModelClass : to return the right Model class added: return tau.core.TauDatabase?
  • updateStyle : to set the values to be displayed added:

obj = self.getModelObj(); if obj: self.setText(obj.get_info()) # or any other PyTango?.Database method call

NOTE: It has been done here because Database object does not have events to subscribe;

for event-driven objects other methods must be modified.

To create a DeviceTable? widget with a TauDatabase? model:

  • Inherit from QTableWidget

 * A method refresh(self) must be added to be able to update the widget using an external button


Some Recipes

Standard Dialogs and Widgets

QMessageBox(parent,Title,Question,FlagsForButtons?)

v = QtGui.QMessageBox.warning(None,'SplitterTester', \
'You must introduce or select an IP from IPAddress Combo Box'
,QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel);
if v == QtGui.QMessageBox.Cancel:
return

QInputDialog(parent,title,question,QLineEdit,defaultText)
returns (text,OkPressed?)

In [29]:QtGui.QInputDialog.getText(None,'hola','dame argo',QtGui.QLineEdit.Normal,'una moneiya')
Out[29]:(<PyQt4.QtCore.QString object at 0x83ad2ac>, True)

QFont: Setting a monospaced font in a QTextEdit panel

font = QtGui.QFont()
font.setStyleHint(QtGui.QFont.TypeWriter)
font.setFamily("unexistentfont")
self.ui.TextPanel.setFont(font)

Focus: .setFocus(), hasFocus() available on most of widgets

QDialog vs QMainWindow (KeyEvents)

  • QDialog automatically connects Return and Escape keys to Ok and Cancel buttons.


  • In QMainWindow it must be hacked using keyPressEvent methods

Managing Key Events

    def keyPressEvent(self,event):
if event.key() == QtCore.Qt.Key_Escape:
self.reject()
elif event.key() in [QtCore.Qt.Key_Return,QtCore.Qt.Key_Enter]:
buttons = [b for b in \
[self.ui.ScanButton,self.ui.buttonBox.buttons()[1],self.ui.AddressEdit,self.ui.RangeEdit] \
if b.hasFocus()]
if buttons:
for b in buttons:
if hasattr(b,'click'): b.click()
else:
self.accept()
return

Signals and Slots

Connecting signals and slots

Connections between signals and slots (and other signals) are made using the QtCore?.QObject.connect() method. For example:

QtCore.QObject.connect(a, QtCore.SIGNAL("QtSig()"), b, QtCore.SLOT("QtSlot()"))
QtCore.QObject.connect(a, QtCore.SIGNAL("PySig()"), b, QtCore.SLOT("QtSlot()"))
QtCore.QObject.connect(a, QtCore.SIGNAL("QtSig()"), pyFunction) #A python function with NO arguments
QtCore.QObject.connect(a, QtCore.SIGNAL("QtSig()"), pyClass.pyMethod) #A python function with NO arguments
QtCore.QObject.connect(a, QtCore.SIGNAL("PySig"), pyFunction) #A python signal WITH arguments

Emitting signals

Any instance of a class that is derived from the QtCore?.QObject class can emit a signal using its emit() method. This takes a minimum of one argument which is the signal. Any other arguments are passed to the connected slots as the signal arguments. For example:

a.emit(QtCore.SIGNAL("clicked()")) #A python function with NO arguments
a.emit(QtCore.SIGNAL("pySig"), "Hello", "World") #A python function WITH arguments

QThreads

QThreads object cannot access directly to GUI objects ... All access must be done using Signals and Slots; so any change to GUI (including displaying messages) must be done through emit and declared functions with arguments.

class QPinger(QtCore.QThread):
def __init__(self,parent,ipstart,iprange):
QtCore.QThread.__init__(self)
...
if hasattr(parent,'scan_finished'):
QtCore.QObject.connect(self, QtCore.SIGNAL("scan_finished"), parent.scan_finished)

def run(self):
...
self.emit(QtCore.SIGNAL("scan_finished"), founds)

Random remarks

Note: it works with milliseconds instead of seconds'':

  • QThread.start() to launch QThread.run() method
  • QThread.wait() equals to threading.Thread.join()
  • QThread.wait(millis): equals to threading.Event.wait(seconds)
  • QMutex.lock() ; QMutex.unlock ... typical mutex
  • QWaitCondition: Like threading.Event but a mutex is unlocked during wait and locked again when the wait finishes.
    • QWaitCondition.wait(QMutex): Forces the Thread to wait until QWaitCondition.wakeOne() or .wakeAll() is called in another thread.
    • QWaitCondition.wait(QMutex, time=int(millis)): This works like threading.Event.wait(seconds).
  • Signals: QThread.started,.finished,.terminated (launched by terminate(); it is thread unsafe!)

How to create a TAU Widget

from Thiago's internal presentation http://www.cells.es/CELLS/Intranet/Divisions/Computing/Controls/Applications/tau/Tau_Internal_Presentation

Writing your own widgets

  • goto widget/utils
  • type:
    python widgetgen.py <classname> <superclass> <outputfile> [<qtfile>]

But it fails a lot!!!

Things to do to setup the module (DBaseWidget example)

  • init: to initialize the model by default (it should be done using Qt Properties!)
    self.setModel('controls01:10000')
  • getModelClass : to return the right Model class
    return tau.core.TauDatabase
  • updateStyle : to set the values to be displayed
    obj = self.getModelObj();
    if obj: self.setText(obj.get_info()) # or any other PyTango.Database method call

Notes:

  • widget module is for generic tango widgets only
  • there will be modules for gl, qwt, etc
  • if you implement a widget that has reference to any system or interprets tango data in a very particular way it is not a widget. Just part of your application

More things …

from unfinished Thiago's tutorial

  • Must inherit from TauBaseWidget?
  • Must inherit from QWidget or any of its subclasses
  • Must provide the following constructor:
    def __init__(self, parent = None, designMode = False)
  • must call the TauBaseWidgetConstructor?:
    self.call__init__(TauBaseWidget, name, designMode=designMode)
  • Must define two properties:
    • model
    • parentModel
  • Should implement getModelClass
  • Should implement updateStyle
Document Actions