Next Previous Table of Contents
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.
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.
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.
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.
Starting with QApplication
, you will find all the methods used in our first example:
QApplication()
,setMainWidget()
method andexec()
method.The interpretation why we use these methods is very simple:
QApplication
with the constructor, so we can make use of the GUI elements provided by
Qt,a
,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:
QPushButton
, use the second constructor to set the buttons text,QApplication
instance a
,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.
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:
virtual void focusInEvent
( QFocusEvent * )
virtual void focusOutEvent
( QFocusEvent * )
b) all other keyboard input:
virtual void keyPressEvent
( QKeyEvent * )
virtual void keyReleaseEvent
( QKeyEvent * )
c) mouse movements:
virtual void mouseMoveEvent ( QMouseEvent * )
virtual void enterEvent ( QEvent * )
virtual void leaveEvent ( QEvent * )
d) mouse button actions:
virtual void mousePressEvent ( QMouseEvent * )
virtual void mouseReleaseEvent ( QMouseEvent * )
virtual void mouseDoubleClickEvent ( QMouseEvent * )
e) window events containing the widget:
virtual void moveEvent ( QMoveEvent * )
virtual void resizeEvent ( QResizeEvent * )
virtual void closeEvent ( QCloseEvent * )
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.
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:
Q_OBJECT
macro at the beginning (without the
semicolon); and have to be derived from the QObject
class,emit
, e.g. emit signal(parameters);
from within any member function
of a class that allows signals/slots,signals:
section,slot
, e.g.
public slots:
within the class declaration,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.
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.
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.
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