Languages/Python/Using PyKDE 4

From KDE TechBase

PyKDE4 includes many example programs and several tutorials to help you begin writing KDE4 applications using Python. The documentation has also been enhanced. The easiest way to begin with PyKDE4 is to copy some of the examples or tutorial code to your home directory, and then examine and experiment with the code provided.

PyKDE4 development is also made considerably easier by the use of an integrated environment, like eric4, or at least through the use of a debugger which can single step and allow you to examine values as your program executes.

Tutorial here.

Importing Modules

All PyKDE4 modules are included in a single Python package named (oddly) "PyKDE4". That means that to import a PyKDE4 module, you must also include the package name as a prefix:

from PyKDE4.kdeui import KApplication
...
app = KApplication ()

or

import PyKDE4.kdeui
...
app = PyKDE4.kdeui.KApplication

There are other forms of the import statement that will also work. All of the PyKDE4 examples and tutorials use the first form shown above. We recommend you do not use:

from PyKDE4.kdeui import *

although we expect many users will. It will work in most, but probably not all cases, as there may be name clashes between objects in the different PyKDE4 modules.

KApplication Required

Nearly every KDE4 (and consequently PyKDE4) application requires a KApplication object be constructed before using most other PyKDE4 (KDE4) objects in your program. KApplication also runs the event loop that allows PyKDE4 objects to communicate with each other.Nearly every example provided with PyKDE4 includes the basic code necessary to create an application using KApplication.

QApplication is not a substitute for KApplication in programs that use KDE4 objects.

A KUniqueApplication object is a subclass of KApplication and will also work. You may also subclass your own classes from KApplication.

See the next section for code that creates a KApplication instance.

KCmdLineArgs, KAboutData

The notable exceptions to the above rule about constructing a KApplication object before using any other PyKDE4 object are the KCmdLineArgs and KAboutData classes.

import sys
from PyKDE4.kdecore import ki18n, KAboutData, KCmdLineArgs
from PyKDE4.kdeui import KApplication

...


appName     = "KApplication"
catalog     = ""
programName = ki18n ("KApplication")
version     = "1.0"
description = ki18n ("KApplication/KMainWindow/KAboutData example")
license     = KAboutData.License_GPL
copyright   = ki18n ("(c) 2007 Jim Bublitz")
text        = ki18n ("none")
homePage    = "www.riverbankcomputing.com"
bugEmail    = "[email protected]"

aboutData   = KAboutData (appName, catalog, programName, version, description,
                        license, copyright, text, homePage, bugEmail)


KCmdLineArgs.init (sys.argv, aboutData)

app = KApplication ()

You can, of course, substitute you own values for the KAboutData arguments.

Even if you don't plan on passing command line arguments to your program, KApplication still requires KCmdLineArgs (or one of several equivalents) be used to pass the command line arguments to KApplication.

Also, KAboutData does more than set the data for your "about application" dialog on the help menu. The appName or programName values are used to define your application in other areas, especially by DBUS. DBUS apparently doesn't like dots (".") in the appName or programName values, so leave the ".py" extension off in those places, or replace the dots with an underscore ('_' - for example, application_py)

The use of ki18n as shown is virtually required. The KAboutData constructor requires KLocalizedString types in the four locations shown, and there is almost no way to create an object of KLocalizedString type except by using ki18n. i18n (without the leading 'k') will not work.

Many of the arguments to the KAboutData constructor are optional - see the KAboutData docs for the complete Python signature.

Signals and Slots

The PyQt4 docs have a more complete explanation of signals and slots. There are several points that deserve notice.

First, under PyQt4 and PyKDE4, a slot may be any Python callable - a function, or class method. The general form for connecting a signal to a slot is:

self.connect (self.button, SIGNAL ("clicked ()"), self.buttonClicked)
self.connect (self.tree, SIGNAL ('itemClicked (QTreeWidgetItem *, int)'),
    self.treeItemClicked)

def buttonClicked (self):
   ...

def treeItemClicked (self, item, n):
   ...

'self.button' and 'self.tree' are concrete instances of the objects that emit the signals. The example assumes that the "self" used with "connect" is a subclass of QObject - any subclass, or even QObject itself, since "connect" is a static method (there is basically a single 'connect' method shared by all QObject descendants).

Note also that the argument to SIGNAL is a string which represents the C++ signature of the signal, without variable names, but *with* argument types, including any 'const', '*', '&' or other decoration. The C++ signatures are reproduced in the PyKDE4 class documentation, so you can just cut and paste them into your code.

The slot named must have a signature which matches the number of arguments in the signal signature. The types of the arguments passed into the slot when the signal is emitted will match the types in the C++ signature (but in this case without the effect of any decorations).

It's important to write both the connect and slot methods carefully, as signal/slot errors will often fail silently - without any error or exception being produced, but also without your code working as expected. If signals appear to be not connecting to slots, check the syntax in the connect statement and slot argument list first.

Namespaces

For PyKDE4 objects which are enclosed in a (C++) namespace. importing the namespace also gets you all of the objects in the namespace. For example, the objects "StorageVolume", "DeviceInterface", "DeviceInterface.StorageVolume", and "Device", in the code snippet below all reside in the "Solid" namespace. All were imported via the single import statement shown.

The namespace name ("Solid" in this case) is a required prefix for all of the namespace's objects.

from PyKDE4.solid import Solid
...
# convert enum values to strings for display
    usageType2Str = { Solid.StorageVolume.Other : "Other",\
                      Solid.StorageVolume.Unused : "Unused",\
                      Solid.StorageVolume.FileSystem : "File System",
                      Solid.StorageVolume.PartitionTable : "Partition Tbl",\
                      Solid.StorageVolume.Raid : "Raid",\
                      Solid.StorageVolume.Encrypted : "Encrypted"
                    }
        
    # retrieve a list of Solid.Device for this machine
    deviceList = Solid.Device.allDevices ()
        
    # filter the list of all devices and display matching results
    # note that we never create a Solid.StorageVolume object,
    # but receive one from the 'asDeviceInterface" call
    for device in deviceList:
        if device.isDeviceInterface (Solid.DeviceInterface.StorageVolume):
        volume = device.asDeviceInterface (Solid.DeviceInterface.StorageVolume)
        QTreeWidgetItem (display, [device.product (),
                                   volume.fsType (),
                                   volume.label (),
                                   str (volume.isIgnored ()),
                                   "%i MB" % (volume.size ()/1024/1024),
                                   usageType2Str [volume.usage ()]])

Version Information

Information about the installed versions of KDE and PyKDE4 is programmatically available from global functions in the PyKDE4.kdecore module. For example:

        import PyKDE4.kdecore as kdecore
        print kdecore.version ()

The following table lists the available functions and the result they return (using KDE 4.0.2 or PyKDE 4.0.2 as an example)

Returns KDE PyKDE example
int version() pykde_version() 212646L (or 0x040002)
int versionMajor() pykde_versionMajor() 4
int versionMinor() pykde_versionMinor() 0
int versionRelease() pykde_versionRelease() 2
string versionString() pykde_versionString() "4.0.2" [note 1]

Note 1: The *versionString functions will return a string that begins with a string representation of the version number,but may also return additional information in the string, such as build or release number, packager, etc.

Abstract Classes

An abstract class is a base class that cannot be instantiated itself, but can be used as a base class for other classes. You can't create an instance of an abstract class.

Abstract classes are denoted in C++ by having one or more 'pure virtual' methods.

virtual int someMethod (int x, int y) = 0;

is the C++ representation of a pure virtual method (the "= 0" is the defining characteristic, along with the virtual modifier on the front end).

In order to derive a class from an abstract class, you have to 'overload' or define (with code) all of the pure virtual methods. So in the example above, your Python class derived from an abstract class would have to contain 'def somemethod (self, x, y)' along with code for the method to execute. The argument list must match the argument list in the pure virtual method (with the addition of 'self').

The PyKDE4 docs clearly label all abstract classes, and label their pure virtual methods as well.



This page is copyright 2007-2008 Jim Bublitz and licensed under Commons Attribution-Share Alike 3.0 Unported.