《QT Creator快速入門》第十章:2D繪製(3)
1、繪製文字
使用QPainter::drawText()來繪製文字:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QRectF rect(10.0, 10.0, 580.0, 280.0); painter.setPen(Qt::red); painter.drawRect(rect); painter.setPen(Qt::blue); painter.drawText(rect, Qt::AlignHCenter, "alignHCenter"); painter.drawText(rect, Qt::AlignLeft,View Code"alignLeft"); painter.drawText(rect, Qt::AlignRight, "alignRight"); painter.drawText(rect, Qt::AlignVCenter, "alignVCenter"); painter.drawText(rect, Qt::AlignBottom, "AlignBottom"); painter.drawText(rect, Qt::AlignCenter, "AlignCenter"); painter.drawText(rect, Qt::AlignBottom | Qt::AlignRight, "AlignBottom|AlignRight"); painter.drawText(rect, Qt::AlignBottom | Qt::AlignCenter, "AlignBottom|AlignCenter"); painter.drawText(rect, Qt::AlignCenter | Qt::AlignRight, "AlignCenter|AlignRight"); }
使用QPainter::setFont()來設定文字字型,QPainter::fontInfo()可以獲得當前字型資訊,QFontDatabase類可以獲得支援的所有字型族:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QFont font("宋體", 15, QFont::Bold, true); //字型族,磅值,字型粗細,是否斜體 font.setUnderline(true);//設定下劃線 font.setCapitalization(QFont::AllUppercase);//設定字母大寫 font.setLetterSpacing(QFont::AbsoluteSpacing, 10);//設定字元間距 painter.setFont(font); painter.setPen(Qt::green); painter.drawText(120, 80, "yafei-linux"); //平移並旋轉後再繪製文字 painter.translate(120, 100); painter.rotate(90); painter.drawText(0, 0, "hello qt"); }View Code
drawText()還有一個以一個點為基準來繪製文字的版本,如下所示,需要注意的是繪製的時候是以這個點的Y座標為字型的baseline的:
2、繪製圖片
Qt提供了四個類來處理影象資料:QImage、QPixmap、QBitmap、QPicture。
①、QImage不僅可以載入一個圖片然後顯示出來,還可以在一個QImage上進行繪製文字,圖形等操作,然後將這個QImage顯示出來,如以下程式碼在QImage上進行一些繪製操作,然後顯示出來:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter; QImage image(100, 100, QImage::Format_ARGB32); painter.begin(&image); painter.setPen(QPen(Qt::green, 3)); painter.setBrush(Qt::yellow); painter.drawRect(10, 10, 60, 60); painter.drawText(10, 10, 60, 60, Qt::AlignCenter, "QImage"); painter.setBrush(QColor(0, 0, 0, 100)); painter.drawRect(50, 50, 40, 40); painter.end(); painter.begin(this); painter.drawImage(50, 20, image); painter.end(); }View Code
下面程式碼實現了載入圖片然後顯示,再將圖片特殊處理後顯示並另存為的功能:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QImage image; image.load("F://image.png");//載入圖片 qDebug() << "size: " << image.size() << "format: " << image.format() << "depth: " << image.depth();//獲得圖片資訊 painter.drawImage(10, 10, image);//顯示圖片 QImage mirror = image.mirrored();//獲取圖片映象 QTransform transform; transform.shear(0.2, 0); QImage image2 = mirror.transformed(transform);//將圖片扭曲 painter.drawImage(300, 10, image2);//顯示圖片 image2.save("F://image2.png");//儲存圖片 }View Code
QImage還提供了強大的訪問和操作畫素的功能。
②、一般是使用QPixmap載入和顯示影象,如果需要提前對影象進行操作的話,先用QImage載入圖片,對圖片資料進行操作,然後將Qimage轉換為QPixmap物件來顯示圖片(可以使用toImage()和fromImage()在QImage和QPixmap之間進行轉換)。
QPixmap的fill()函式可以使用指定的顏色初始化整個pixmap影象,還可以使用grabWindows()和grabWidget()等靜態函式來實現擷取螢幕、擷取視窗部件上內容功能。
以下程式碼使用QPixmap載入並顯示了圖片,並展示了在圖片之上繪製一個透明矩形的效果:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); QPixmap pix; pix.load("./image.png"); painter.drawPixmap(0, 0, pix); painter.drawPixmap(300, 0, pix); painter.setBrush(QColor(255, 255, 255, 100)); painter.drawRect(300, 0, pix.width(), pix.height()); painter.drawPixmap(0, 250, pix); painter.setBrush(QColor(0, 0, 255, 100)); painter.drawRect(0, 250, pix.width(), pix.height()); painter.drawPixmap(300, 250, pix); painter.setBrush(QColor(0, 0, 0, 150)); painter.drawRect(300, 250, pix.width(), pix.height()); }View Code
drawPixmap()有很多過載函式,比如:
void QPainter::drawPixmap ( int x, int y, const QPixmap & pixmap ),表示使用pixmap中圖片大小向(x, y)處繪製。
void QPainter::drawPixmap ( int x, int y, int width, int height, const QPixmap & pixmap ),表示向指定座標和大小的位置繪製 pixmap中內容。
void QPainter::drawPixmap ( int x, int y, const QPixmap & pixmap, int sx, int sy, int sw, int sh ),表示向指定座標繪製pixmap中指定位置和大小的內容。
下面的程式碼擷取整個屏幕後儲存檔案,然後將擷取的影象顯示到一個Label上:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); QPixmap screen = QPixmap::grabWindow(QApplication::desktop()->winId()); screen.save("F://screen.png"); QLabel* label = new QLabel(this); label->move(10, 10); label->resize(400, 200); QPixmap pix = screen.scaled(label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); label->setPixmap(pix); }View Code
上面程式碼用到了QPixmap::scaled()函式,它可以對QPixmap上影象進行縮放後儲存到另一個QPixmap物件上,其第一個引數指定縮放後的大小,第二個引數指定寬高比(Qt::IgnoreAspectRatio為自由縮放;Qt::KeepAspectRatio為保持寬高比,在給定的矩形內;Qt::KeepAspectRatioByExpanding為保持寬高比,在給定的矩形外;各選項效果見下圖),第三個引數指定轉換模式(快速轉換Qt::FastTransformation和平滑轉換Qt::SmoothTransformation) 。
③、QBitmap只能用來處理和顯示黑白兩種顏色。
④、QPicture是一個可以記錄和重演QPainter命令的繪圖裝置,即它可以將繪圖命令序列化,對序列化的繪圖命令進行重演。
⑤、使用QPainter::setCompositionMode()來設定繪圖的複合模式,其中有QPainter::CompositionMode_SourceOver(預設模式)、QPainter::CompositionMode_DestinationOver等模式,各模式效果如下圖:
修改繪圖的複合模式一個示例及效果:
void Widget::paintEvent(QPaintEvent *event) { QPainter painter; QImage image(400, 300, QImage::Format_ARGB32_Premultiplied); painter.begin(&image); painter.setBrush(Qt::red); painter.drawRect(100, 50, 200, 200); painter.setBrush(Qt::green); painter.drawRect(50, 0, 100, 100); painter.setBrush(Qt::blue); painter.setCompositionMode(QPainter::CompositionMode_DestinationOver); painter.drawRect(250, 0, 100, 100); painter.end(); painter.begin(this); painter.drawImage(0, 0, image); painter.end(); }View Code
可以將圖片新增到專案中來使用,新增圖片資源的方法為:首先專案右鍵新增Qt資原始檔(名稱可以設定為myResource,路徑為當前專案目錄,點選確定後可以看到當前專案下有了一個qrc檔案)->如果沒有彈出資源編輯器頁面的話右鍵點選qrc檔案選擇open in editor,然後點選下方的“新增”按鈕,選擇新增字首,可以編輯字首名為/image,按下ctrl+s儲存->然後再點選下方的"新增"按鈕,選擇新增檔案來新增圖片檔案(圖片檔案應該在qrc所在目錄下或其子目錄下),最後按下ctrl+s儲存,然後在程式中就可以通過":/image/imageName.png"來使用圖片:
void Widget::paintEvent(QPaintEvent* ) { QPainter painter(this); QPixmap pix(":/image/112.png"); painter.drawPixmap(0, 0, pix);//在指定位置chu 原圖大小顯示 //painter.drawPixmap(QRect(10, 10, 200, 160), pix, // QRect(0, 0, pix.width(), pix.height()));//按照指定區域縮放顯示 }View Code
3、其它影象處理類
QImageReader可以在載入影象時提供更多的控制,如使用setScaledSize()來將影象以指定的大小來讀取,使用setClipRect()來只讀取影象的一個區域。
QImageWriter提供了儲存影象的更多控制,如壓縮等級和品質、伽瑪等級等。
QMovie可以用來播放gif動畫,可以參考該類的幫助文件或檢視Movie Player示例程式。
QSvgWidget可以載入一個SVG(可縮放向量圖形)檔案,使用QSvgRenderer類在QSvgWidget中進行SVG檔案的渲染,可以參考SVG Generator和SVG Viewer示例程式。
4、鍵盤事件、滑鼠事件、重繪事件
鍵盤按下事件處理函式:void keyPressEvent(QKeyEvent *);
鍵盤松開事件處理函式:void keyReleaseEvent(QKeyEvent *)
滑鼠按下事件處理函式:mousePressEvent(QMouseEvent* event)
滑鼠移動事件處理函式:mouseMoveEvent(QMouseEvent* event),如果想要保證不用按下滑鼠也能觸發滑鼠移動事件,則在部件的建構函式中新增:setMouseTracking(true);
滑鼠鬆開事件處理函式:mouseReleaseEvent(QMouseEvent* event)
滑鼠滾輪滾動事件處理函式:wheelEvent(QWheelEvent *)
其中的QMouseEvent包含了滑鼠資訊,比如QMouseEvent::pos()可以獲得當前滑鼠位置。
重繪事件處理函式:void Widget::paintEvent(QPaintEvent *event)
重繪事件一般產生在repaint()或update()函式呼叫後,或者隱藏的部件被顯示,或者其他一些原因。repaint()後paintEvent()會立即呼叫,update()會將重繪事件放入主訊息迴圈中,如果update被呼叫了很多次,最後這些update會合併到一個大的重繪事件,所以只會呼叫一次update(),
一般情況下我們選擇使用update()。
當重繪事件發生時,要更新的區域一般會被擦除,然後在部件的背景上進行繪製,部件的背景可以使用setBackgroundRole()函式來設定,然後使用setAutoFillBackground()函式來啟用指定的顏色,eg:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); ui->pushButton->setBackgroundRole(QPalette::Dark); ui->pushButton->setAutoFillBackground(true); }View Code
5、雙緩衝
雙緩衝繪圖就是在繪製的時候將所有內容都繪製到一個繪圖裝置(如QPixmap)上,然後再將繪圖裝置中整個影象繪製到部件上顯示出來,這樣避免了一個一個的將內容繪製到部件上產生的顯示閃爍現象。Qt4之後QWidget部件的所有繪製都自動使用了雙緩衝,所以一般沒必要在paintEvent()中使用雙緩衝,不如如果想要實現一些繪圖效果的話,還是要藉助雙緩衝的概念。