最近在研究Qt的2D绘图部分,对窗口和视口比较感兴趣,故写几个测试程序来加深理解。
PaintDemo.h
#ifndef PAINTDEMO_H #define PAINTDEMO_H #include <QWidget> class QPaintEvent; class PaintDemo : public QWidget { public: PaintDemo(); protected: void paintEvent(QPaintEvent *event); }; #endif
PaintDemo.cpp
#include <QPainter> #include "PaintDemo.h" PaintDemo::PaintDemo() { resize(800, 600); setWindowTitle(tr("Paint Demo")); } void PaintDemo::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setPen(QPen(Qt::black, 2)); painter.drawLine(0,0,800,600); }
在构造函数中将窗口大小设置为800x600,在paintEvent中从(0,0)到(800,600)绘制了一条Line,斜贯整个窗口:
此时,我们拉动改变窗口的大小,显然,窗口右下角的坐标不再是(800,600),而且其它更大的一个数值,譬如(900,700),而我们的线只画到(800,600),所以剩下的一段是空白。如下图所示:
OK,我们来修改一下代码,在绘制Line前加上一行
painter.setWindow(0,0,800,600);
修改后的PaintDemo.cpp代码如下(红色为增加的代码):
#include <QPainter> #include "PaintDemo.h" PaintedDemo::PaintedDemo() { resize(800, 600); setWindowTitle(tr("Paint Demo")); } void PaintDemo::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setWindow(0,0,800,600); painter.setPen(QPen(Qt::black, 2)); painter.drawLine(0,0,800,600); }
编译运行:
这个时候我们发现不管怎样拉动窗口,Line永远贯穿整个窗口:
这说明painter.setWindow(0,0,800,600)将整个窗口设置为一个区域,左上角为原点,X坐标的终点为800,即窗口的宽度,Y坐标的终点为600,即窗口高度,这样,不管窗口怎么变化,右下角的坐标始终为(800,600),因此我们的Line始终贯穿整个窗口。
OK,我们再接再厉,将ViewPort也设置一下,PaintDemo.cpp代码如下(红色为增加的代码):
#include <QPainter> #include "PaintDemo.h" PaintDemo::PaintDemo() { resize(800, 600); setWindowTitle(tr("Paint Demo")); } void PaintDemo::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setViewport(0,0,800,600); painter.setWindow(0,0,800,600); painter.setPen(QPen(Qt::black, 2)); painter.drawLine(0,0,800,600); }
编译运行,这时我们会惊奇的发现,Line又不能贯穿整个窗口了
再来,我们将Viewport改小一点,宽度由800改为300,高度由600改为400,结果如何?看图:
现在可以得到结论了,Qt通过QPainter::setWindow将窗口坐标映射到视口坐标,而QPainter::setViewport则用来指定在窗体上所能绘制的区域。
关于Qt的坐标系统其实在Qt的doc里已经讲得很详细了,具体请参看:
http://qt-project.org/doc/qt-4.8/coordsys.html#window-viewport-conversion
这里借用一张图说明一下:
世界坐标通过矩阵转换成窗口坐标,然后通过窗口到视口的映射转换成设备坐标。
我这里的说明省略了矩阵变换,其实从逻辑坐标到窗口坐标之间还要进行矩阵变换。