一 基礎知識
圖形視圖框架是基於笛卡爾坐標系統的,一個圖形項在場景中的位置和幾何形狀由x坐標和y坐標來表示。當使用一個沒有變換的視圖來觀察場景時,場景中的一個單元代表屏幕上的一個像素。圖形視圖框架的三個坐標系分別是視圖坐標系、場景坐標系和圖元坐標系。三個坐標系分別由視圖、場景和圖元使用。為了方便應用,圖形視圖框架中提供了一些便捷函數來完成3個坐標系統之間的映射。當進行繪圖時,場景坐標對應QPainter的邏輯坐標,視圖坐標對應設備坐標。
比如在給場景中添加圖元時,圖元的位置就是相對於場景坐標系而言的:
1.1 場景坐標系
場景坐標系是所有圖元對象的絕對坐標. 有四個象限,場景坐標是所有圖形項的基礎坐標系統。場景坐標系統描述了每一個頂層圖形項的位置,也形成了所有從視圖傳到場景上的事件的基礎。場景坐標的原點在場景的中心,x軸正方向向右,y軸正方向向下。
每一個在場景中的圖形項除了擁有一個圖形項的本地坐標和邊界矩形外,還都擁有一個場景坐標(QGraphicsItem: :scenePos())和一個場景中的邊界矩形(QGraphicsItem::sceneBoundingRect())。場景坐標用來描述圖形項在場景坐標系統中的位置,而圖形項的場景邊界矩形用於QGraphicsScene判斷場景中的哪些區域進行了更改。
常用添加圖元函數:
QGraphicsScene::setBackgroundBrush //填充背景色
QGraphicsScene::setForegroundBrush //填充前景色
QGraphicsScene::addSimpleText //添加簡單文本
QGraphicsScene::addLine //添加直線
QGraphicsScene::addRect //添加矩形
QGraphicsScene::addEllipse //添加橢圓
QGraphicsScene::addWidget //添加窗口
QGraphicsScene::addPixmap //添加圖片
操作圖元函數:
QGraphicsScene::itemAt //查找場景某個中最表層的item
QGraphicsScene::setSelectionArea //設置選定區域
QGraphicsScene::setSceneRect //設置場景的區域大小
QGraphicsScene::itemsBoundingRect //根據所有的item計算區域大小
QGraphicsScene:: selectedItems //獲取被選中的item,item必須為可選QGraphicsItem::ItemIsSelectable
QGraphicsScene類的坐標系以中心為原點(0,0),如下圖所示。
1.2 視圖坐標
視圖的坐標就是窗口部件的坐標。視圖坐標的每一個單位對應一個像素。QGraphicsView視圖的左上角是(0,0),x軸正方向向右,y軸正方向向下。
所有的鼠標事件最開始都是使用視圖坐標。 QGraphicsView類繼承自QWidget類,因此它與其他的QWidget類一樣,以窗口的左上角作為自己坐標系的原點,如圖所示。
1.3 圖形項坐標
圖形項使用自己的本地坐標,這個坐標系統通常以圖形項中心為原點,這也是所有變換的原點。圖形項坐標方向是x軸正方向向右,y軸正方向向下。創建圖形項后,只需注意圖形項坐標就可以了,QGraphicsScene和QGraphicsView會完成所有的變換。
一個item的位置是item坐標系下的中心點在其父對象坐標系下的位置,有時也被稱為父坐標。對於所有沒有父對象的對象來說,場景就是其父對象。因此最頂層items的位置就是其在scene中的位置。
子對象坐標系是相對於父對象坐標系來說的一個概念。如果子節點沒有進行矩陣變換,那么在子對象坐標系和父對象坐標系的差異就和這些對象在父對象中的偏移一樣。比如:如果一個未經變換的子對象精確的位於父對象的中心點,那么這兩個對象的坐標系就是完全一致的。如果子對象的位置是(10, 0),那么子對象的(0, 10)點就位於父對象的(10, 10)點的位置。
由於items的位置和轉換是相對於父對象來說的,因此雖然父對象的變換隱式地變換了子對象,子對象的坐標系不會因父對象坐標系改變而改變。在上面的例子中,即使父對象經過了旋轉和縮放,子對象的(0, 10)點依然相對於父對象是(10, 10)點。不過相對於scene來說,子對象將隨着父對象進行變換和偏移 。如果父對象縮放了(2x, 2x),那么子對象在場景坐標系下將會位於(20, 0)的位置,同時其(10, 0) 點將會對應於場景中的(40, 0)點。
不管item或父對象進行了什么樣的變化, QGraphicsItem的函數一般總是表示在item坐標系下的位置,其操作也作用於item坐標系內。比如:一個對象的矩形邊界(QGraphicsItem::boundingRect())總是在item坐標系下給出的。但是QGraphicsItem::pos()是例外之一,該函數表示其在父對象中的位置 。
QGraphicsItem::rect //不帶邊框的圖形區域
QGraphicsItem::boundingRect //帶邊框的圖形區域
QGraphicsItem::collidesWithItem //碰撞檢測
QGraphicsItem::setScale //縮放
QGraphicsItem::setRotation //旋轉
QGraphicsItem::setZValue //設置z坐標,圖元的疊加先后順序可以用它來設置
QGraphicsItem::setPos //設置位置坐標
設置item的屬性:
void QGraphicsItem::setFlags(GraphicsItemFlags flags);
/*
*參數GraphicsItemFlags flags 為枚舉類型,可以以下值
* QGraphicsItem::ItemIsMovable 是否可以移動
* QGraphicsItem::ItemIsSelectable 是否可以被選中
* QGraphicsItem::ItemIsFocusable 是否可以設置為焦點item
*/
QGraphicsItem類的坐標系,若在調用QGraphicsItem類的paint()函數重繪圖元時,則以此坐標系為基准,如下圖所示。
二 、 坐標映射轉換
當處理場景中的圖形項時,將坐標或者一個任意的形狀從場景映射到圖形項、或者從一個圖形項映射到另一個圖形項、或者從視圖映射到場景,這些坐標變換都是非常有用的。例如:
- 當在QGraphicsView的視口上單擊了鼠標,便可以調用QGraphicsView::mapToScene()以及 QGraphicsScene::itemAt()來獲取光標下的圖形項;
- 如果要獲取一個圖形項在視口中的位置,那么可以先在圖形項上調用QGraphicsItem::mapToScene(),然后在視圖上調用QGraphicsView: :mapFromScene();如果要獲取在視圖的一個橢圓形中包含的圖形項,可以先傳遞一個QPainterPath對象作為參數給mapToScene()函數,然后傳遞映射后的路徑給QGraphicsScene::items()函數。
不僅可以在視圖、場景和圖形項之間使用坐標映射,還可以在子圖形項和父圖形項或者圖形項和圖形項之間進行坐標映射 。圖形視圖框架提供的所有映射函數如下表所列,所有的映射函數都可以映射點、矩形、多邊形和路徑。
映 射 函 數 | 轉 換 類 型 |
---|---|
QGraphicsView::mapToScene() | 視圖到場景 |
QGraphicsView::mapFromScene() | 場景到視圖 |
QGraphicsItem:: mapFromScene() | 場景到圖形項 |
QGraphicsItem:: mapToScene() | 圖形項到場景 |
QGraphicsItem:: mapToParent() | 子圖形項到父圖形項 |
QGraphicsItem:: mapFromParent() | 父圖形項到子圖形項 |
QGraphicsItem:: mapToItem() | 本圖形項到其他圖形項 |
QGraphicsItem:: mapFromItem() | 其他圖形項到本圖形項 |
調整坐標系的的類是QTransform、QMatrix,這兩個類都提供了縮放、旋轉、變形坐標系的方法。
2.1 調整QGraphicsVeiw坐標系
#include <QApplication> #include <QGraphicsView> #include <QGraphicsRectItem> #include <QLabel> #include <QTransform> int main(int argc, char** argv) { QApplication app(argc, argv); QGraphicsView view; QGraphicsScene scene; view.setScene(&scene); view.show(); view.resize(400, 400); QTransform transform; //transform.translate(100, 0); //移動坐標原點 transform.scale(1.5, 1); //縮放 //transform.rotate(10); //旋轉 // transform.shear(0.1, 0.1); //變形 view.setTransform(transform); /*添加矩形*/ scene.addRect(0, 100, 100, 100, QPen(Qt::yellow), QBrush(Qt::blue)); return app.exec(); }
2.2 調整QGraphicsItem坐標系
#include <QApplication> #include <QGraphicsView> #include <QTransform> #include <QGraphicsRectItem> int main(int argc, char** argv) { QApplication app(argc, argv); QGraphicsView view; QGraphicsScene scene; view.setScene(&scene); view.show(); view.resize(400, 400); QTransform transform; //transform.translate(100, 0); //移動坐標原點 transform.scale(1.5, 1); //縮放 //transform.rotate(10); //旋轉 // transform.shear(0.1, 0.1); //變形 /*添加矩形*/ QGraphicsRectItem *rect = scene.addRect(0, 100, 100, 100 , QPen(Qt::yellow), QBrush(Qt::blue)); rect->setTransform(transform); return app.exec(); }