![]() |
Home · Overviews · Examples |
This document describes Qt 4's painting system, providing a comparison between the approaches used by Qt when rendering graphics in Qt 3 and Qt 4.
QPainter was capable of recognizing external devices and could serialize each paint operation to the reimplemented cmd() function. This allowed reimplementation of arbitrary devices, but the approach has some disadvantages which we have addressed in Qt 4. One of these is that an external device could not reuse any functionality implemented in QPainter since QPainter was tied to widget/pixmap painting on that platform. Supporting multiple device backends, such as OpenGL, was therefore inconvenient and not very efficient.
This has led us to devise a more convenient and intuitive API for Qt 4.How Painting is Done in Qt 4
In Qt 4 we have introduced the QPaintEngine abstract class. Implementations of this class provide the concrete functionality needed to draw to specific device types. The QPaintEngine class is only used internally by QPainter and QPaintDevice, and it is hidden from application programmers unless they reimplement their own device types for their own QPaintEngine subclasses. Qt currently provides paint engines for the following platforms and APIs:
The main benefit of this approach is that all painting follows the same painting pipeline. This means that adding support for new features and providing default implementations for unsupported ones has become much simpler. Linear gradients are specified using two control points. Setting a linear gradient brush is done by creating a QLinearGradient object and setting it as a brush. New Features in the Qt 4 Paint System
Gradient Brushes
With Qt 4 it is possible to fill shapes using gradient brushes. A gradient in this case is used to describe the transition from one color at a given point to different color at another point. A gradient can span from one color to another or over a number of colors by specifying multiple colors at positions in the gradient area. Qt 4 supports linear, radial, and conical gradients.
QLinearGradient gradient(0, 0, 100, 100);
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(0.5, Qt::green);
gradient.setColorAt(1, Qt::blue);
painter.setBrush(gradient);
painter.drawRect(0, 0, 100, 100);
The code shown above produces a pattern as show in the following pixmap:
Radial gradients are specified using a center, a radius, and a focal point. Setting a radial brush is done by creating a QRadialGradient object and setting it as a brush.
QRadialGradient gradient(50, 50, 50, 30, 30); gradient.setColorAt(0.2, Qt::white); gradient.setColorAt(0.8, Qt::green); gradient.setColorAt(1, Qt::black); painter.setBrush(gradient); painter.drawEllipse(0, 0, 100, 100);The code shown above produces a pattern as shown in the following pixmap:
QConicalGradient gradient(60, 40, 0); gradient.setColorAt(0, Qt::black); gradient.setColorAt(0.4, Qt::green); gradient.setColorAt(0.6, Qt::white); gradient.setColorAt(1, Qt::black); painter.setBrush(gradient); painter.drawEllipse(0, 0, 100, 100);The code shown above produces a pattern as shown in the following pixmap:
// Specfiy semi-transparent red painter.setBrush(QColor(255, 0, 0, 127)); painter.drawRect(0, 0, width()/2, height()); // Specify semi-transparend blue painter.setBrush(QColor(0, 0, 255, 127)); painter.drawRect(0, 0, width(), height()/2);The code shown above produces the following output:
// One line without anti-aliasing painter.drawLine(0, 0, width()/2, height()); // One line with anti-aliasing painter.setRenderHint(QPainter::Antialiasing); painter.drawLine(width()/2, 0, width()/2, height());This produces the following output:
Among these are native transformations (Mac OS X and OpenGL), making painting with a world matrix much faster. Some pixmap operations have also been moved closer to the underlying hardware implementations. Building blocks can be joined in closed subpaths, such as a rectangle or an ellipse, or they can exist independently as unclosed subpaths, although an unclosed path will not be filled. Below is a code example on how a path can be used. The painter in this case has a pen width of 3 and a light blue brush. We first add a rectangle, which becomes a closed subpath. We then add two bezier curves, and finally draw the entire path. In previous versions of Qt double-buffering was achieved by painting to an off-screen pixmap then copying the pixmap to the screen. For example: Painter Paths
A painter path is an object composed of a number of graphical building blocks, such as rectangles, ellipses, lines, and curves. A painter path can be used for filling, outlining, and for clipping. The main advantage of painter paths over normal drawing operations is that it is possible to build up non-linear shapes which can be drawn later in one go.
QPainterPath path;
path.addRect(20, 20, 60, 60);
path.addBezier(0, 0, 99, 0, 50, 50, 99, 99);
path.addBezier(99, 99, 0, 99, 50, 50, 0, 0);
painter.drawPath(path);
The code above produces the following output: Widget Double-Buffering
In Qt 4, all widgets are double-buffered by default.
QPixmap buffer(size());
QPainter painter(&buffer);
// Paint code here
painter.end();
bitBlt(this, 0, 0, &buffer);
Since the double-buffering is handled by QWidget internally this now becomes:
QPainter painter(this); // Paint code here painter.end();Double-buffering is turned on by default, but can be turned off for individual widgets by setting the widget attribute Qt::WA_PaintOnScreen.
unbufferedWidget->setAttribute(Qt::WA_PaintOnScreen);
In Qt 4, pens and brushes honor the painter's transformation matrix.
Note that this feature is still in development and not yet supported on all platforms.Custom Filled Pens
In Qt 4, it is possible to specify how an outline should be filled. It can be a solid color or a QBrush, which makes it possible to specify both texture and gradient fills for both text and outlines.
QLinearGradient gradient(0, 0, 100, 100); gradient.setColorAt(0, Qt::blue); gradient.setColorAt(1, Qt::red); painter.setPen(QPen(gradient, 0)); for (int y=fontSize; y<100; y+=fontSize) drawText(0, y, text);The code above produces the following output:
One advantage of this is that it is possible to guarantee the pixel exactness of any drawing operation in a platform-independent way.
Painting on an image is as simple as drawing on any other paint device.
QImage image(100, 100, 32); QPainter painter(&image); // painter commands. painter.end();
Displaying an SVG drawing in an application is as simple as displaying a bitmap image. QSvgWidget is a display widget that can be placed in an appropriate place in a user interface, and new content can be loaded as required. For example, a predetermined file can be loaded and displayed in a widget with little effort:
QSvgWidget window = new QSvgWidget(":/files/spheres.svg"); window.show();For applications with more specialized requirements, the QSvgRenderer class provides more control over the way SVG drawings are rendered and animated.
Copyright © 2008 Trolltech | Trademarks | Qt Jambi 4.4.0_01 |