Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions | ![]() |
This document describes Qt 4's approach to painting, and contrasts it with the Qt 3 approach.
The Qt 4 Paint Subsystem is primarly based on the classes QPainter, QPaintDevice and QPaintEngine. QPainter is the class used to perform drawing operations, for example, drawLine() and drawRect(). QPaintDevice is an object that can be painted on using a QPainter. Both QWidget and QPixmap are QPaintDevices. QPaintEngine is the painter's means of drawing to a specific device type.
In Qt 3.x QPainter could be used to draw on widgets and pixmaps. (It could also be used to draw to printers on Windows and Mac OS X). When other paint devices needed to be supported, such as QPrinter on X11, this was done by deriving from QPaintDevice and reimplementing the virtual function QPaintDevice::cmd(). A reimplemented paint device was treated as an external device.
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 is tied to widget/pixmap painting on the current 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.
In Qt 4 we have introduced the abstract class QPaintEngine. Implementations of this class provide the concrete functionallity needed to draw to a specific device type. The class QPaintEngine is only used internally by QPainter and QPaintDevice and is hidden from application programmers, unless they reimplement their own device type in their own QPaintEngine subclass. Qt currently provides paint engines for the following platforms and API's:
To implement support for a new backend, you must derive from QPaintEngine and reimplement its virtual functions. You also need to derive from QPaintDevice and reimplement the virtual function QPaintDevice::paintEngine() to tell QPainter which paint engine should be used to draw on this particular device.
The main benefit of this approach is that all painting follows the same painting pipeline which means that adding support for new features and providing default implementations for unsupported ones has become much simpler.
GDI+ is installed by default on Windows XP, and is available as a downloadable redistributable binary for 98/ME/NT/2000. In order for Qt to take advantage of the features in GDI+ the gdiplus.dll library must be in the PATH.
With Qt 4 it is possible to fill shapes using a linear gradient brush. A gradient in this case is used to describe the transition from one color at one point to another color at another point. We use the term linear gradient since the transition area follows a line.
Setting a linear gradient brush is done using the QBrush constructor that takes two points and two colors, as sketched below:
QBrush diagonalGradient(QPoint(0, 0), Qt::red, QPoint(width(), height()), Qt::blue); painter.setBrush(diagonalGradient); painter.drawRect(0, 0, width(), height());
The code shown above produces a pattern as show in the following pixmap:
With Qt 4 we support alpha-blended outlining and filling. The alpha channel of a color is specified through QColor.
// 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.
Alpha-blended drawing is supported on Windows, Mac OS X, and on X11 systems that have the X Render extension installed.
It is now possible to open a QPainter on a QGLWidget as if it were a normal QWidget. One huge benefit from this is that we utilize the high performance of OpenGL for most drawing operations, such as transformations and pixmap drawing.
On platforms where this is supported by the drawing API's, we provide the option of turning on anti-aliased edges when drawing primitives.
// One line without anti-aliasing painter.drawLine(0, 0, width()/2, height()); // One line with anti-aliasing painter.setRenderHints(QPainter::LineAntialiasing); painter.drawLine(width()/2, 0, width()/2, height());
This produces the following output.
Supported platforms are currently Mac OS X, Windows if GDI+ is installed, and OpenGL.
In the Qt 4 Paint Subsystem we make more use of native graphics operations. The benefit we gain from this is that these operations can potentially be performed in hardware which gives significant speed improvements.
Among these are native transformations (Windows 2000/XP, Mac OS X, and, OpenGL) making painting with a world matrix much faster. Some pixmap operations have also been moved closer to hardware.
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 one go.
Building blocks can be joined in closed sub-paths, such as a rectangle or an ellipse, or they can exist independently as unclosed sub-paths, 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 sub-path. We then add two bezier curves, and finally draw the entire path.
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:
In Qt 4, all widgets are double-buffered by default.
In previous versions of Qt double-buffereing was acheived by painting to an off-screen pixmap then copying the pixmap to the screen. e.g.
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 by setting the widget attribute Qt::WA_PaintOnScreen.
unbufferedWidget->setAttribute(Qt::WA_PaintOnScreen);
The Qt 4 Paint Subsystem is mostly completed, but there is still work being done.
Part of the work in progress is the finalization of the rendering pipeline for all platforms, so that all features are supported and look the same on all platforms. Among the currently unfinished features are these:
[Back to the Technology Preview page]
See also QBrush.
Copyright © 2004 Trolltech. | Trademarks | Qt 4.0.0-tp1 |