The K Desktop Environment

Next Previous Table of Contents

2. The KDE and Qt Libraries

The Norwegian company Troll Tech ( http://www.troll.no) provides a so-called GUI toolkit, named Qt. Thereby, GUI means "Graphical User Interface", and therefore, Qt-based applications represent themselves with buttons, windows etc, allowing user input by visualizing the functions an application provides. Such a toolkit is needed for developing graphical applications that run on the X-Window interface on Unix Systems, because X does not contain a pre-defined user interface itself. Although other toolkits are also available to create User Interfaces, Qt offers some technical advantages that make application design very easy. Additionally, the Qt toolkit is also available for Microsoft Windows systems, which allows developers to provide their applications for both platforms.

The KDE Team ( http://www.kde.org) joined together with the goal to make using Unix Systems more friendly, and decided to use the Qt toolkit for the development of a window manager on X-Window, plus a variety of tools included with the KDE packages. The K Desktop Environment therefore contains the window manager kwm, the file manager kfm and the launch panel kpanel as the main components plus a variety of first-class utilities and applications. After KDE was out, a lot of developers turned their eyes towards the new environment and what it has to offer them. The KDE libraries are providing essential methods and classes that make all applications designed with them look similar and consistent, so the user has the great advantage that he only has to get accustomed with an application's specific usage, not with handling dialogs or buttons. Also, KDE programs integrate themselves into the desktop and are able to interact with the file manager via drag'n drop, offer session management and many more, if all features offered by the KDE libraries are used.

Both, the Qt toolkit and the KDE libraries, are implemented in the C++ programming language; therefore applications that make use of these libraries are also mostly written in C++. In the following chapter, we'll make a short trip through the libraries to see what already is provided and how Qt and KDE applications are created in general.

2.1 The Qt GUI Toolkit

As said, the Qt library is a toolkit that offers graphical elements that are used for creating GUI applications and are needed for X-Window programming. Additionally, the toolkit offers:

Therefore knowing the Qt classes is very essential, even if you only want to program KDE-applications. To have an impression on the basic concept how GUI-applications are constructed and compiled, we'll first have a look at a sample Qt-only program; then we'll extend it to a KDE program.

The first Qt Application

As usual, programs in C++ have to contain a main() function, which is the starting point for application execution. As we want them to be graphically visible in windows and offering user interaction, we first have to know, how they can show themselves to the user. For an example, we'll have a look at the first tutorial included with the Qt Online Reference Documentation and explain the basic execution steps; also why and how the application window appears:


#include <qapplication.h>
#include <qpushbutton.h>

int main( int argc, char **argv )
{
QApplication a( argc, argv );

QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );

a.setMainWidget( &hello );
hello.show();
return a.exec();
}

This application merely paints a window containing a button with "Hello world" as its text. As for all Qt-based applications, you first have to create an instance of the class QApplication, represented by a.

Next, the program creates an instance of the class QPushButton called hello, this will be the button. The constructor of hello gets a string as a parameter, which is the contents of the widget visible as the buttons text.

Then the resize() method is called on the hello button. This changes the default size a widget (which is in this case the QPushButton) has when created to the length of 100 pixels and the height of 30 pixels. Finally, the setMainWidget() method is called for a and the show() method for hello. The QApplication is finally executed by a.exec(), enters the main event loop and waits until it has to return an integer value to the overlaying Operating System signaling that the application is exited.

The Reference Documentation for Qt

Now, let's have a quick look at the reference documentation of the Qt library. To do this, start KDevelop and select "Qt-library" from the "Help"-menu in the menubar. The documentation browser opens and shows you the start page of the Qt reference. This will be your first place to get information about Qt, it's classes and the available functions they provide. Also, the above program is the first that is included in the tutorials section. To get to the classes we want to have a look at, QApplication and QPushButton, select "Alphabetical Class List" and search for the according names. Follow either of them to have a look at the class documentation.

For QApplication, you will see the constructor and all other methods that this class provides. If you follow a link, you will get more information about the usage and meaning of the methods, which is very useful when you sometimes can't detect the correct use or want to have an example. This also counts for the KDE library documentation, which uses a similar documentation type; therefore this is almost all you have to know about using the class-references with the documentation browser.

Interpretation of the Sample

Starting with QApplication, you will find all the methods used in our first example:

The interpretation why we use these methods is very simple:

  1. first create an instance of the class QApplication with the constructor, so we can make use of the GUI elements provided by Qt,
  2. create a widget which will be the contents of our program window,
  3. set the widget as the main widget for a,
  4. execute the a instance of QApplication.

The second object of our program is the pushbutton, an instance of the class QPushButton. From the two constructors given to create an instance, we used the second: this accepts a text, which is the label contents of the button; here, it is the string "Hello world!". Then we called the resize() method to change the size of the button according to it's contents- the button has to be larger to make the string completely visible.

But what about the show() method ? Now, you see that like most other widgets, QPushButton is based on a single-inheritance- here, the documentation says, Inherits QButton. Follow the link to the QButton class. This shows you a lot of other methodss that are inherited by QPushButton, which we'll use later to explain the signal/slot mechanism. Anyway, the show() method is not listed, therefore, it must be a method that is provided by inheritance as well. The class that QButton inherits, is QWidget. Just follow the link again, and you will see a whole bunch of methods that the QWidget class provides; including the show() method. Now we understand what was done in the sample with the button:

  1. create an instance of QPushButton, use the second constructor to set the buttons text,
  2. resize the widget to it's contents,
  3. set the widget as the main widget of the QApplication instance a,
  4. tell the widget to display itself on the screen by calling show(), an inherited method from QWidget.

After calling the exec() method, the application is visible to the user, showing a window with the button showing "Hello world!". Now, GUI programs behave somewhat differently than procedural applications. The main thing here is that the application enters a so-called "main event loop". This means that the program has to wait for user actions and then react to it, also that for a Qt application, the program has to be in the main event loop to start the event handling. The next section tells you in short what this means to the programmer and what Qt offers to process user events.

(For already advanced users: The button has no parent declared in the constructor, therefore it is a top-level widget alone and runs in a local event loop which doesn't need to wait for the main event loop, see the QWidget class documentation and The KDE Library Reference Guide)

Summary:

A Qt application always has to have one instance of the class QApplication. This provides that we can create windows that are the graphical representation of programs to the user and allow interaction. The window contents itself is called a "Main Widget", meaning that all graphical elements are based on the class QWidget and can be any type of widget that fits the needs of the application to communicate with the user. Therefore, all user elements somehow have to inherit QWidget to be visible.

User Interaction

After reading the last sections, you should already know:

Now we'll turn to give the application "life" by processing user events. Generally, the user has two ways to interact with a program: the mouse and the keyboard. For both ways, a graphical user interface has to provide methods that detect actions and methods that do something as a reaction to these actions.

The Window system therefore sends all interaction events to the according application. The QApplication then sends them to the active window as a QEvent and the widgets themselves have to decide what to do with them. A widget receives the event and processes QWidget::event(QEvent*)/, which then decides which event has been executed and how to react; event() is therefore the main event handler. Then, the event() function passes the event to so-called event filters, that determine what happened and what to do with the event. If no filter signs responsible for the event, the specialized event handlers are called. Thereby we can decide between:

a) Keyboard events --TAB and Shift-TAB keys:

changes the keyboard input focus from the current widget to the next widget in the focus order. The focus can be set to widgets by calling setFocusPolicy () and process the following event handlers:

b) all other keyboard input:

c) mouse movements:

d) mouse button actions:

e) window events containing the widget:

Note that all event functions are virtual and protected; therefore you can re-implement the events that you need in your own widgets and specify how your widget has to react. QWidget also contains some other virtual methods that can be useful in your programs; anyway, it is sufficient to know about QWidget very well generally.

Object Interaction by Signals and Slots

Now we're coming to the most obvious advantages of the Qt toolkit: the signal/slot mechanism. This offers a very handy and useful solution to object interaction, which usually is solved by callback functions for X-Window toolkits. As this communication requires a strict programming and sometimes makes user interface creation very difficult (as referred by the Qt documentation and explained in Programming with Qt by K.Dalheimer), Troll Tech invented a new system where objects can emit signals that can be connected to methods declared as slots. For the C++ part of the programmer, he only has to know some things about this mechanism:

  1. the class declaration of a class using signals/slots has to contain the Q_OBJECT macro at the beginning (without the semicolon); and have to be derived from the QObject class,
  2. a signal can be emitted by the keyword emit, e.g. emit signal(parameters); from within any member function of a class that allows signals/slots,
  3. all signals used by the classes that are not inherited have to be added to the class declaration by a signals: section,
  4. all methods that can be connected with a signal are declared in sections with the additional keyword slot, e.g. public slots: within the class declaration,
  5. the meta-object compiler moc has to run over the header file to expand the macros and to produce the implementation (which is not needed to know.). The output files of moc are compiled as well by the C++ compiler.

Another way to use signals without deriving from QObject is to use the QSignal class- see the reference documentation for more information and example usage. In the following, we assume you're deriving from QObject.

This way, your class is able to send signals anywhere and to provide slots that signals can connect to. By using the signals, you don't have to care about who's receiving it- you just have to emit the signal and whatever slot you want to connect to it can react to the emission. Also the slots can be used as normal methods during implementation.

Now, to connect a signal to a slot, you have to use the connect() methods that are provided by QObject or, where available, special methods that objects provide to set the connection for a certain signal.

Sample Usage

To explain the way how to set up object-interaction, we'll take our first example again and extend it by a simple connection:


#include <qapplication.h>
#include <qpushbutton.h>

int main( int argc, char **argv )
{
QApplication a( argc, argv );

QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );

a.setMainWidget( &hello );

connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));

hello.show();
return a.exec();
}

You see, the only addition to give the button more interaction is to use a connect() method: connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() )); is all you have to add. What is the meaning now ? The class declaration of QObject says about the connect() method:

bool connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * member )

This means, you have to specify a QObject instance pointer that is the sender of the signal, meaning that it can emit this signal as first parameter; then you have to specify the signal that you want to connect to. The last two parameters are the receiver object that provides a slot, followed by the member function which actually is the slot that will be executed on signal emission.

By using signals and slots, your program's objects can interact with each other easily without explicitely depending on the type of the receiver object. You will learn more about using this mechanism for productive usage later in this handbook. More information about the Signals/Slot mechanism can also be found in The KDE Library Reference Guide and the Qt online reference.

2.2 What KDE provides

The KDE 1.1.x libraries

For the time of this writing and due to the fact that KDevelop uses KDE 1.1, I'm referring to the state of the KDE libraries at that release. The main KDE libraries you'll be using for creating your own KDE applications are:

Additionally, for specific solutions KDE offers the following libraries:

Next, we'll have a look at what is needed to turn our first Qt application into a KDE one.

Example KDE Application

In the following, you will see that writing a KDE application is not much more difficult than a Qt application. For the use of KDE's features, you just have to use some other classes, and you're almost done. As an example, we'll discuss the changed version of the Qt example from above:


#include <kapp.h>
#include <qpushbutton.h>

int main( int argc, char **argv )
{
KApplication a( argc, argv );

QPushButton hello( "Hello world!" );
hello.resize( 100, 30 );

a.setTopWidget( &hello );

connect(&hello, SIGNAL( clicked() ), &a, SLOT( quit() ));

hello.show();
return a.exec();
}

You see that first we have changed from QApplication to KApplication. Further, we had to change the previously used setMainWidget() method to setTopWidget, which KApplication uses to set the main widget. That's it ! Your first KDE application is ready- you only have to tell the compiler the KDE include path and the linker to link in the KDE-Core library with -lkdecore.

As you now know what at least the main() function provides generally and how an application gets visible and allows user and object interaction, we'll go on with the next chapter, where our first application is made with KDevelop- there you can also test everything which was mentioned before and see the effects.

What you should have looked into additionally until now is the reference documentation for Qt, especially the QApplication, QWidget and QObject class and the KDE-Core library documentation for the KApplication class. The KDE Library Reference handbook also covers a complete description about the invocation of the QApplication and KApplication constructors including command-line argument processing.

Next Previous Table of Contents