最近在研究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
這里借用一張圖說明一下:
世界坐標通過矩陣轉換成窗口坐標,然后通過窗口到視口的映射轉換成設備坐標。
我這里的說明省略了矩陣變換,其實從邏輯坐標到窗口坐標之間還要進行矩陣變換。