一、QT繪圖原理
Qt4中的2D繪圖系統稱為Arthur繪圖系統,可以使用相同的API在屏幕上和繪圖設備上進行繪製,主要基於QPainter、QPainterDevice和 QPainterEngine。QPainter執行繪圖操作,QPainterDevice提供繪圖設備,是一個二維空間的抽象,QPainterEngine提供一些接口。QPainter用來執行具體的繪圖相關操作,如畫點,畫線,填充,變換,alpha通道等。QPaintDevice類是能夠進行繪圖的對象的基類,QWidget,QPixmap,QPicture,QImage,以及QPrinter類繼承了QPaintEngine類的繪圖能力,QPainter類可以在一切繼承QPainterDevice的子類上進行繪製操作。
QT中Arthur繪圖框架中的基本繪圖元素是畫筆,畫刷。
QPainter類具有GUI程序需要的絕大多數函數,能夠繪製基本圖形(點,線,矩形,多邊形等)以及複雜的圖形(如繪圖路徑)。使用繪圖路徑(QPaintPath)的優點是複雜形狀的圖形只用生成一次,再使用的時候只需要調用QPainter::drawPath()就可以繪製。QPainterPath對象可以用來填充,繪製輪廓。
線和輪廓都可以用畫筆(QPen)進行繪製,畫刷(QBrush)進行填充。畫筆定義風格(線形),寬度,筆尖畫刷以及端點是如何繪製的(cap-style),端點的連接方式(join-style)。畫刷用來填充畫筆繪製的圖形,可以定製不同的填充模式和顏色的畫刷。
當繪製文字時,字體使用QFont類定義,Qt使用指定字體的屬性,如果沒有匹配的字體,Qt將使用最接近的字體。字體屬性可以通過QFontInfo來獲取。字體的度量(measurement)使用QFontMetrics類來獲取。QFontDatabase類可以獲得底層窗口系統所有可用的字體。
通常情況下QPainter以默認的座標系統進行繪製,也可以用QMatrix類對座標進行變換。
當繪製時,可以使用QPainter::SetRenderHint函數設置繪圖引擎是否啟用反鋸齒功能使圖變得平滑。
QPainter::Antialiasing儘可能進行邊的反鋸齒繪製
QPainter::TextAntialiasing 儘可能進行文字的反鋸齒繪製
QPainter::SmoothPixmapTransform 使用平滑的pixmap變換算法(雙線性插值算法),而不是近鄰插值算法
1、重寫重繪事件處理函數實現繪圖
重繪事件處理函數:
void QWidget::paintEvent ( QPaintEvent * event )
基礎部件類Qwidget提供的paintEvent函數,是純虛函數;Qwidget的子類要使用paintEvent函數必須重新實現。在三種情況會發生重繪事件調用paintEvent函數:
A、當窗口部件第一次顯示時,系統會自動產生一個繪圖事件
B、repaint()與update()函數被調用時
C、當窗口部件被其他部件遮擋,然後又再次顯示出來時,就會對隱藏的區域產生一個重繪事件
D、重新調整窗口大小時
2、通過事件過濾器實現重繪
二、繪圖工具
繪圖時需要先定義一個QPainter類對象,繪圖工具可以使Qpen(畫筆)和QBrush(畫刷)。Qpen(畫筆)來繪製輪廓線,QBrush(畫刷)用來填充,使用QPen寫文本時還可以指定字體(QFont類)。
1、QPen畫筆
畫筆的屬性包括線型,線寬,顏色等。
A、QPen主要成員函數如下:
QPen(Qt::PenStyle style)
QPen(const QColor & color)
QPen(const QBrush & brush, qreal width, Qt::PenStyle style = Qt::SolidLine, Qt::PenCapStyle cap = Qt::SquareCap, Qt::PenJoinStyle join = Qt::BevelJoin)
QPen(const QPen & pen)
void setBrush(const QBrush & brush)
void setCapStyle (Qt::PenCapStyle style)
void setColor (const QColor & color)
void setJoinStyle (Qt::PenJoinStyle style)
void setWidth (int width)
畫筆的屬性可以在構造函數中指定,也可以使用setStyle(),setWidth(),setBrush(),setCapStyle(),setJoinStyle()等函數設定畫筆的各項屬性。Qt中使用Qt::PenStyle定義了6種畫筆風格,分別是Qt::SolidLine,Qt::DashLine,Qt::DotLine,Qt::DashDotLine,Qt::DashDotDotLine,Qt::CustomDashLine。自定義線風格(Qt::CustomDashLine),需要使用QPen的setDashPattern()函數來設定自定義風格。
畫筆的設置代碼如下:
QPainter painter(this);
QPen pen(Qt::green, 3, Qt::DashDotLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);
等價於如下代碼:
QPainter painter(this);
QPen pen; // creates a default pen
pen.setStyle(Qt::DashDotLine);
pen.setWidth(3);
pen.setBrush(Qt::green);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
painter.setPen(pen);
B、畫筆風格
畫筆風格使用Qt::PenStyle枚舉定義。
C、畫筆的端點風格( Qt::PenCapStyle)
畫筆端點風格決定了線的端點樣式,只對線寬大於1的線有效。Qt使用枚舉定義了三種端點風格,分別為Qt::SqureCap,QT::FlatCap,Qt::RoundCap。
D、畫筆連接風格(Qt::PenJoinStyle)
畫筆連接風格是兩條線如何連接,連接風格對線寬大於等於1的線有效。Qt使用枚舉定義了四種連接類型,分別是Qt::MiterJoin,Qt::BevelJoin,Qt::RoundJoin,Qt::SvgMiterJoin。
2、QBrush畫刷
在Qt中圖形使用QBrush進行填充,畫刷包括填充顏色和填充模式(風格)。
A、QBrush主要成員函數
QBrush(Qt::BrushStyle style)
QBrush(const QColor& color,Qt::BrushStyle style = Qt::SolidPattern)
QBrush(Qt::GlobalColor color,Qt::BrushStyle style = Qt::SolidPattern)
QBrush(const QColor & color, const QPixmap & pixmap)
QBrush(Qt::GlobalColor color, const QPixmap & pixmap)
QBrush(const QPixmap & pixmap)
QBrush(const QImage & image)
QBrush(const QBrush & other)
QBrush(const QGradient & gradient)
const QColor &color() const
const QGradient *gradient() const
const QMatrix &matrix() const
void setColor(const QColor & color)
void setColor(Qt::GlobalColor color)
void setMatrix(const QMatrix & matrix)
void setStyle(Qt::BrushStyle style)
void setTexture(const QPixmap & pixmap)
void setTextureImage(const QImage & image)
void setTransform(const QTransform & matrix)
Qt::BrushStyle style() const
QPixmap texture() const
QImage textureImage() const
QTransform transform() const
B、填充顏色
在Qt中,顏色使用QColor類表示,QColor支持RGB,HSV,CMYK顏色模型。QColor還支持alpha混合的輪廓和填充。RGB是面向硬件的模型,顏色由紅綠藍三種基色混合而成;HSV模型比較符合人對顏色的感覺,由色調(0-359),飽和度(0-255),亮度(0-255)組成;CMYK由青,洋紅,黃,黑四種基色組成,主要用於打印機等硬件拷貝設備上,每個顏色分量的取值是0-255。
C、填充模式
填充模式通過枚舉類型Qt::BrushStyle來實現,默認值是Qt::NoBrush,不進行任何填充;填充模式包括基本填充模式,漸變填充,和紋理填充模式。不同的填充模式顯示效果如下:
Qt4中,QBrush提供了三種漸變填充:線性(QLinearGradient),圓形(QRadialGradient)和圓錐漸變(QConicalGradient),所有的類都從QGradient類繼承。
線性漸變填充
線性漸變填充指定兩個控制點,畫刷在兩個控制點之間進行顏色插值。通過創建QLinearGradient對象來設置畫刷。
QLinearGradient linearGradient(0,0,200,100);
linearGradient.setColorAt(0,Qt::red);
linearGradient.setColorAt(0.5,Qt::green);
linearGradient.setColorAt(1,Qt::blue);
painter.setBrush(linearGradient);
painter.drawRect(0,0,200,100);
在QGradient構造函數中指定線行填充的兩點分別為(0,0),(100,100)。 setColorAt()函數在0-1之間設置指定位置的顏色。
圓形漸變填充
圓形漸變填充需要指定圓心,半徑和焦點。畫刷在焦點和圓上的所有點之間進行顏色插值,通過創建QRadialGradient對象設置畫刷。
QRadialGradient radialGradient(50,50,50,30,30);
radialGradient.setColorAt(0.2,Qt::cyan);
radialGradient.setColorAt(0.8,Qt::yellow);
radialGradient.setColorAt(1,Qt::magenta);
painter.setBrush(radialGradient);
painter.drawEllipse(0,0,100,100);
圓錐漸變填充
圓錐漸變填充指定圓心和開始角,畫刷沿圓心逆時針對顏色進行插值,通過創建QConicalGradient對象並設置畫刷。
QConicalGradient conicalGradient(60,40,30);
conicalGradient.setColorAt(0,Qt::gray);
conicalGradient.setColorAt(0.4,Qt::darkGreen);
conicalGradient.setColorAt(0.6,Qt::darkMagenta);
conicalGradient.setColorAt(1,Qt::drakBlue);
painter.setBrush(conicalGradient);
painter.drawEllipse(0,0,100,100);
其他填充模式
其他填充模式通過setStyle(Qt::BrushStyle style)函數進行設置。
如果實現自定義填充,可以使用QPixmap或者QImage對象進行紋理填充。兩種圖像分別使用setTexture()和setTextureImage()函數加載紋理。
D、alpha通道
在windows,Mac OSX和有XRender擴展的X11系統上,Qt4能夠支持Alpha通道,通過使用Alpha通道,可以實現半透明效果,QColor類中定義了Alpha通道的透明度,0表示完全透明,255表示完全不透明。QWidget類有一個屬性windowOpacity,通過setWindowOpacity(qreal level)可以設置窗口的透明度。但該屬性和Alpha通道的原理並不相同,Qt4在Windows和Mac OS X平臺上才支持該屬性,但在X11平臺上卻需要Composite擴展才能工作。(alpha通道使用的是X11的xRender擴展)。
3、雙緩衝繪圖
在Qt4中,所有的窗口部件默認都使用雙緩衝進行繪圖。使用雙緩衝,可以減輕繪製的閃爍感。在有些情況下,用戶要關閉雙緩衝,自己管理繪圖。下面的語句設置了窗口部件的Qt::WA_PaintOnScreen屬性 ,就關閉了窗口部件的雙緩衝。
widget->setAttribute(Qt::WA_PaintOnScreen);
Qt4不再提供異或筆,組合模式QPainter::CompostionMode_Xor()並不是異或筆,Qt4只提供了QRubberBand實現矩形和直線的繪圖反饋。要實現在繪圖中動態反饋必須使用其他方法。程序中使用雙緩衝來解決這個問題。在繪圖過程中,一個緩衝區繪製臨時內存,一個緩衝區保存繪製好的內容,最後進行合併。
在交互繪圖過程中,程序將圖像緩衝區複製到臨時緩衝區,並在臨時緩衝區上繪製,繪製完畢在將結果複製到圖像緩衝區,如果沒有交互複製,則直接將圖像緩衝區繪製顯示到屏幕上。
4、繪圖路徑
繪圖路徑(painter path)由基本圖元(矩形,橢圓,直線,曲線)組成,繪圖路徑可以是閉合的路徑,如矩形和圓,或者是非閉合的路徑,如直線和曲線。繪圖路徑在Qt中使用QPainterPth類表示,提供了繪圖操作的容器,可以使圖形能夠複用。繪圖路徑可以進行填充,顯示輪廓和裁剪。要生成可填充的輪廓的繪圖路徑,可以使用QPainterPathStroker類。使用QPainterPath的優點是複雜的圖形只需創建一次,就可以多次使用。QPainterPath對象可以是隻有起點的空路徑,或者從其他QPainterPath對象複製,創建了QPainterPath對象後,可以使用lineTo(),cubicTo(),quadTo() 函數將直線和曲線添加到路徑中來,直線和曲線從currentPosition()開始繪製。currentPosition()總是返回最後的子路經繪製的終點。使用moveTo()函數可以在不增加路徑的情況下移動currentPositon(),它關閉了一個子路經,開始一個新的子路經。 closeSubPath()也可以關閉當前路徑,並從currentPosition()連接一條直線到繪圖路徑的起點。QPainter可以使用 addEllipse(),addPath(),addRect(),addRegion(),
addText()將Qt的一些基本圖元加入繪圖路徑。一個已有的繪圖路徑可以通過connectPath()函數加入到另一個繪圖路徑中。
箭頭的繪製代碼如下:
QPainterPath path;
path.moveTo(10,100);
path.cubicTo(10,100,100,10,200,70);
path.lineTo(200,50);
path.lineTo(220,80);
path.lineTo(200,110);
path.lineTo(200,90);
path.cubicTo(200,100,100,50,50,100);
QPainter painter(this);
QPen pen(QColor(255,0,0),2);
painter.setPen(pen);
painter.drawPath(path);
Qt提供了兩種填充方式,Qt::OddEventFill和Qt::WindingFill。Qt::OddEvent是默認的填充規則,指定QPainterPath使用奇偶填充規則,奇偶填充規則判斷一個點是否在路徑圖形內的方法是從該點畫一條水平線到路徑外,計算水平線和路徑的交點數,如果交點是奇數個則說明該點在路徑圖形內。QPainterPath還有一些函數可以獲取路徑信息,如elementAt()函數可以取出指定的子路經元素,isEmpty()函數判斷當前路徑是否為空。controlPointRect()函數返回路徑中所有的點和控制點的矩形,controlPointRect函數運行速度比返回精確包容框boundingRect()函數快得多。contains()函數判斷一個點或一個矩形是否在路徑內。intersects()判斷指定的矩形與路徑是否相交。QPainterPath可以將矩形圖形轉換為其他圖形,如使用toFillPolygon(),toFillPolygon(),toSubpathPOlygons()函數將路徑轉化為多邊形。
QPainterPath還可以使用文字作為路徑。
使用線性漸變填充的文字路徑實現代碼:
QPainter painter(this);
QLinearGradient linearGrad(QPointF(200,0),QPointF(1000,0));
linearGrad.setColorAt(0,Qt::black);
linearGrad.setColorAt(1,Qt::white);
QFont font("隸書",80);
font.setBold(true);
QPainterPath textPath;
textPath.addText(200,300,font,tr("電子工業出版社"));
painter.setBrush(linearGrad);
painter.drawPath(textPath);
三、繪圖設備
QPaintDevice類是繪製設備的基類,QPainter能夠在QPaintDevice子類QWidget,QImage,QPixmap,QGLWidget,QGLPixelBuffer,QPicture,QPrinter,
QSvgGenerator上進行繪製。要實現自定義的繪圖設備,必須從QPaintDevice類繼承並實現其虛函數QPaintDevice::paintEngine(),paintEngine()將通知QPainter能夠在自定義的設備上繪製圖形,同時還需要從QPaintEngine類繼承自定義的圖形繪製引擎。
1、QWidget
QWidget是所有用戶界面元素的基類,窗口部件是用戶界面的原子元素,接受鼠標、鍵盤、窗口系統的其他事件並在屏幕上繪製自己。
2、QImage
QImage類提供了與硬件無關的圖像表示,為直接操作像素提供優化,QImage支持單色、8-bit、32-bit和alpha混合圖像,使用QImage的優點在於可以獲得平臺無關的繪製操作,同時圖像可以不必在GUI線程中處理。
3、QPixmap
QPixmap是後臺顯示的圖像,為在屏幕上顯示圖像提供優化,不同於QImage,QPixmap的圖像數據用戶不可見,由底層窗口系統管理,為了優化QPixmap圖像,Qt提供了QPixmapCache類來存儲臨時的pixmap。Qt還提供了QPixmap的繼承類QBitmap類,QBitmap表示單色的pixmap,主要用來創建自定義的QCursor和QBrush對象,構造QRegion對象,設置pixmap和窗口部件的掩碼。
4、OPenGLWidget
Qt提供了QtOpenGL模塊來實現OpenGL操作,QGLWidget允許使用OpenGL API進行繪製。QGLWidget是QWidget的子類,QPainter可以在上面繪製,因此Qt能夠利用OpenGL完成繪製操作,如變換和繪製pixmap。
5、QGLPixelBuffer
QGLPixelBuffer從QPaintDevice繼承,封裝了OpenGL pbuffer,使用pbuffer繪製通常是全硬件加速,比使用QPixmap繪製更加迅速。
6、QGLFrameBufferObject
QGLFrameBufferObject從QPaintDevice繼承,QGLFrameBufferObject封裝了OpenGL frameBuffer對象,FrameBuffer用來實現後臺屏幕繪製,比pixel buffer更好。
7、QPicture
QPicture類是能夠記錄和重演QPainter命令的繪圖設備,picture串行化painter的命令為平臺無關的格式,QPicture同時也與分辨率無關,如QPicuture能夠在不同的設備上(svg,pdf,ps打印機和屏幕)有一樣的顯示。QPicture::load()和QPicture::save()函數分別完成載入和存儲圖像。
8、QPrinter
QPrinter類是在打印機上繪製的繪圖設備,在Windows和MAC OS X上,QPrinter使用內建的打印機驅動程序,在X11上,QPrinter上傳postscript代碼併發送給lpr,lp或者其他打印程序,QPrinter可以在任意其他QPrintEngine對象上打印,也可以直接生成PDF文件。
QPrintEngine類定義了QPrinter如何和其他打印機系統交互的接口,主要創建自己的打印引擎時,可以從QPaintEngine和QPaintEngine上繼承。
四、QPainter類成員函數
主要的繪圖成員函數如下:
drawArc() 弧
drawChord() 弦
drawConvexPolygon() 凸多邊形
drawEllipse() 橢圓
drawImage() QImage表示的圖像
drawLine() 線
drawLines() 多條線
drawPath() 路徑
drawPicture() 按QPainter指令繪製
drawPie() 扇形
drawPixmap() QPixmap表示的圖像
drawPoint() 點
drawPoints() 多個點
drawPolygon() 多邊形
drawPolyline() 多折線
drawRect() 矩形
drawRects() 多個矩形
drawRoundRect() 圓角矩形
drawText() 文字
drawTiledPixmap() 平鋪圖像
drawLineSegments() 繪製折線
設置好畫筆、畫刷就可以使用繪圖函數進行繪圖。
閱讀更多 cpp軟件架構獅 的文章