QPaniter 的座標系裝換

 聲明:本文原創於yafeilinux的百度博客,http://hi.baidu.com/yafeilinux 轉載請註明出處。

我看了這篇文章很好很容易理解。如果看了Qt助手之後更加的形象。


前面一節我們講解了圖片的顯示,其中很多都用到了座標的變化,這一節我們簡單講一下Qt的座標系統,其實也還是主要講上一節的那幾個函數。這裏我們先講解一下Qt的座標系,然後講解那幾個函數,它們分別是:
translate()函數,進行平移變換;scale()函數,進行比例變換;rotate()函數,進行旋轉變換;shear()函數,進行扭曲變換。
最後介紹兩個有用的函數save()和restore(),利用它們來保存和彈出座標系的狀態,從而實現快速利用幾個變換來繪圖。
一、座標系簡介。
Qt中每一個窗口都有一個座標系,默認的,窗口左上角爲座標原點,然後水平向右依次增大,水平向左依次減小,垂直向下依次增大,垂直向上依次減小。原點即爲(0,0)點,然後以像素爲單位增減。
例如:
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setBrush(Qt::red);
    painter.drawRect(0,0,100,100);
    painter.setBrush(Qt::yellow);
    painter.drawRect(-50,-50,100,100);
}
我們先在原點(0,0)繪製了一個長寬都是100像素的紅色矩形,又在(-50,-50)點繪製了一個同樣大小的黃色矩形。可以看到,我們只能看到黃色矩形的一部分。效果如下圖。
二、座標系變換。
座標系變換是利用變換矩陣來進行的,我們可以利用QTransform類來設置變換矩陣,因爲一般我們不需要進行更改,所以這裏不在涉及。下面我們只是對座標系的平移,縮放,旋轉,扭曲等應用進行介紹。
1.利用translate()函數進行平移變換。
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setBrush(Qt::yellow);
    painter.drawRect(0,0,50,50);
   painter.translate(100,100); //將點(100,100)設爲原點
    painter.setBrush(Qt::red);
    painter.drawRect(0,0,50,50);
   painter.translate(-100,-100);
    painter.drawLine(0,0,20,20);
}
效果如下。
這裏將(100,100)點作爲了原點,所以此時(100,100)就是(0,0)點,以前的(0,0)點就是
(-100,-100)點。要想使原來的(0,0)點重新成爲原點,就是將(-100,-100)設爲原點。
2.利用scale()函數進行比例變換,實現縮放效果。
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setBrush(Qt::yellow);
    painter.drawRect(0,0,100,100);
    painter.scale(2,2); //放大兩倍
    painter.setBrush(Qt::red);
    painter.drawRect(50,50,50,50);
}
效果如下。
可以看到,painter.scale(2,2),是將橫縱座標都擴大了兩倍,現在的(50,50)點就相當於以前的
(100,100)點。
3.利用shear()函數就行扭曲變換。
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setBrush(Qt::yellow);
    painter.drawRect(0,0,50,50);
    painter.shear(0,1); //縱向扭曲變形
    painter.setBrush(Qt::red);
    painter.drawRect(50,0,50,50);
}
效果如下。
這裏,painter.shear(0,1),是對縱向進行扭曲,0表示不扭曲,當將第一個0更改時就會對橫行進行扭曲,關於扭曲變換到底是什麼效果,你觀察一下是很容易發現的。
4.利用rotate()函數進行比例變換,實現縮放效果。
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.drawLine(0,0,100,0);
    painter.rotate(30); //以原點爲中心,順時針旋轉30度
    painter.drawLine(0,0,100,0);
   painter.translate(100,100);
    painter.rotate(30);
    painter.drawLine(0,0,100,0);
}
效果如下。
因爲默認的rotate()函數是以原點爲中心進行順時針旋轉的,所以我們要想使其以其他點爲中心進行旋轉,就要先進行原點的變換。這裏的painter.translate(100,100)將(100,100)設置爲新的原點,想讓直線以其爲中心進行旋轉,可是你已經發現效果並非如此。是什麼原因呢?我們添加一條語句,如下:
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.drawLine(0,0,100,0);
    painter.rotate(30); //以原點爲中心,順時針旋轉30度
    painter.drawLine(0,0,100,0);
   painter.rotate(-30);
    painter.translate(100,100);
    painter.rotate(30);
    painter.drawLine(0,0,100,0);
}
效果如下。
這時就是我們想要的效果了。我們加的一句代碼爲painter.rotate(-30),這是因爲前面已經將座標旋轉了30度,我們需要將其再旋轉回去,才能是以前正常的座標系統。不光這個函數如此,這裏介紹的這幾個函數均如此,所以很容易出錯。下面我們將利用兩個函數來很好的解決這個問題。
三、座標系狀態的保護。
我們可以先利用save()函數來保存座標系現在的狀態,然後進行變換操作,操作完之後,再用restore()函數將以前的座標系狀態恢復,其實就是一個入棧和出棧的操作。
例如:
void Dialog::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.save(); //保存座標系狀態
    painter.translate(100,100);
    painter.drawLine(0,0,50,50);
    painter.restore(); //恢復以前的座標系狀態
    painter.drawLine(0,0,50,50);
}
效果如下。
利用好這兩個函數,可以實現快速的座標系切換,繪製出不同的圖形

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章