Qt 提供了內置的繪圖系統以及獨立的QtOpenGL模塊提供對OpenGL的支持。Qt提供了基於狀態機的QPainter系統和麪向對象的Graphics View系統。css
基於狀態機的繪圖系統主要包含QPainter、QPaintEngine、QPaintDevice 三個類。算法
QPainter有三個主要參數分別用於設置畫筆(QPen)、畫刷(QBrush)、字體(font),分別由setPen、setBrush、setFont系列方法設定。架構
widget.h:框架
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QPainter> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); void paintEvent(QPaintEvent *event = 0); ~Widget(); private: Ui::Widget *ui; }; #endif // WIDGET_H
widget.cpp:ide
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } void Widget::paintEvent(QPaintEvent *parent) { // QPainter *painter = new QPainter(this); QPainter painter(this); painter.setPen(Qt::blue); painter. setFont(QFont("Arial", 30)); painter. drawLine(0,0,100,100); }
main.cpp:函數
#include "widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); w.paintEvent(); return a.exec(); }
使用QPainter進行繪畫必須重寫QWidget::paintEvent(QPaintEvent *)
事件,並在事件中進行繪圖。如Widget.cpp中的void Widget::paintEvent(QPaintEvent *parent)
。工具
調用可視化組件的update(),repaint()實例方法或者直接調用paintEvent()方法能夠對可視化組件進行重繪。字體
update()容許Qt進行優化從而獲得比調用repaint()更快的速度和更少的閃爍。優化
幾回調用update()的結果一般僅僅是一次paintEvent()調用,repaint()則是當即調用paintEvent()動畫
Qt一般在paintEvent()調用以前擦除這個窗口部件的區域,除非設置了WRepaintNoErase窗口部件標記。
畫筆QPen主要用於線條的繪製,畫筆的樣式能夠在建立QPen對象時指定也可由setStyle()指定。
畫筆主要支持cap、join (結合點)和line三種風格,能夠經過setStyle()、setCapStyle()、setJoinStyle()、setlineStyle()等方法進行設置。
畫刷QBrush用於二維封閉圖形的填充,與QPen相似一樣經過style設定填充風格,還可使用漸變填充。
反走樣技術經過對像素的細微調整避免鋸齒狀邊緣出現,可是反走樣算法須要較高計算量且會修改原有圖形,因此與大多數2D繪圖工具同樣QPainter默認不打開反走樣算法。
painter.setRenderHint(QPainter::Antialiasing,true);
使用上述語句將QPainter::Antialiasing設置爲true以後painter就會打開反走樣算法,直到將QPainter::Antialiasing顯式地設爲false反走樣算法纔會關閉。
Qt 的漸變是一個獨立的類,包含QLinearGradient(線性漸變),QRadialGrafient(輻射漸變),QConcialGradient(角度漸變)。
示例:
void Widget::paintEvent(QPaintEvent *parent) { QPainter painter(this); QLinearGradient gradient(0,0,100,100); //初始化漸變對象,左上座標和寬高設定位置 gradient.setColorAt(0.2,Qt::blue); //設定漸變色彩,第一個參數爲參照點的位置比例,第二個參數爲參照點的顏色 gradient.setColorAt(0.5,Qt::red); gradient.setColorAt(0.8,Qt::yellow); painter. setBrush(QBrush(gradient)); //QBrush接受漸變對象作參數,並將其做爲QPainter的繪製工具 painter. drawEllipse(0,0,100,100); //畫圖 }
QPainter的座標位於左上角,x軸正方向向右,y軸正方向向下;每一個像素佔據
1×1的座標空間,但像素中心爲與方格中心(x+0.5,y+0.5),其實是一個半像素座標系。
QPainter使用了viewport和window機制,viewport使用物理座標而window使用邏輯座標、QPainter傳遞邏輯座標。二者的座標系一般是相同的,可是QPainter還提供了setViewport()和setWindow()函數用於重置兩個座標系的位置大小,使得能夠在不改變物理實現的狀況下移動畫布的範圍。
QPainter還提供了世界座標用於座標的變換:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QFont font("Courier",12);//初始化字體對象 painter.setFont(font);//爲QPainter設置字體 QTransform transform;//定義座標變換 transform.rotate(+45);//設置旋轉 painter.setWorldTransform(transform);//爲QPainter設置座標變換 painter.drawText(150,0,"Hello World!");//繪製 }
QTransform是對座標變換矩陣的封裝,一般使用:旋轉rotate,放縮scale,裁剪shear,平移translate等方法設定相關變換。一個QTransform對象能夠依次設置多個座標變換操做。
Qtransform也可使用setmatrix()等方法直接操做變換矩陣。
繪圖設備是指QPaintDevice的派生類,包括QPixmap、QBitmap、QImage和QPicture。QPainter提供了drawPixmap()方法能夠將圖像畫到不一樣設備上。
QPixmap爲圖片在屏幕顯示作了優化,QPixmap與繪圖設備底層相關,不提供像素級支持,不一樣設備上圖像有所不一樣。
能夠直接使用QPainter在QPixmap上繪製也能夠接受一個圖片文件在屏幕上顯示。
QBitmap是QPixmap的派生類,只能繪製黑白圖像(色深爲1)。
QImage是與硬件無關的繪圖設備,提供了像素級操做支持。
QPicture用於記錄QPainter的操做,並保存到一個序列化的平臺獨立的二進制文件中。
示例:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPicture picture; painter.begin(&picture); //開始記錄 painter.drawText(100,100,"Hello World!");//繪製 painter.end();//終止記錄 picture.save("Hello.pic");//保存到文件 picture.load("Hello.pic");//加載文件 painter.drawPicture(0,0,picture);//重畫 }
Graphics View是一種採用MV架構,面向對象的繪圖系統。與QPainter狀態機使用繪圖語句繪製的模式不一樣,Gaphics View中每一個圖形元素都是一個對象。
Graphics View的架構中Model負責存儲對象結構View則提供觀察窗口,MV架構能夠很容易的實現轉換視角,攝像機,碰撞檢測等功能。
Grphics View框架採用BSP樹管理item,能夠對大量items作出快速響應。
示例:
QGraphicsScene scene; scene.addText("Hello, world!"); QGraphicsView view(&scene); view.show();
QGraphicsScene類做爲容器(MV中的模型Model),用於存儲全部的圖形元素;QGraphicsView則是觀察窗口,能夠顯示場景的一部分或者全局;全部的圖形元素均繼承自QGraphicsItem。
QGraphicsScene的addItem(QGraphicsItem * item);
方法能夠向容器中添加圖形元素。
addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(), addRect(), or addText()能夠方便地添加圖形元素並返回指向圖形元素的指針。QGraphicsScene::removeItem(QGraphicsItem * item)
用於移除相應的Item。
QGraphicsScene使用下標來高效的管理item的位置,默認的使用BSP樹,適用於一個大型的場景,其中的item都是靜止不變的,能夠選擇調用setItemIndexMethod().來禁用下標,能夠查看itemIndexMethod來獲取更多的信息。
items()函數能夠在數微秒內找到item的位置,item()有一些重載函數。itemAt()函數能夠根據提供的位置返回所在位置處的最上層的item指針。
場景的邊界可使用setSceneRect()來設置,item能夠放置在場景中任何位置,場景默認的大小是不受限制的。若是場景邊界矩形沒有設置,QgrapbhicsScene將會使用全部item圖元的邊界,使用函數itemsBoundingRect()返回。
經過繼承QGraphicsScene並重寫事件響應函數能夠對Scene中的Item的點擊、拖動等事件進行響應。在場景變換時,QGraphicsScene將會發射changed()信號,通知相應槽函數進行處理。
QGraphicsView提供了用於顯示的widget,用於顯示Scene,可使用構造函數或void setScene(QGraphicsScene * scene)
將多個View聯繫到同一個scene,給相同的數據提供多個View,視口支持openGL,甚至能夠將QGLWidget做爲視口,只要調用一下QGraphicsView::setViewport()
。
QGraphicsView::mapToScene()
, QGraphicsView::mapFromScene()
等多個函數能夠在view和scene之間轉換座標系。
QGraphicsView是一個觀察窗口,它將QGraphicsScene中item顯示出來,並將用戶的鼠標和鍵盤事件映射到QGraphicsScene事件,且將座標轉換爲QGraphicsScene的座標。
setScence
QGraphicsView的構造函數能夠接受一個QGraphicsScene的指針做爲參數或者使用void QGraphicsView::setScene ( QGraphicsScene * scene )
。
transform()
QGraphicsView::setTransform()
使用轉換矩陣來改變視圖座標系,達到旋轉或縮放的目的。並經過QGraphicsView::transform()
訪問QTransform。
示例:
QTransform transform;//定義座標變換 transform.rotate(+45);//設置旋轉 view.setTransform(transform); view.show()
固然能夠用void QGraphicsView::rotate(qreal angle)
或者void QGraphicsView::scale(qreal sx, qreal sy)
示例:
QGraphicsScene scene; scene.addText("GraphicsView rotated clockwise"); QGraphicsView view(&scene); view.rotate(90); // the text is rendered with a 90 degree clockwise rotation view.show();
QGraphicsView使用ViewportAnchor屬性來決定當轉換矩陣修改和座標系統修改時候如何擺放場景的在viewport中的位置。
默認的是 AnchorViewCenter,這樣使場景點在變換時候保持在view中心點不變。例如當旋轉時候,場景將會圍繞着view中心點來旋轉。
只有場景中的一部分可見時候這個屬性才顯而易見的。例如:當view中有滾動條時候,不然整個場景都在view中,場景將會使用QGraphicsView::aligenment來擺放它的位置。
void QGraphicsView::render ( QPainter * painter)
將QGraphicsView經過QPainter映射到QPaintDevice上顯示。
來自官方文檔的示例:
QGraphicsScene scene; scene.addItem(... ... QGraphicsView view(&scene); view.show(); ... QPrinter printer(QPrinter::HighResolution); printer.setPageSize(QPrinter::A4); QPainter painter(&printer); // print, fitting the viewport contents into a full page view.render(&painter); // print the upper half of the viewport into the lower. // half of the page. QRect viewport = view.viewport()->rect(); view.render(&painter, QRectF(0, printer.height() / 2, printer.width(), printer.height() / 2), viewport.adjusted(0, 0, 0, -viewport.height() / 2));
QGraphicsItem是全部item的基類,要自定義item須要繼承QGraphicsItem並實現兩個純虛函數:
返回一個表明形狀QRectF對象。
控制繪圖過程。
QGraphicsScene認爲全部item的boundingRect函數與shape函數都是不發生改變的,除非用戶進行通知。若是想改變一個item,必需先調用prepareGeometryChange
以容許QGraphicsScene進行更新。
Graphics View框架使用shape()
與collidesWithPath()
實現碰撞檢測。
QPainterPath QGraphicsItem::shape() const
函數返回碰撞箱形狀,默認實現爲調用boundingRect()
並返回簡單的矩形。
重寫該函數,定義更復雜的碰撞箱形狀,但複雜的形狀會使計算量增大。
默認實現:
QPainterPath RoundItem::shape() const { QPainterPath path; path.addEllipse(boundingRect()); return path; }
bool QGraphicsItem::collidesWithPath(const QPainterPath & path)
當item與參數指定的PainterPath發生碰撞時返回true,不然爲false。
碰撞箱形狀決定於shape(),可使用shape()函數進行兩個item的碰撞檢測:
item1.collidesWithPath(item2.shape());
Qt提供了默認實現,能夠重寫該方法實現更復雜的碰撞檢測。
示例:
QPushButton button("Animated Button"); button.show(); QPropertyAnimation animation(&button, "geometry"); //初始化Animation對象,指定要動畫的屬性 animation.setDuration(10000); //設定持續時間,單位爲毫秒 animation.setStartValue(QRect(0, 0, 0, 0)); //設定初始值 animation1->setKeyValueAt(0.4, QRect(20, 250, 20, 30)); //設定中間關鍵值,第一個參數爲時間百分比,第二個參數爲關鍵值 animation.setEndValue(QRect(250, 250, 100, 30)); //設定結束值 animation.start(); //啓動動畫
QPropertyAnimation是Qt動畫框架提供的一個實現類,它按照設置對某個Qt屬性進行線性插值,並在時間軸的控制下動態調節該屬性達到動畫的效果。
QPropertyAnimation動畫的屬性必須是Qt屬性,Qt屬性由Q_PROPERTY宏來聲明,而且類必須繼承QObject。標準的Qt Widgets組件均使用Q_PROPERTY屬性,能夠直接進行動畫,若自定義組件使用動畫效果則須要使用Q_PROPERTY進行聲明。
Q_PROPERTY宏的原型爲:
Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER memberName [(READ getFunction | WRITE setFunction)]) [RESET resetFunction] [NOTIFY notifySignal] [REVISION int] [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool] [USER bool] [CONSTANT] [FINAL])
屬性類型必須有一個read函數。它用來讀取屬性值。所以用Const限定。它的返回值類型必須爲屬性類型或者屬性類型的引用或者指針。不能是其餘類型例如:QWidget::hasFocus()。
有一個可選的write函數。它用來設置屬性值,它的返回值必須爲void型,而起必需要含有一個參數。例如:QWidget::setEnabled()。
一個reset函數可以把property設置成其默認狀態,它也是可選的。復位功能必須返回void,而且不帶參數。
一個可選的NOTIFY信號, 它提供了一個在值發生改變時會自動被觸發信號。
若是定義了"STODE"屬性代表這是一直存在的。
一個"DESIGNABLE"屬性代表該property能在GUI builder(通常爲Qt Designer)可見。
USER 屬性 表面是否能夠被用戶所編輯
CONST設定屬性是不可修改的 因此不能跟WRITE或者NOTIFY同時出現
FINAL代表該屬性不會被派生類中重寫
示例:
class Test : public QObject { Q_OBJECT Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) public: Test(QObject *parent = 0) : QObject(parent) {} virtual ~Test(){} void setEnabled(bool e) { enabled = e; } bool isEnabled() const { return enabled; } private: bool enabled; };
QPropertyAnimation默認進行線性插值,也可使用寬鬆曲線(EasyCurvig)設置屬性變化規律,如產生組件彈跳進入的效果等。
QPushButton button("Animated Button"); button.show(); QPropertyAnimation animation(&button, "geometry"); //初始化Animation對象,指定要動畫的屬性 animation.setDuration(10000); //設定持續時間,單位爲毫秒 animation.setStartValue(QRect(0, 0, 0, 0)); //設定初始值 animation1->setKeyValueAt(0.4, QRect(20, 250, 20, 30)); //設定中間關鍵值,第一個參數爲時間百分比,第二個參數爲關鍵值 animation.setEndValue(QRect(250, 250, 100, 30)); //設定結束值 animation1->setEasingCurve(QEasingCurve::OutBounce); //使用彈跳曲線 animation.start(); //啓動動畫
QEasyCurving::Type
枚舉類型中定義了各類曲線,能夠從中選擇或者自行實現而後註冊到EasyCurving。
Qt的 動畫效果離不開時間軸的控制,Animation框架依賴QTimeLine提供時間軸。咱們可使用QTimeLine製做本身的動畫。
QTimeLine接受一個以毫秒爲單位的參數,表明動畫運行的總時間。
例:timeline = new QTimeLine(1000);
在計時結束後將會發出finished()
信號,或者調用stop()方法手動使QTimeLine進入NotRunning狀態。
調用start方法,QTimeLine開始計時:timeLine->start();
QTimeLine進入Running狀態後,默認每隔40ms發送一個frameChanged()
信號,間隔規律能夠手動設置:setUpdateInterval(int interval);
默認狀況下QTimeLine均勻的發送信號,也能夠手動設置間隔規律:timeline->setCurveShape(QTimeLine::LinearCurve);
目前,Qt支持的模式有:
The value starts growing slowly, then increases in speed.先慢後快
The value starts growing steadily, then ends slowly.先勻加速,後減速
The value starts growing slowly, then runs steadily, then grows slowly again.
先慢,中間穩定,最後慢
The value grows linearly (e.g., if the duration is 1000 ms, the value at time 500 ms is 0.5).勻速的
The value grows sinusoidally.正選曲線式
The value grows cosinusoidally.餘弦曲線式