Qt GUI Toolkit

This GUI toolkit makes porting graphics to multiple platforms a snap.
The Qt Paint Engine.

Qt contains a device independent drawing engine, implemented in the class QPainter. QPainter is highly optimized and contains several caching mechanisms to speed up drawing. Under X11, it caches GCs (graphics contexts), which often make it faster than native X11 programs. QPainter contains all the functionality one would expect from a professional 2D graphics library.

The coordinate system of a QPainter can be transformed using the standard 2D transformations (translate, scale, rotate and shear). These transformations can be done directly or via a transformation matrix (QWMatrix), exactly as in postscript. Here is a small example taken from www.troll.no/qt showing the use of coordinate transformations:

void LJWidget::drawLJWheel( int x, int y, QPainter *p )
// set center point to 0,0
        p->translate( x, y );

// 24 point bold Times
        p->setFont(QFont("Times", 24, QFont::Bold));

// save graphics state

// full circle
        for( int i = 0 ; i < 360/15 ; i++ ) {

// rotate 15 degrees more
        p->rotate( 15 );

// draw rotated text
        p->drawText( 0, 0, "Linux" );
    p->restore();       // restore graphics state
    p->setPen( green ); // green 1 pixel width pen
// draw unrotated text
    p->drawText( 0, 0, "Linux Journal" );

This member function draws a text “wheel” with the center given at a specified point. First the coordinate system is transformed so that the given point becomes the point (0,0) in the new coordinate system. Next a font is set, and the graphics state is saved. Then the coordinate system is rotated 15 degrees at a time, clockwise, and the text “Linux” is drawn to form a textual “wheel”. The graphics state is then restored , the pen set to a green pen and the text “Linux Journal” is displayed. Note that it is not strictly necessary to save the graphics state since we do a full 360 degree rotation. Saving the graphics state is strictly defensive programming—if we were to change the for loop, which is doing the rotation, we could still guarantee that the last text would be output horizontally.

Qt has a font-abstraction implemented in the QFont class. A font can be specified in terms of the font family, point size and several font attributes. If the specified font is not available, Qt uses the closest matching font.

The drawLJWheel function can be used to generate output on any device since it merely uses a pointer to a QPainter. It does not know what kind of device the painter is operating on. The function is put into a widget in code, see http://www.troll.no/qt. Running it produces the result shown in Figure 1.

Figure 1. LJ Widget Output

Support Classes

Qt also contains a set of general purpose classes and a number of collection-classes to ease the development of multi-platform applications. The hardest part of generating portable code has always been operating system dependent functions. Qt has platform independent support for these functions, such as time/date, files/directories and TCP/IP sockets. Sometimes it might be necessary to use the underlying window system resources directly, e.g., when interfacing with other libraries. Qt gives direct access to all low-level window IDs and other resource IDs. Troll Tech has used this access to write a small widget that makes it possible to use OpenGL/mesa within a Qt widget.

Qt Event Handling

The structure of any GUI program is based on events. This basis is the main difference between GUI programming and non-GUI programming. A GUI program does not have “control” over the application; it merely waits for an event, does something as a response, and then waits for the next one.

A program typically sets up a top level widget to call the main event loop, which then dispatches events as they are received from the user or other parts of the system.

This model can be elegantly applied in an object-oriented language by using subclasses and reimplementation of virtual functions in the classical C++ event mechanism that is also used by Qt. The QWidget class contains one virtual function for each event type. A new type of widget is made by subclassing QWidget (or one of its descendants). You can simply reimplement an event function for each type of event you wish to receive. The event functions together with the Qt paint engine make up a powerful toolbox for creating custom widgets.

By far the most important event a widget receives is the paint event. It is called by the main event loop whenever the widget needs to draw a part of itself. Below is an example of a simple paint event, taken from code, http://www.troll.no/qt:

void CustomWidget::paintEvent( QPaintEvent *e )
// necessary to draw?
    if ( rect.intersects( e->rect() )) {
        QPainter p;
        p.begin( this );         // paint this widget
        p.setBrush( color );     // fill color
        p.drawRect( rect );      // draw rectangle

CustomWidget contains the member variable rect with type QRect, containing a rectangle with a one pixel black outline and filled with a color. Another member variable is color with type QColor, containing the color used to fill the rectangle.

First we check if the rectangle intersects the part of the widget that is to be updated. If it does, we instantiate a QPainter, open it on the widget, set its brush to the correct color and draw the rectangle (the default pen is one line thick and black).

All event functions take a pointer to an event object as their single argument. QPaintEvent contains the rectangular area of the widget that must be redrawn.

In the same widget we also receive resize events like this:

void CustomWidget::resizeEvent( QResizeEvent * )
// widget size - 20 pixel border
    rect = QRect( 20, 20, width() - 40,
        height() - 40 );

This event function sets the rectangle to be the size of the widget minus a 20 pixel border on all sides. It is never necessary to repaint a widget in a resize event since Qt always sends a paint event after the resize event when a widget has been resized.

CustomWidget also receives mouse press, move and release events like this:

void CustomWidget::mousePressEvent( QMouseEvent *e )
// left button click
    if ( e->button() == LeftButton &&
// on rectangle?
         rect.contains( e->pos() ) ) {
// set rectangle color to red
         color   = red;
// remember that it was clicked
         clicked = TRUE;
// repaint without erase
         repaint( FALSE );
void CustomWidget::mouseMoveEvent(QMouseEvent *)
// clicked and first time?
    if ( clicked && color != yellow ) {
        color = yellow;    // set color to yellow
        repaint( FALSE );  // repaint without erase
void CustomWidget::mouseReleaseEvent(QMouseEvent *e)
    if ( clicked ) {       // need to reset color
        color   = green;   // set color to green
        repaint( FALSE );  // repaint without erase
        clicked = FALSE;

The mouse press event sets the rectangle color to red if the left mouse button is clicked inside the rectangle. When the mouse is moved after a click on the rectangle the color will change to yellow. Finally the color is reset to green when the mouse button is released.

The calls to repaint cause the entire widget to be redrawn. The FALSE argument instructs Qt not to erase the widget (fill it with the background color) before sending the paint event. We can use FALSE, because we know that paintEvent will draw a new rectangle covering the old one. Painting in this manner reduces flickering considerably; otherwise, double-buffering should be used.

The full widget code can be found in www.troll.no/qt . Running it produces the result shown in Figure 2. Custom Widget Output



Comment viewing options


GUI deveopment using QT

Anonymous's picture



sowmya's picture
