📄 coordsys.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"><html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Qt Toolkit - The Coordinate System</title><style type="text/css"><!--h3.fn,span.fn { margin-left: 1cm; text-indent: -1cm; }a:link { color: #004faf; text-decoration: none }a:visited { color: #672967; text-decoration: none }body { background: white; color: black; }--></style></head><body bgcolor="#ffffff"><p><table width="100%"><tr><td><a href="index.html"><img width="100" height="100" src="qtlogo.png"alt="Home" border="0"><img width="100"height="100" src="face.png" alt="Home" border="0"></a><td valign="top"><div align="right"><img src="dochead.png" width="472" height="27"><br><a href="classes.html"><b>Classes</b></a>- <a href="annotated.html">Annotated</a>- <a href="hierarchy.html">Tree</a>- <a href="functions.html">Functions</a>- <a href="index.html">Home</a>- <a href="topicals.html"><b>Structure</b> <font face="Arial,Helvetica,Geneva,Swiss,SunSans-Regular" align="center" size=32>Qte</font></a></div></table><h1 align="center"> The Coordinate System</h1><br clear="all">A <a href="qpaintdevice.html">paint device</a> in Qt is a drawable 2Dsurface. <a href="qwidget.html">QWidget</a>, <a href="qpixmap.html">QPixmap</a>, <a href="qpicture.html">QPicture</a> and <a href="qprinter.html">QPrinter</a> are allpaint devices. A <a href="qpainter.html">QPainter</a> is an object to draw on such surfaces.<p>The default coordinate system of a paint device has its origin at thetop left corner. X increases to the right and Y increases downwards.The unit is one pixel on pixel-based devices and one point onprinters.<p><h2>An Example</h2><p>The illustration below shows a strongly magnified portion of the topleft corner of a paint device.<p><img src="coordsys.png" width="342" height="340"><p>The rectangle and the line were drawn by this code (with the gridadded and colors touched up afterwards):<p><pre> void MyWidget::paintEvent( <a href="qpaintevent.html">QPaintEvent</a> * ) { <a href="qpainter.html">QPainter</a> p( this ); p.<a href="qpainter.html#0183e4">setPen</a>( lightGray ); p.<a href="qpainter.html#4c0077">drawRect</a>( 1,2, 5,4 ); p.<a href="qpainter.html#0183e4">setPen</a>( darkGray ); p.<a href="qpainter.html#e3a489">drawLine</a>( 9,2, 7,7 ); }</pre><p>Note that all of the pixels drawn by drawRect() are inside the sizespecified (5*4 pixels). This is different from some toolkits; in Qtthe size you specify exactly encompasses the the pixels drawn. Thisapplies to all the relevant function in QPainter.<p>Similarly, the drawLine() call draws both endpoints of the line, notjust one.<p>Here are the classes that relate most closely to the coordinatesystem: <ul><li> <a href="qpoint.html">QPoint</a> is a single 2D point in the coordinate system. Mostfunctions in Qt that deal with points can accept both a QPointargument and two ints, for example <a href="qpainter.html#8e172b">QPainter::drawPoint()</a>.<li> <a href="qsize.html">QSize</a> is a single 2D vector. Internally, QPoint and QSize arethe same, but a point is not the same as a size, so both classesexist. Again, most functions accept both a QSize and two ints, forexample <a href="qwidget.html#8fcbbe">QWidget::resize()</a>.<li> <a href="qrect.html">QRect</a> is a 2D rectangle. Most functions accept both a QRectand four ints, for example <a href="qwidget.html#9ede68">QWidget::setGeometry()</a>.<li> <a href="qregion.html">QRegion</a> is an arbitrary set of points, including all thenormal set operations, e.g. <a href="qregion.html#28e973">QRegion::intersect()</a>, and also a lessusual function to return a list of rectangles whose union is equal tothe region. QRegion is used e.g. by <a href="qpainter.html#15cc78">QPainter::setClipRegion()</a>, <a href="qwidget.html#7569b1">QWidget::repaint()</a> and <a href="qpaintevent.html#dc5fc5">QPaintEvent::region()</a>.<li> <a href="qpainter.html">QPainter</a> is the class that paints. It can paint on any devicewith the same code. There are differences between devices, <a href="qprinter.html#d4f693">QPrinter::newPage()</a> is a good example, but QPainter works the same wayon all devices.<li> <a href="qpaintdevice.html">QPaintDevice</a> is a device on which QPainter can paint. Thereare two internal devices, both pixel-based, and two external devices,<a href="qprinter.html">QPrinter</a> and <a href="qpicture.html">QPicture</a> (which records QPainter commands to a fileor other <a href="qiodevice.html">QIODevice</a>, and plays them back). Other devices can bedefined.<p></ul><p><h2>Transformations</h2><p>While Qt's default coordinate system is as described above, <a href="qpainter.html">QPainter</a> supports arbitrary transformations.<p>This transformation engine is a three-step pipeline, closely followingthe model outlined in books such as<a href="http://www.amazon.com/exec/obidos/ASIN/0201848406/trolltech/t">Foley & Van Dam</a> and the<a href="http://www.amazon.com/exec/obidos/ASIN/0201604582/trolltech/t">OpenGL Programming Guide.</a> We refer to those for an in-depthcoverage; here we give just a brief overview and an example.<p>The first step uses the world transformation matrix. Use this matrixto orient and position your objects in your model. Qt providesmethods such as <a href="qpainter.html#b5205c">QPainter::rotate()</a>, <a href="qpainter.html#e5ec3e">QPainter::scale()</a>, <a href="qpainter.html#eb778c">QPainter::translate()</a> and so on to operate on this matrix.<p><a href="qpainter.html#938d23">QPainter::save()</a> and <a href="qpainter.html#ddb3f4">QPainter::restore()</a> save and restore thismatrix. You can also use <a href="qwmatrix.html">QWMatrix</a> objects, <a href="qpainter.html#e876ac">QPainter::worldMatrix()</a> and <a href="qpainter.html#862c4d">QPainter::setWorldMatrix()</a> to store anduse named matrices.<p>The second step uses the window. The window describes the viewboundaries in model coordinates. The matrix positions the <em>objects</em>and <a href="qpainter.html#ad8b2b">QPainter::setWindow()</a> positions the <em>window,</em> deciding whatcoordinates will be visible. (If you have 3D experience, the windowis what's usually called projection in 3D.)<p>The third step uses the viewport. The viewport too describes the viewboundaries, but in device coordinates. The viewport and the windowsdescribe the same rectangle, but in different coordinate systems.<p>On-screen, the default is the entire <a href="qwidget.html">QWidget</a> or <a href="qpixmap.html">QPixmap</a> whereyou are drawing, which is mostly suitable. For printing this functionis vital, since very few printers even <em>can</em> print on the entirepaper.<p>So in short, each object to be drawn is transformed into modelcoordinates using <a href="qpainter.html#e876ac">QPainter::worldMatrix()</a>, then clipped by <a href="qpainter.html#99513c">QPainter::window()</a>, and finally positioned on the drawing device using<a href="qpainter.html#3ea58a">QPainter::viewport()</a>.<p>It is perfectly possible to do without one or two of the stages. If,for example, your goal is to draw something scaled, then using just <a href="qpainter.html#e5ec3e">QPainter::scale()</a> makes perfect sense. If your goal is to use afixed-size coordinate system, just <a href="qpainter.html#ad8b2b">QPainter::setWindow()</a> isperfect. And so on.<p>Here is a short example that uses all three mechanisms: the functionthat draws the clock face in the aclock/aclock.cpp example. Werecommend compiling and running the example before you read anyfurther. In particular, try resizing the window to different shapes. <pre> void AnalogClock::drawClock( <a href="qpainter.html">QPainter</a> *paint ) { paint-><a href="qpainter.html#938d23">save</a>();</pre><p>First off, we save the painter's state, so that the calling functionis guaranteed not to be disturbed by the transformations we're goingto use. <pre> paint-><a href="qpainter.html#ad8b2b">setWindow</a>( -500,-500, 1000,1000 );</pre><p>We set the model coordinate system we want: A 1000*1000 window where0,0 is in the middle. <pre> <a href="qrect.html">QRect</a> v = paint-><a href="qpainter.html#3ea58a">viewport</a>(); int d = QMIN( v.<a href="qrect.html#45fe95">width</a>(), v.<a href="qrect.html#581ab8">height</a>() );</pre><p>The device may not be square and we want the clock to be, so we findits current viewport and compute its shortest side. <pre> paint-><a href="qpainter.html#42d67a">setViewport</a>( v.<a href="qrect.html#369cab">left</a>() + (v.<a href="qrect.html#45fe95">width</a>()-d)/2, v.<a href="qrect.html#4dd27e">top</a>() + (v.<a href="qrect.html#581ab8">height</a>()-d)/2, d, d );</pre><p>Then we set a new square viewport, centered in the old one.<p>We're now done with our view. From this point in, when we draw in a1000*1000 area around 0,0, what we draw will show up in the biggestpossible square that'll fit in the output device.<p>Time to start drawing. <pre> time = QTime::currentTime(); <a href="qpointarray.html">QPointArray</a> pts;</pre><p>Since we'll draw a clock, we'll need to know the time. <em>pts</em> is justa utility variable to hold some points.<p>Next comes three drawing blocks, one for the hour hand, one for theminute hand and finally one for the clock face itself. First we drawthe hour hand: <pre> paint-><a href="qpainter.html#938d23">save</a>(); paint-><a href="qpainter.html#b5205c">rotate</a>( 30*(time.hour()%12-3) + time.minute()/2 );</pre><p>We save the painter and then rotate it so that one axis points alongthe hour hand. <pre> pts.<a href="qpointarray.html#76de1d">setPoints</a>( 4, -20,0, 0,-20, 300,0, 0,20 ); paint-><a href="qpainter.html#2efe17">drawPolygon</a>( pts );</pre><p>We set <em>pts</em> to a four-point polygon that looks like the hour hand atthree o'clock, and draw it. Because of the rotation, it's drawnpointed in the right direction. <pre> paint-><a href="qpainter.html#ddb3f4">restore</a>();</pre><p>We restore the saved painter, undoing the rotation. We could alsocall rotate( -30 ) but that might introduce rounding errors, so it'sbetter to use save() and restore(). Next, the minute hand, drawnalmost the same way: <pre> paint-><a href="qpainter.html#938d23">save</a>(); paint-><a href="qpainter.html#b5205c">rotate</a>( (time.minute()-15)*6 ); pts.<a href="qpointarray.html#76de1d">setPoints</a>( 4, -10,0, 0,-10, 400,0, 0,10 ); paint-><a href="qpainter.html#2efe17">drawPolygon</a>( pts ); paint-><a href="qpainter.html#ddb3f4">restore</a>();</pre><p>The only differences are how the rotation angle is computed and theshape of the polygon.<p>The last part to be drawn is the clock face itself. <pre> for ( int i=0; i<12; i++ ) { paint-><a href="qpainter.html#e3a489">drawLine</a>( 440,0, 460,0 ); paint-><a href="qpainter.html#b5205c">rotate</a>( 30 ); }</pre><p>Twelve short hour lines at thirty-degree intervals. At the end ofthat, the painter is rotated in a way which isn't very useful, butwe're done with painting so that doesn't matter. <pre> paint-><a href="qpainter.html#ddb3f4">restore</a>(); }</pre><p>The final line of the function restores the painter, so that thecaller won't be bothered by all the transformations we've done.<p><address><hr><div align="center"><table width="100%" cellspacing="0" border="0"><tr><td>Copyright
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -