1. 程式人生 > 實用技巧 >《QT Creator快速入門》第十章:2D繪製(3)

《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, 
"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"); }
View Code

使用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()中使用雙緩衝,不如如果想要實現一些繪圖效果的話,還是要藉助雙緩衝的概念。