Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions |

# The Coordinate System

A paint device in Qt is a drawable 2D surface. QWidget, QPixmap, QPicture, and QPrinter are all paint devices. A QPainter is an object which can draw on such devices.

The default coordinate system of a paint device has its origin at the top-left corner. The x values increase to the right and the y values increase downwards. The default unit is one pixel on pixel-based devices and one point (1/72 of an inch) on printers.

## An Example

The illustration below shows a highly magnified portion of the top left corner of a paint device.

The rectangle and the line were drawn by this code (with the grid added and colors touched up in the illustration):

        void MyWidget::paintEvent(QPaintEvent *)
        {
            QPainter painter(this);
            painter.setPen(Qt::darkGray);
            painter.drawRect(1, 2, 5, 4);
            painter.setPen(Qt::lightGray);
            painter.drawLine(9, 2, 7, 7);
        }

Note that all of the pixels drawn by QPainter::drawRect() are inside the size specified (5 x 4 pixels). This is different from some toolkits; in Qt the size you specify exactly encompasses the pixels drawn. This applies to all the relevant functions in QPainter.

Similarly, the QPainter::drawLine() call draws both endpoints of the line, not just one.

Here are the classes that relate most closely to the coordinate system:

QPoint | A single 2D point in the coordinate system. Most functions in Qt that deal with points can accept either a QPoint argument or two ints, for example QPainter::drawPoint().
QSize | A single 2D vector. Internally, QPoint and QSize are the same, but a point is not the same as a size, so both classes exist. Again, most functions accept either a QSize or two ints, for example QWidget::resize().
QRect | A 2D rectangle. Most functions accept either a QRect or four ints, for example QWidget::setGeometry().
QRegion | An arbitrary set of points, including all the normal set operations, e.g. QRegion::intersect(), and also a less usual function to return a list of rectangles whose union is equal to the region. QRegion is used e.g. by QPainter::setClipRegion(), QWidget::repaint(), and QPaintEvent::region().
QPainter | The class that paints. It can paint on any device with the same code. There are differences between devices, QPrinter::newPage() is a good example, but QPainter works the same way on all devices.
QPaintDevice | A device on which QPainter can paint. There are two internal devices, both pixel-based, and two external devices, QPrinter and QPicture (which records QPainter commands to a file or other QIODevice, and plays them back). Other devices can be defined.

## Transformations

Although Qt's default coordinate system works as described above, QPainter also supports arbitrary transformations, through it's transformation matrix. Use this matrix to orient and position your objects in your model. Qt provides methods such as QPainter::rotate(), QPainter::scale(), QPainter::translate(), and so on to operate on this matrix.

QPainter::save() and QPainter::restore() save and restore this matrix. You can also use QMatrix objects, QPainter::matrix() and QPainter::setMatrix(), if you need the same transformations over and over.

One frequent need for the transformation matrix is when reusing the same drawing code on a variety of paint devices. Without transformations, the results are tightly bound to the resolution of the paint device. Printers have typically 600 dots per inch, whereas screens often have between 75 and 100 dots per inch.

Here is a short example that uses the matrix to draw the clock face in the widgets/analogclock example. We recommend compiling and running the example before you read any further. In particular, try resizing the window to different sizes.

        void AnalogClock::paintEvent(QPaintEvent *)
        {
            static QCOORD hourHand[8] = { 2, 0, 0, 2, -2, 0, 0, -25 };
            static QCOORD minuteHand[8] = { 1, 0, 0, 1, -1, 0, 0, -40 };

            int side = qMin(width(), height());

            QPainter painter(this);
            painter.translate(width() / 2, height() / 2);
            painter.scale(side / 100.0, side / 100.0);
            painter.setBrush(painter.pen().color());

First, we set up the painter. We translate the coordinate system so that point (0, 0) is in the widget's center, instead of being at the top-left corner. We also scale the system by `side` / 100, where `side` is either the widget's width or the height, whichever is shortest. We want the clock to be square, even if the device isn't.

This will give us a 100 x 100 square area with point (0, 0) in the middle that we can draw on. What we draw will show up in the largest possible square that will fit in the widget.

            QTime time = QTime::currentTime();

            painter.save();
            painter.rotate(30 * (time.hour() % 12) + time.minute() / 2);
            painter.drawConvexPolygon(QPointArray(4, hourHand));
            painter.restore();

We draw the clock's hour hand by rotating the coordinate system and calling QPainter::drawConvexPolygon(). Thank's to the rotation, it's drawn pointed in the right direction.

The polygon is specified as an array of alternating x, y values, stored in the `hourHand` static variable (defined at the beginning of the function), which corresponds to the four points (2, 0), (0, 2), (-2, 0), and (0, -25).

The calls to QPainter::save() and QPainter::restore() surrounding the code guarantees that the code that follows won't be disturbed by the transformations we've used.

            painter.save();
            painter.rotate(6 * time.minute());
            painter.drawConvexPolygon(QPointArray(4, minuteHand));
            painter.restore();

We do the same for the clock's minute hand, which is defined by the four points (1, 0), (0, 1), (-1, 0), and (0, -40). These coordinates specify a hand that is thinner and longer than the minute hand.

            for (int i = 0; i < 12; i++) {
                painter.drawLine(44, 0, 46, 0);
                painter.rotate(30);
            }

Finally, we draw the clock face, which consists of twelve short lines at 30-degree intervals. At the end of that, the painter is rotated in a way which isn't very useful, but we're done with painting so that doesn't matter.