7.4  Writing Controls

7.4.1  Important Rules!

Before you start publishing controls, please thoroughly read these rules. They make your life and especially that of the users easier.

  1. Before writing a new control, please check if the functionality you need has already been implemented by somebody else. There's no point in having two or more controls with different interfaces doing the same!
  2. If there already is a control doing what you want, but you want to make a more efficient implementation, please implement the interfaces of the other control to ensure backwards compatibility.
  3. Do never put applet-specific functionality into a control. Controls are meant to be shared among applets!
  4. Never publish a control without obeying rules 1 - 3!

7.4.2  Anatomy of Controls

Controls are Python classes derived from the Control base class and from the interfaces which they implement. The base class can be loaded from libdesklets.controls:

from libdesklets.controls import Control
  

Each control has its own directory, which at least consists of the __init__.py file. That file initializes the control and provides a function get_class() returning the main class (not an instance of the class) of the control.

The typical directory structure of a control looks like:

MyControl/
  IMyInterface.py
  __init__.py
  

The control directory has to include all interface files from which the control inherits. By convention, the filenames of interface files start with an "I" to distinguish them from regular files. The file __init__.py is also mandatory. If neccessary, a control can also include other files as well, which are loaded by the initialization file. You should, however, keep in mind to design controls as generic as possible.

7.4.3  Deriving from Interfaces

Every control implements one or more interfaces. Since an interface is a simple Python class, you just have to derive your control from the interface classes:

from libdesklets.controls import Control
from IMyInterface import IMyInterface

class MyControl(Control, IMyInterface):

    def __init__(self):

        Control.__init__(self)
        ...

    ...


def get_class(): return MyControl
  

Because interfaces are implementation-less, there is no super-constructor to invoke for them.

Always remember to derive from the Control class and to invoke its constructor to get a valid control class.

7.4.4  Implementing Properties

Every property in the interfaces must be implemented by creating appropriate property objects.

Python's property constructor takes four arguments, of which are all optional. From the Python inline help:

property(fget=None, fset=None, fdel=None, doc=None) -> property attribute

fget is a function to be used for getting an attribute value, and likewise
fset is a function for setting, and fdel a function for del'ing, an
attribute.  Typical use is to define a managed attribute x:
class C(object):
    def getx(self): return self.__x
    def setx(self, value): self.__x = value
    def delx(self): del self.__x
    x = property(getx, setx, delx, "I'm the 'x' property.")
  

The fdel argument is not needed for controls. If a property is not readable, you also omit the fget argument or set it to None. Likewise, for not writable properties, you omit the fset argument. The read-write permissions must match those declared by the interfaces.

The doc argument can be used for describing the property in human-readable form. It is highly recommended to always give a useful description for every property.

7.4.5  Methods of the Control Class

The Control class provides you with all you need for writing compliant controls. The following methods can be used inside controls:

Method Name Arguments Description
__init__ The constructor of the Control. This always has to be called as the super-constructor within the constructor.
_add_timer

interval: integer

callback: function

*args

This is a convenience function for adding a timeout handler which gets called after interval milliseconds. If the callback function returns True, the callback will be called again after the next timeout. This method returns an ID which can be used with _remove_timer() to remove the timer again.
_remove_timer

ident: integer

Removes the timer with the given ID ident.
_shutdown This is a hook method which can be overridden in order to perform cleanup operations before the control is being closed.
_update

prop: string

Notifies observers of property prop that the value has changed. You have to call this method whenever a property which is watchable using bind() changes its value. Of course it does not make sense for all properties to be watchable. Always call this method after the change has actually taken place.