Difference between revisions of "Development/Architecture/KDE3/Low-level Graphics"

Jump to: navigation, search
(works without div's now)
m (Text replace - "</code>" to "</syntaxhighlight>")
 
(18 intermediate revisions by 6 users not shown)
Line 1: Line 1:
Qt's low level imaging model is based on the capabilities provided
+
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.
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 ==
 
== Rendering with QPainter ==
  
 
The central graphics class for 2D painting with Qt is
 
The central graphics class for 2D painting with Qt is
[http://doc.trolltech.com/3.3/qpainter.html QPainter]. It can
+
{{qt3|QPainter}}. It can draw on a
draw on a [http://doc.trolltech.com/3.3/qpaintdevice.html QPaintDevice].
+
{{qt3|QPaintDevice}}. There are three
There are three possible paint devices implemented: One is  
+
possible paint devices implemented: One is
[http://doc.trolltech.com/3.3/qwidget.html QWidget]
+
{{qt3|QWidget}}
 
which represents a widget on the screen. The second is  
 
which represents a widget on the screen. The second is  
[http://doc.trolltech.com/3.3/qprinter.html QPrinter] which
+
{{qt3|QPrinter}} which
represents a printer and produces Postscript output. The third it
+
represents a printer and produces Postscript output. The third it the class
the class [http://doc.trolltech.com/3.3/qpicture.html QPicture] which
+
{{qt3|QPicture}} which
records paint commands and can save them on disk and play them back
+
records paint commands and can save them on disk and play them back later. A
later. A possible storage format for paint commands is the W3C standard
+
possible storage format for paint commands is the W3C standard SVG.
SVG.
+
  
So, it is possible to reuse the rendering code you use for displaying a
+
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 <tt>paintEvent()</tt> method of a widget class.
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.
+
  
<code cppqt>
+
<syntaxhighlight lang="cpp-qt">
 
void FooWidget::paintEvent()
 
void FooWidget::paintEvent()
 
{
 
{
Line 32: Line 24:
 
     // Use painter
 
     // Use painter
 
}
 
}
</code>
+
</syntaxhighlight>
  
When drawing on a printer, you have to make sure to use QPrinter::newPage()
+
When drawing on a printer, you have to make sure to use <tt>QPrinter::newPage()</tt> 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
to finish with a page and begin a new one - something that naturally is not
+
[http://doc.trolltech.com/3.3/qpaintdevicemetrics.html device metrics] in order to compute coordinates.
relevant for painting widgets. Also, when printing, you may want to use the
+
[http://doc.trolltech.com/3.3/qpaintdevicemetrics.html device metrics]
+
in order to compute coordinates.
+
  
 
== Transformations ==
 
== Transformations ==
  
By default, when using the QPainter, it draws in the natural coordinate
+
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
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
+
  
[[Image:transformation-basic.png|frame|center|Formula for affine transformation]]
+
<p class="center">
 +
<math>
 +
\begin{pmatrix} x' \\ y' \\ 1\end{pmatrix} =
 +
\begin{pmatrix}
 +
m_11 & m_12 & 0 \\
 +
m_21 & m_22 & 0 \\
 +
dx & dy & 1 \\
 +
\end{pmatrix}
 +
\begin{pmatrix} x \\ y \\ 1\end{pmatrix}
 +
</math>
 +
<br />Formula for affine transformation
 +
</p>
  
 
The 3x3 matrix in this equation can be set with <tt>QPainter::setWorldMatrix()</tt>
 
The 3x3 matrix in this equation can be set with <tt>QPainter::setWorldMatrix()</tt>
and is of type [http://doc.trolltech.com/3.3/qwmatrix.html QWMatrix].
+
and is of type {{qt3|QWMatrix}}. Normally,
Normally, this is the identity matrix, i.e. <tt>m11</tt> and <tt>m22</tt> are
+
this is the identity matrix, i.e. <tt>m<sub>11</sub></tt> and <tt>m<sub>22</sub></tt> are
one, and the other parameters are zero. There are basically three different
+
one, and the other parameters are zero. There are basically three different groups of transformations:
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 <tt>m.translate(dx, dy)</tt> for a QWMatrix. This corresponds to the matrix
+
* '''Translations''': These move all points of an object by a fixed amount in some direction. A translation matrix can be obtained by calling method <tt>m.translate(dx, dy)</tt> for a QWMatrix. This corresponds to the matrix
[[Image:transformation-translate.png|frame|center|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 <tt>m.scale(sx, sy)</tt>. 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
+
[[Image:transformation-scale.png|frame|center|Formula for scaling transformation]]
+
*Shearing: A distortion of the coordinate system with two parameters. A shearing transformation can be applied by calling <tt>m.shear(sh, sv)</tt>, corresponding to the matrix
+
[[Image:transformation-shear.png|frame|center|Formula for shearing transformation]]
+
*Rotating: This rotates an object. A rotation transformation can be applied by calling <tt>m.rotate(alpha)</tt>. 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
+
[[Image:transformation-rotate.png|frame|center|Formula for rotating transformation]]
+
  
Here are some pictures that show the effect of the elementary
+
<p class="center">
transformation to our masquot:
+
<math>
 +
\begin{pmatrix}
 +
1 & 0 & 0 \\
 +
0 & 1 & 0 \\
 +
dx & dy & 1
 +
\end{pmatrix}
 +
</math>
 +
<br />Formula for translating transformation
 +
</p>
 +
 
 +
* '''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 <tt>m.scale(sx, sy)</tt>. 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
 +
<p class="center">
 +
<math>
 +
\begin{pmatrix}
 +
sx & 0 & 0 \\
 +
0 & sy & 0 \\
 +
0 & 0 & 1
 +
\end{pmatrix}
 +
</math>
 +
<br />Formula for scaling transformation
 +
</p>
 +
 
 +
*'''Shearing''': A distortion of the coordinate system with two parameters. A shearing transformation can be applied by calling <tt>m.shear(sh, sv)</tt>, corresponding to the matrix
 +
<p class="center">
 +
<math>
 +
\begin{pmatrix}
 +
1 & sv & 0 \\
 +
sh & 1 & 0 \\
 +
0 & 0 & 1
 +
\end{pmatrix}
 +
</math>
 +
<br />Formula for shearing transformation
 +
</p>
 +
 
 +
*'''Rotating''': This rotates an object. A rotation transformation can be applied by calling <tt>m.rotate(alpha)</tt>. 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
 +
 
 +
<p class="center">
 +
<math>
 +
\begin{pmatrix}
 +
\cos{\alpha} &  \sin{\alpha} & 0 \\
 +
-\sin{\alpha} & \cos{\alpha} & 0 \\
 +
0 & 0 & 1
 +
\end{pmatrix}
 +
</math>
 +
<br />Formula for rotating transformation
 +
</p>
 +
 
 +
Here are some pictures that show the effect of the elementary transformation to our mascot:
  
 
{| align="center"
 
{| align="center"
 
||[[Image:konqi-normal.png|frame|none|a) Normal]]
 
||[[Image:konqi-normal.png|frame|none|a) Normal]]
||[[Image:konqi-rotated.png|frame|none|b) Rotated by 30°]]
+
||[[Image:konqi-rotated2.png|frame|none|b) Rotated by 30°]]
 
|-
 
|-
 
||[[Image:konqi-sheared.png|frame|none|c) Sheared by 0.4]]
 
||[[Image:konqi-sheared.png|frame|none|c) Sheared by 0.4]]
Line 87: Line 120:
 
The rendering of lines, curves and outlines of polygons can be modified by  
 
The rendering of lines, curves and outlines of polygons can be modified by  
 
setting a special pen with <tt>QPainter::setPen()</tt>. The argument of this
 
setting a special pen with <tt>QPainter::setPen()</tt>. The argument of this
function is a [http://doc.trolltech.com/3.3/qpen.html QPen] object. The properties
+
function is a {{qt3|QPen}} object. The properties
 
stored in it are a style, a color, a join style and a cap style.
 
stored in it are a style, a color, a join style and a cap style.
  
Line 102: Line 135:
  
  
{| align="center"
+
{| width="100%"
||[[Image:pen-joinmiter.png|frame|none|a) MiterJoin]]
+
|align="center"|[[Image:pen-joinmiter.png|frame|]]a) MiterJoin
||[[Image:pen-joinbevel.png|frame|none|a) BevelJoin]]
+
|align="center"|[[Image:pen-joinbevel.png|frame|none]]b) BevelJoin
||[[Image:pen-joinround.png|frame|none|a) RoundJoin]]
+
|align="center"|[[Image:pen-joinround.png|frame|none]]c) RoundJoin
 
|}
 
|}
  
Line 113: Line 146:
 
from the following table:
 
from the following table:
  
{| align="center"
+
{| width="100%"
||[[Image:capflat.png|frame|none|a) FlatCap]]
+
|align="center"|[[Image:capflat.png|frame|none]]a) FlatCap
||[[Image:capsquare.png|frame|none|a) SquareCap]]
+
|align="center"|[[Image:capsquare.png|frame|none]]b) SquareCap
||[[Image:capround.png|frame|none|a) RoundCap]]
+
|align="center"|[[Image:capround2.png|frame|none]]c) RoundCap
 
|}
 
|}
  
Line 122: Line 155:
  
 
The fill style of polygons, circles or rectangles can be modified by setting
 
The fill style of polygons, circles or rectangles can be modified by setting
a special brush with QPainter::setBrush(). This function takes a
+
a special brush with <tt>QPainter::setBrush()</tt> This function takes a
 
[http://doc.trolltech.com/3.3/qbrush.html QBrush] object as argument.  
 
[http://doc.trolltech.com/3.3/qbrush.html QBrush] object as argument.  
 
Brushes can be constructed in four different ways:
 
Brushes can be constructed in four different ways:
  
*QBrush::QBrush() - This creates a brush that does not fill shapes.
+
*<tt>QBrush::QBrush()</tt> - This creates a brush that does not fill shapes.
*QBrush::QBrush(BrushStyle) - This creates a black brush with one of the default patterns shown below.
+
*<tt>QBrush::QBrush(BrushStyle)</tt> - This creates a black brush with one of the default patterns shown below.
*QBrush::QBrush(const QColor &, BrushStyle) - This creates a colored brush with one of the patterns shown below.
+
*<tt>QBrush::QBrush(const QColor &, BrushStyle)</tt> - This creates a colored brush with one of the patterns shown below.
*QBrush::QBrush(const QColor &, const QPixmap) - This creates a colored brush with the custom pattern you give as second parameter.
+
*<tt>QBrush::QBrush(const QColor &, const QPixmap)</tt> - This creates a colored brush with the custom pattern you give as second parameter.
  
 
A default brush style is from the enum
 
A default brush style is from the enum
Line 137: Line 170:
 
[[Image:q3brushstyles.png|frame|none|Brush styles]]
 
[[Image:q3brushstyles.png|frame|none|Brush styles]]
  
A further way to customize the brush behavior is to use the function
+
A further way to customize the brush behavior is to use the function <tt>QPainter::setBrushOrigin()</tt>.
QPainter::setBrushOrigin().
+
  
== Color ==
+
== Colors ==
  
Colors play a role both when stroking curves and when filling shapes. In Qt,  
+
Colors play a role both when stroking curves and when filling shapes. In Qt, colors are represented by the class  
colors are represented by the class  
+
{{qt3|QColor}}. Qt does not support advanced graphics features like ICC color profiles and color correction. Colors are usually constructed by specifying their red, green and blue components, as the RGB model is the way pixels are composed of on a monitor.
[http://doc.trolltech.com/3.3/qcolor.html QColor]. Qt does not support  
+
advanced graphics features like ICC color profiles and color correction. Colors  
+
are usually constructed by specifying their red, green and blue components, as  
+
the RGB model is the way pixels are composed of on a monitor.  
+
  
It is also possible to use hue, saturation and value. This HSV representation is  
+
It is also possible to use hue, saturation and value. This HSV representation is what you use in the Gtk color dialog, e.g. in GIMP. There, the hue corresponds to the angle on the color wheel, while the saturation corresponds to the distance from the center of the circle. The value can be chosen with a separate slider.
what you use in the Gtk color dialog, e.g. in GIMP. There, the hue corresponds
+
to the angle on the color wheel, while the saturation corresponds to the  
+
distance from the center of the circle. The value can be chosen with a separate
+
slider.
+
  
 
== Other settings ==
 
== Other settings ==
  
Normally, when you paint on a paint device, the pixels you draw replace those
+
Normally, when you paint on a paint device, the pixels you draw replace those that were there previously. This means, if you paint a certain region with a red color and paint the same region with a blue color afterwards, only the blue color will be visible. Qt's imaging model does not support transparency, i.e. a way to blend the painted foreground with the background. However, there is a simple way to combine background and foreground with boolean operators. The method <tt>QPainter::setRasterOp()</tt> sets the used operator,
that were there previously. This means, if you paint a certain region with
+
a red color and paint the same region with a blue color afterwards, only
+
the blue color will be visible. Qt's imaging model does not support  
+
transparency, i.e. a way to blend the painted foreground with the background.
+
However, there is a simple way to combine background and foreground with
+
boolean operators. The method QPainter::setRasterOp() sets the used operator,
+
 
which comes from the enum  
 
which comes from the enum  
 
[http://doc.trolltech.com/3.3/qt.html#RasterOp-enum RasterOp].
 
[http://doc.trolltech.com/3.3/qt.html#RasterOp-enum RasterOp].
  
The default is CopyROP which ignores the background. Another popular choice is
+
The default is CopyROP which ignores the background. Another popular choice is XorROP. If you paint a black line with this operator on a colored image, then the covered area will be inverted. This effect is for example used to create the rubberband selections in image manipulation programs known as "marching ants".
XorROP. If you paint a black line with this operator on a colored image, then  
+
the covered area will be inverted. This effect is for example used to create
+
the rubberband selections in image manipulation programs known as  
+
"marching ants".
+
  
 
== Drawing graphics primitives ==
 
== Drawing graphics primitives ==
  
In the following we list the elementary graphics elements supported by  
+
In the following we list the elementary graphics elements supported by QPainter. Most of them exist in several overloaded versions which take a different number of arguments. For example, methods that deal with rectangles usually either take a [http://doc.trolltech.com/3.3/qrect.html QRect] as an argument or a set of four integers.
QPainter. Most of them exist in several overloaded versions which take a  
+
different number of arguments. For example, methods that deal with rectangles
+
usually either take a [http://doc.trolltech.com/3.3/qrect.html QRect] as
+
argument or a set of four integers.
+
  
*Drawing a single point - drawPoint().
+
*Drawing a single point - <tt>drawPoint()</tt>.
*Drawing lines - drawLine(), drawLineSegments() and drawPolyLine().
+
*Drawing lines - <tt>drawLine()</tt>, <tt>drawLineSegments()</tt> and <tt>drawPolyLine()</tt>.
*Drawing and filling rectangles - drawRect(), drawRoundRect(), fillRect() and eraseRect().
+
*Drawing and filling rectangles - <tt>drawRect()</tt>, <tt>drawRoundRect()</tt>, <tt>fillRect()</tt> and <tt>eraseRect()</tt>.
*Drawing and filling circles, ellipses and parts or them - drawEllipse(), drawArc(), drawPie and drawChord().
+
*Drawing and filling circles, ellipses and parts or them - <tt>drawEllipse()</tt>, <tt>drawArc()</tt>, <tt>drawPie()</tt> and <tt>drawChord()</tt>.
*Drawing and filling general polygons - drawPolygon().
+
*Drawing and filling general polygons - <tt>drawPolygon()</tt>.
*Drawing bezier curves - drawQuadBezier() [drawCubicBezier in Qt 3.0].
+
*Drawing bezier curves - <tt>drawQuadBezier()</tt> [<tt>drawCubicBezier()</tt> in Qt 3.0].
  
 
== Drawing pixmaps and images ==
 
== Drawing pixmaps and images ==
Line 192: Line 202:
 
Qt provides two very different classes to represent images.  
 
Qt provides two very different classes to represent images.  
  
[http://doc.trolltech.com/3.3/qpixmap.html QPixmap] directly corresponds
+
{{qt3|QPixmap}} directly corresponds to the pixmap objects in X11. Pixmaps are server-side objects and may - on a modern graphics card - even be stored directly in the card's memory. This makes it ''very'' efficient to transfer pixmaps to the screen. Pixmaps also act as an off-screen equivalent of widgets - the QPixmap class is a subclass of QPaintDevice, so you can draw on it with a QPainter. Elementary drawing
to the pixmap objects in X11. Pixmaps are server-side objects and may - on a
+
operations are usually accelerated by modern graphics. Therefore, a common usage pattern is to use pixmaps for double buffering. This means, instead of painting
modern graphics card - even be stored directly in the card's memory. This makes
+
it ''very'' efficient to transfer pixmaps to the screen. Pixmaps also act as
+
an off-screen equivalent of widgets - the QPixmap class is a subclass of  
+
QPaintDevice, so you can draw on it with a QPainter. Elementary drawing  
+
operations are usually accelerated by modern graphics. Therefore, a common usage
+
pattern is to use pixmaps for double buffering. This means, instead of painting
+
 
directly on a widget, you paint on a temporary pixmap object and use the
 
directly on a widget, you paint on a temporary pixmap object and use the
[http://doc.trolltech.com/3.3/qpaintdevice.html#bitBlt bitBlt]
+
[http://doc.trolltech.com/3.3/qpaintdevice.html#bitBlt bitBlt] function to transfer the pixmap to the widget. For complex repaints, this helps to avoid flicker.
function to transfer the pixmap to the widget. For complex repaints, this helps
+
to avoid flicker.
+
  
In contrast, [http://doc.trolltech.com/3.3/qimage.html QImage] objects
+
In contrast, {{qt3|QImage}} objects live on the client side. Their emphasis in on providing direct access to the pixels of the image. This makes them of use for image manipulation, and things
live on the client side. Their emphasis in on providing direct access to the
+
like loading and saving to disk (QPixmap's load() method takes QImage as intermediate step). On the other hand, painting an image on a widget is a relatively expensive operation, as it implies a transfer to the X server,
pixels of the image. This makes them of use for image manipulation, and things
+
which can take some time, especially for large images and for remote servers. Depending on the color depth, the conversion from QImage to QPixmap may also require dithering.
like loading and saving to disk (QPixmap's load() method takes QImage as  
+
intermediate step). On the other hand, painting an image on a widget is a
+
relatively expensive operation, as it implies a transfer to the X server,
+
which can take some time, especially for large images and for remote servers.
+
Depending on the color depth, the conversion from QImage to QPixmap may also  
+
require dithering.
+
  
 
== Drawing text ==
 
== Drawing text ==
  
Text can be drawn with one of the overloaded variants of the method  
+
Text can be drawn with one of the overloaded variants of the method <tt>QPainter::drawText()</tt>. These draw a QString either at a given point or in a given rectangle, using the font set by <tt>QPainter::setFont()</tt>. There is also a parameter which takes an ORed combination of some flags from the enums
QPainter::drawText(). These draw a QString either at a given point or in a given
+
rectangle, using the font set by QPainter::setFont(). There is also a parameter
+
which takes an ORed combination of some flags from the enums
+
 
[http://doc.trolltech.com/3.3/qt.html#AlignmentFlags-enum Qt::AlignmentFlags]
 
[http://doc.trolltech.com/3.3/qt.html#AlignmentFlags-enum Qt::AlignmentFlags]
 
and
 
and
 
[http://doc.trolltech.com/3.3/qt.html#TextFlags-enum Qt::TextFlags]
 
[http://doc.trolltech.com/3.3/qt.html#TextFlags-enum Qt::TextFlags]
  
Beginning with version 3.0, Qt takes care of the complete text layout even for
+
Beginning with version 3.0, Qt takes care of the complete text layout even for languages written from right to left.
languages written from right to left.
+
  
 
A more advanced way to display marked up text is the
 
A more advanced way to display marked up text is the
[http://doc.trolltech.com/3.3/qsimplerichtext.html QSimpleRichText]
+
{{qt3|QSimpleRichText}} class. Objects of this class can be constructed with a piece of text using a subset of the HTML tags, which is quite rich and provides even tables. The text style can be customized by using a
class. Objects of this class can be constructed with a piece of text using
+
{{qt3|QStyleSheet}} (the documentation of the tags can also be found here). Once the rich text object has been constructed, it can be rendered on a widget or another paint device with the <tt>QSimpleRichText::draw()</tt> method.
a subset of the HTML tags, which is quite rich and provides even tables.
+
The text style can be customized by using a  
+
[http://doc.trolltech.com/3.3/qstylesheet.html QStyleSheet] (the
+
documentation of the tags can also be found here). Once the rich text object has
+
been constructed, it can be rendered on a widget or another paint device with
+
the QSimpleRichText::draw() method.
+
  
  
 
''Initial Author:'' [mailto:bernd@kdevelop.org Bernd Gehrmann]
 
''Initial Author:'' [mailto:bernd@kdevelop.org Bernd Gehrmann]
 +
 +
[[Category:KDE3]]
 +
[[Category:Architecture]]

Latest revision as of 21:49, 29 June 2011

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.

Contents

[edit] 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.

[edit] 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

<math> \begin{pmatrix} x' \\ y' \\ 1\end{pmatrix} = \begin{pmatrix} m_11 & m_12 & 0 \\ m_21 & m_22 & 0 \\ dx & dy & 1 \\ \end{pmatrix} \begin{pmatrix} x \\ y \\ 1\end{pmatrix} </math>
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

<math> \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ dx & dy & 1 \end{pmatrix} </math>
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

<math> \begin{pmatrix} sx & 0 & 0 \\ 0 & sy & 0 \\ 0 & 0 & 1 \end{pmatrix} </math>
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

<math> \begin{pmatrix} 1 & sv & 0 \\ sh & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix} </math>
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

<math> \begin{pmatrix} \cos{\alpha} & \sin{\alpha} & 0 \\ -\sin{\alpha} & \cos{\alpha} & 0 \\ 0 & 0 & 1 \end{pmatrix} </math>
Formula for rotating transformation

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

a) Normal
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.

[edit] 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:


Pen-joinmiter.png
a) MiterJoin
Pen-joinbevel.png
b) BevelJoin
Pen-joinround.png
c) RoundJoin

The cap style is a member of the enum Qt::PenCapStyle and specifies how the end points of lines are drawn. It takes one of the values from the following table:

Capflat.png
a) FlatCap
Capsquare.png
b) SquareCap
Capround2.png
c) RoundCap

[edit] Setting fill attributes

The fill style of polygons, circles or rectangles can be modified by setting a special brush with QPainter::setBrush() This function takes a QBrush object as argument. Brushes can be constructed in four different ways:

  • QBrush::QBrush() - This creates a brush that does not fill shapes.
  • QBrush::QBrush(BrushStyle) - This creates a black brush with one of the default patterns shown below.
  • QBrush::QBrush(const QColor &, BrushStyle) - This creates a colored brush with one of the patterns shown below.
  • QBrush::QBrush(const QColor &, const QPixmap) - This creates a colored brush with the custom pattern you give as second parameter.

A default brush style is from the enum Qt::BrushStyle. Here is a picture of all predefined patterns:

Brush styles

A further way to customize the brush behavior is to use the function QPainter::setBrushOrigin().

[edit] Colors

Colors play a role both when stroking curves and when filling shapes. In Qt, colors are represented by the class QColor. Qt does not support advanced graphics features like ICC color profiles and color correction. Colors are usually constructed by specifying their red, green and blue components, as the RGB model is the way pixels are composed of on a monitor.

It is also possible to use hue, saturation and value. This HSV representation is what you use in the Gtk color dialog, e.g. in GIMP. There, the hue corresponds to the angle on the color wheel, while the saturation corresponds to the distance from the center of the circle. The value can be chosen with a separate slider.

[edit] Other settings

Normally, when you paint on a paint device, the pixels you draw replace those that were there previously. This means, if you paint a certain region with a red color and paint the same region with a blue color afterwards, only the blue color will be visible. Qt's imaging model does not support transparency, i.e. a way to blend the painted foreground with the background. However, there is a simple way to combine background and foreground with boolean operators. The method QPainter::setRasterOp() sets the used operator, which comes from the enum RasterOp.

The default is CopyROP which ignores the background. Another popular choice is XorROP. If you paint a black line with this operator on a colored image, then the covered area will be inverted. This effect is for example used to create the rubberband selections in image manipulation programs known as "marching ants".

[edit] Drawing graphics primitives

In the following we list the elementary graphics elements supported by QPainter. Most of them exist in several overloaded versions which take a different number of arguments. For example, methods that deal with rectangles usually either take a QRect as an argument or a set of four integers.

  • Drawing a single point - drawPoint().
  • Drawing lines - drawLine(), drawLineSegments() and drawPolyLine().
  • Drawing and filling rectangles - drawRect(), drawRoundRect(), fillRect() and eraseRect().
  • Drawing and filling circles, ellipses and parts or them - drawEllipse(), drawArc(), drawPie() and drawChord().
  • Drawing and filling general polygons - drawPolygon().
  • Drawing bezier curves - drawQuadBezier() [drawCubicBezier() in Qt 3.0].

[edit] Drawing pixmaps and images

Qt provides two very different classes to represent images.

QPixmap directly corresponds to the pixmap objects in X11. Pixmaps are server-side objects and may - on a modern graphics card - even be stored directly in the card's memory. This makes it very efficient to transfer pixmaps to the screen. Pixmaps also act as an off-screen equivalent of widgets - the QPixmap class is a subclass of QPaintDevice, so you can draw on it with a QPainter. Elementary drawing operations are usually accelerated by modern graphics. Therefore, a common usage pattern is to use pixmaps for double buffering. This means, instead of painting directly on a widget, you paint on a temporary pixmap object and use the bitBlt function to transfer the pixmap to the widget. For complex repaints, this helps to avoid flicker.

In contrast, QImage objects live on the client side. Their emphasis in on providing direct access to the pixels of the image. This makes them of use for image manipulation, and things like loading and saving to disk (QPixmap's load() method takes QImage as intermediate step). On the other hand, painting an image on a widget is a relatively expensive operation, as it implies a transfer to the X server, which can take some time, especially for large images and for remote servers. Depending on the color depth, the conversion from QImage to QPixmap may also require dithering.

[edit] Drawing text

Text can be drawn with one of the overloaded variants of the method QPainter::drawText(). These draw a QString either at a given point or in a given rectangle, using the font set by QPainter::setFont(). There is also a parameter which takes an ORed combination of some flags from the enums Qt::AlignmentFlags and Qt::TextFlags

Beginning with version 3.0, Qt takes care of the complete text layout even for languages written from right to left.

A more advanced way to display marked up text is the QSimpleRichText class. Objects of this class can be constructed with a piece of text using a subset of the HTML tags, which is quite rich and provides even tables. The text style can be customized by using a QStyleSheet (the documentation of the tags can also be found here). Once the rich text object has been constructed, it can be rendered on a widget or another paint device with the QSimpleRichText::draw() method.


Initial Author: Bernd Gehrmann


This page was last modified on 29 June 2011, at 21:49. This page has been accessed 4,821 times. Content is available under Creative Commons License SA 3.0 as well as the GNU Free Documentation License 1.2.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal