Development/Architecture/KDE3/Low-level Graphics

From KDE TechBase
Revision as of 11:57, 6 January 2007 by Dhaumann (talk | contribs) (next part)

Qt's low level imaging model is based on the capabilities provided by X11 and other windowing systems for which Qt ports exist. But it also extends these by implementing additional features such as arbitrary affine transformations for text and pixmaps.

Rendering with QPainter

The central graphics class for 2D painting with Qt is QPainter. It can draw on a QPaintDevice. There are three possible paint devices implemented: One is QWidget which represents a widget on the screen. The second is QPrinter which represents a printer and produces Postscript output. The third it the class QPicture which records paint commands and can save them on disk and play them back later. A possible storage format for paint commands is the W3C standard SVG.

So, it is possible to reuse the rendering code you use for displaying a widget for printing, with the same features supported. Of course, in practice, the code is used in a slightly different context. Drawing on a widget is almost exclusively done in the paintEvent() method of a widget class.

void FooWidget::paintEvent() {

   QPainter p(this);
   // Setup painter
   // Use painter

}

When drawing on a printer, you have to make sure to use QPrinter::newPage() to finish with a page and begin a new one - something that naturally is not relevant for painting widgets. Also, when printing, you may want to use the device metrics in order to compute coordinates.

Transformations

By default, when using the QPainter, it draws in the natural coordinate system of the device used. This means, if you draw a line along the horizontal axis with a length of 10 units, it will be painted as a horizontal line on the screen with a length of 10 pixels. However, QPainter can apply arbitrary affine transformations before actually rendering shapes and curves. An affine transformation maps the x and y coordinates linearly into x' and y' according to

File:Transformation-basic.png
Formula for affine transformation

The 3x3 matrix in this equation can be set with QPainter::setWorldMatrix() and is of type QWMatrix. Normally, this is the identity matrix, i.e. m11 and m22 are one, and the other parameters are zero. There are basically three different groups of transformations:

  • Translations: These move all points of an object by a fixed amount in some direction. A translation matrix can be obtained by calling method m.translate(dx, dy) for a QWMatrix. This corresponds to the matrix
File:Transformation-translate.png
Formula for translating transformation
  • Scaling: These stretch or shrink the coordinates of an object, making it bigger or smaller without distorting it. A scaling transformation can be applied to a QWMatrix by calling m.scale(sx, sy). By setting one of the parameters to a negative value, one can achieve a mirroring of the coordinate system. The corresponding matrix looks like this
File:Transformation-scale.png
Formula for scaling transformation
  • Shearing: A distortion of the coordinate system with two parameters. A shearing transformation can be applied by calling m.shear(sh, sv), corresponding to the matrix
File:Transformation-shear.png
Formula for shearing transformation
  • Rotating: This rotates an object. A rotation transformation can be applied by calling m.rotate(alpha). Note that the angle has to be given in degrees, not as mathematical angle! Notate that a rotation is equivalent with a combination of scaling and shearing. The corresponding matrix is
File:Transformation-rotate.png
Formula for rotating transformation

Here are some pictures that show the effect of the elementary transformation to our masquot:

a) Normal
File:Konqi-rotated.png
b) Rotated by 30°
c) Sheared by 0.4
d) Mirrored

Transformations can be combined by multiplying elementary matrices. Note that matrix operations are not commutative in general, and therefore the combined effect of of a concatenation depends on the order in which the matrices are multiplied.

Setting stroking attributes

The rendering of lines, curves and outlines of polygons can be modified by setting a special pen with QPainter::setPen(). The argument of this function is a QPen object. The properties stored in it are a style, a color, a join style and a cap style.

The pen style is member of the enum Qt::PenStyle. and can take one of the following values:

Pen styles

The join style is a member of the enum Qt::PenJoinStyle. It specifies how the junction between multiple lines which are attached to each other is drawn. It takes one of the following values: