界面編程之QT繪圖和繪圖設備20180728


/*******************************************************************************************/

一、繪圖

整個繪圖系統基於QPainter,QPainterDevice和QPaintEngine三個類:

QPainter(畫家)->QPaintEngine(中間引擎,畫家與設備之間的交互(通信接口),對於應用開發一般用不上)->QpaintDevice(設備,表示畫在哪里)

 

畫圖的時候就是要重寫事件:

protected:

    //重寫繪圖事件,虛函數

    //如果在窗口上(給窗口)繪圖,必須放在繪圖事件里實現

    //繪圖事件內部自動調用,窗口需要重繪的時候(窗口狀態改變的時候)自動調用

         //當然也可以人為的調用

    void paintEvent(QPaintEvent *);

        

void Widget::paintEvent(QPaintEvent *)

{

    //QPainter p(this);//這是一種方法,因為this是Widget也是一種繪圖設備

         //另一種方法,begin

    QPainter p;//創建畫家對象

    p.begin(this);//指定當前窗口為繪圖設備,因為this是Widget也是一種繪圖設備

        

    //繪圖操作

    //p.drawxxx();

    //比如,畫背景圖(一般先畫):

    //p.drawPixmap(0, 0, width(), height(), QPixmap("../Image/bk.png"));          //繪圖操作

         p.drawPixmap(rect(), QPixmap("../Image/bk.png"));

 

    //定義畫筆,畫筆確定畫家畫出什么樣的效果

    QPen pen;

    pen.setWidth(5); //設置線寬大小,

    //pen.setColor(Qt::red); //設置顏色

    pen.setColor( QColor(14, 9, 234) );//rgb設置顏色

    pen.setStyle(Qt::DashLine); //設置風格

 

    //把畫筆交給畫家,這樣畫家才有畫筆,才生效

    p.setPen(pen);

 

    //畫直線

    p.drawLine(50, 50, 150, 50);

    p.drawLine(50, 50, 50, 150);

 

    //創建畫刷對象,用於封閉圖形填充顏色

    QBrush brush;

    brush.setColor(Qt::red); //設置顏色

    brush.setStyle(Qt::Dense1Pattern);//設置樣式

 

    //把畫刷交給畫家

    p.setBrush(brush);

 

 

    //畫矩形

    p.drawRect(150, 150, 100, 50);

 

    //畫圓形,后兩個分別是水平半徑和垂直半徑,當相等的時候為圓形

    p.drawEllipse(QPoint(150, 150), 50, 25);

 

    //畫笑臉

    p.drawPixmap(x, 180, 80, 80, QPixmap("../Image/face.png"));

        

         //另一種方法,end

    p.end();   

 

/*******************************************************************************************/

二、手動更新窗口

調用update()函數:

 

void Widget::on_pushButton_clicked()

{

    x += 20;

    if(x > width())

    {

        x = 0;

    }

 

    //刷新窗口,讓窗口重繪,沒有參數所以整個窗口都刷新(重繪),如果有填入指定區域的參數,則只刷新區域部分

    update(); //相當於間接調用paintEvent()

}

 

上述代碼具體見《PaintEvent》

 1 #ifndef WIDGET_H
 2 #define WIDGET_H
 3 
 4 #include <QWidget>
 5 
 6 namespace Ui {
 7 class Widget;
 8 }
 9 
10 class Widget : public QWidget
11 {
12     Q_OBJECT
13 
14 public:
15     explicit Widget(QWidget *parent = 0);
16     ~Widget();
17 
18 protected:
19     //重寫繪圖事件,虛函數
20     //如果在窗口繪圖,必須放在繪圖事件里實現
21     //繪圖事件內部自動調用,窗口需要重繪的時候(狀態改變)
22     void paintEvent(QPaintEvent *);
23 
24 private slots:
25     void on_pushButton_clicked();
26 
27 private:
28     Ui::Widget *ui;
29     int x;
30 };
31 
32 #endif // WIDGET_H
widget.h
 1 #include "widget.h"
 2 #include "ui_widget.h"
 3 #include <QPainter>
 4 #include <QPen>
 5 #include <QBrush>
 6 
 7 Widget::Widget(QWidget *parent) :
 8     QWidget(parent),
 9     ui(new Ui::Widget)
10 {
11     ui->setupUi(this);
12 
13     x = 0;
14 }
15 
16 Widget::~Widget()
17 {
18     delete ui;
19 }
20 
21 void Widget::paintEvent(QPaintEvent *)
22 {
23     //QPainter p(this);
24 
25     QPainter p;//創建畫家對象
26     p.begin(this);//指定當前窗口為繪圖設備
27 
28     //繪圖操作
29     //p.drawxxx();
30     //畫背景圖
31     //p.drawPixmap(0, 0, width(), height(), QPixmap("../Image/bk.png"));
32     p.drawPixmap(rect(), QPixmap("../Image/bk.png"));
33 
34     //定義畫筆
35     QPen pen;
36     pen.setWidth(5); //設置線寬
37     //pen.setColor(Qt::red); //設置顏色
38     pen.setColor( QColor(14, 9, 234) );//rgb設置顏色
39     pen.setStyle(Qt::DashLine); //設置風格
40 
41     //把畫筆交給畫家
42     p.setPen(pen);
43 
44     //畫直線
45     p.drawLine(50, 50, 150, 50);
46     p.drawLine(50, 50, 50, 150);
47 
48     //創建畫刷對象
49     QBrush brush;
50     brush.setColor(Qt::red); //設置顏色
51     brush.setStyle(Qt::Dense1Pattern);//設置樣式
52 
53     //把畫刷交給畫家
54     p.setBrush(brush);
55 
56 
57     //畫矩形
58     p.drawRect(150, 150, 100, 50);
59 
60     //畫圓形
61     p.drawEllipse(QPoint(150, 150), 50, 25);
62 
63     //畫笑臉
64     p.drawPixmap(x, 180, 80, 80, QPixmap("../Image/face.png"));
65 
66     p.end();
67 }
68 
69 void Widget::on_pushButton_clicked()
70 {
71     x += 20;
72     if(x > width())
73     {
74         x = 0;
75     }
76 
77     //刷新窗口,讓窗口重繪,整個窗口都刷新
78     update(); //間接調用paintEvent()
79 }
widget.cpp

/*******************************************************************************************/

三、QBitMap和QPixmap的區別

QBitMap是QPixmap的子類

QBitMap是黑白的圖片

QPixmap是彩色的圖片

 

#include "widget.h"

#include "ui_widget.h"

#include <QPainter>

#include <QBitmap>

 

Widget::Widget(QWidget *parent) :

    QWidget(parent),

    ui(new Ui::Widget)

{

    ui->setupUi(this);

}

 

Widget::~Widget()

{

    delete ui;

}

 

void Widget::paintEvent(QPaintEvent *)

{

    QPainter p(this);

    //QPixmap 圖片背景透明

    p.drawPixmap(0, 0, QPixmap("../Image/butterfly.png"));

    //QBitmap 圖片背景透明 透明的部分變為黑色了

    p.drawPixmap(200, 0, QBitmap("../Image/butterfly.png"));

 

     //QPixmap 圖片背景白色

    QPixmap pixmap;

    pixmap.load("../Image/butterfly1.png");

    p.drawPixmap(0, 200, pixmap);

 

    //QBitmap 圖片背景白色,白色變為透明了

    QBitmap bitmap;

    bitmap.load("../Image/butterfly1.png");

    p.drawPixmap(200, 200, bitmap);

 

}

 

/*******************************************************************************************/

四、繪圖設備

繪圖設備主要有三種:

I、QPixmap               //最常用,針對屏幕進行優化了,和平台(顯卡)相關,不可以對圖片進行修改 //QBitMap是QPixmap的子類 QBitMap是黑白的圖片

II、QImage               //沒有優化,和平台無關,有自己的一套系統。可以對圖片進行修改(像素點的修改),可以在線程中繪圖即可以在單獨開的線程中使用

III、QPicture   //平台無關的,保存繪圖的狀態(保存為一個二進制文件),可以給另外的程序(平台)使用導致另外的繪的一樣。

都可以在窗口上面繪圖

 

1.QPixmap繪圖設備

    //繪圖設備, 400*300

    QPixmap pixmap(400, 300);

 

    QPainter p(&pixmap);

    //填充白色背景色

    //p.fillRect(0, 0, 400, 300, QBrush(Qt::white));

 

    pixmap.fill(Qt::white);

 

    p.drawPixmap(0, 0, 80, 80, QPixmap("../Image/face.png"));

 

    //把繪圖設備中的圖片(繪畫結果)保存出來,保存圖片

    pixmap.save("../pixmap.jpg");

 

2.QImage繪圖設備

         //創建一個繪圖設備,QImage::Format_ARGB32背景是透明

    QImage image(400, 300, QImage::Format_ARGB32);

    QPainter p;

    p.begin(&image);

 

    //繪圖

    p.drawImage(0, 0, QImage("../Image/face.png"));

 

    //對繪圖設備前50個像素點進行操作

    for(int i = 0; i < 50; i++)

    {

        for(int j = 0; j < 50; j++)

        {

            image.setPixel(QPoint(i, j), qRgb(0, 255, 0));

            //image.pixel(QPoint(i, j));

        }

    }

 

    p.end();

 

    image.save("../image.png");

 

3.QPicture繪圖設備

 

Widget::Widget(QWidget *parent) :

    QWidget(parent),

    ui(new Ui::Widget)

{

    ui->setupUi(this);

 

    QPicture picture;

    QPainter p;

    p.begin(&picture);

 

    p.drawPixmap(0, 0, 80, 80, QPixmap("../Image/face.png"));

    p.drawLine(50, 50, 150, 50);

 

    p.end();

 

    //保存的是二進制文件

    picture.save("../picture.png");//把繪圖狀態(繪圖操作)保存為二進制文件

}

void Widget::paintEvent(QPaintEvent *)

{

    QPicture pic;

         //加載文件

    pic.load("../picture.png"); //加載之前繪圖的操作,用於生成圖片

 

    QPainter p(this);

    p.drawPicture(0, 0, pic);

 

}

 

4.QImage和QPixmap相互轉換

QPixmap使用底層平台的繪制系統進行繪制,無法提供像素級別的操作,而QImage則是使用獨立於硬件的繪制系統,實際上是自己繪制自己,

因此提供了像素級別的操作,並且能夠在不同系統之上提供一個一致的顯示形式。

 

比如網絡傳輸的是QImage(因為和和平台無關),但是畫的時候需要有優化的QPixmap,這時就需要吧接收到的

QImage轉換為QPixmap

void Widget::paintEvent(QPaintEvent *)

{

    QPainter p(this);

    QPixmap pixmap;

    pixmap.load("../Image/face.png");

 

    //QPixmap -> QImage

    QImage tempImage = pixmap.toImage();

    p.drawImage(0, 0, tempImage);

 

 

    QImage image;

    image.load("../Image/face.png");

 

    //QImage -> QPixmap

    QPixmap tempPixmap = QPixmap::fromImage(image);

    p.drawPixmap(100, 0, tempPixmap);

 

}

 

/*******************************************************************************************/

五、不規則窗口

常見的窗體是各種方形的對話框,但有時候也需要非方形的窗體,如圓形,橢圓甚至是不規則形狀的對話框。

實現步驟:

1.新建一個項目,比如項目名稱叫做“ShapeWidget”,給此項目添加一個類“ShapeWidget”,基類選擇“QWidget”。

2.為了使該不規則窗體可以通過鼠標隨意拖拽,在類中重定義鼠標事件:mousePressEvent()、mouseMoveEvent()、以及繪制函數paintEvent()

3.“ShapeWidget”的構造函數部分是實現該不規則窗體的關鍵,添加具體代碼如下:

Widget::Widget(QWidget *parent) :

    QWidget(parent),

    ui(new Ui::Widget)

{

    ui->setupUi(this);

 

    //去窗口邊框

    setWindowFlags(Qt::FramelessWindowHint | windowFlags());

 

    //把窗口背景設置為透明,通過透明已經將窗口設置為圖片的樣式了,窗口和透明圖片一樣,當然就是不規則窗口了

    setAttribute(Qt::WA_TranslucentBackground);

         //注意,此時無法移動鼠標以及無法關閉整個特殊的窗口,所以需要重寫這些事件

         //注意,移動窗口是行對於屏幕而言的,所以鼠標的坐標獲取是相對於窗口左上角而言的差值,移動也是移動到左上角。(移動的時候是以窗口的左上角移動的)

}

4.重新實現鼠標事件和繪制函數

void Widget::mousePressEvent(QMouseEvent *e)

{

    if(e->button() == Qt::RightButton)

    {

        //如果是右鍵,關閉窗口

        close();

    }

    else if(e->button() == Qt::LeftButton)

    {

        //求坐標差值

        //坐標差值=當前點擊坐標-窗口左上角坐標 //之所以不用表示相對於窗口的坐標e->x/y,是因為這個e->x/y是相對於窗口的內邊框,而移動的是外邊框

        p = e->globalPos() - this->frameGeometry().topLeft();//this->frameGeometry()獲取的是當前矩形窗口

                   //e->globalPos(),當前坐標 全局的,即相對於屏幕左上角的坐標。.topLeft()矩形窗口的左上角坐標

    }

}

void Widget::mouseMoveEvent(QMouseEvent *e)

{

    if(e->buttons() & Qt::LeftButton)

    {

            //把當前窗口中心點移動到左上角,即以當前的左上角作為移動后窗口的中心位置

       move(e->globalPos() - p);//當前坐標(全局的)減去差值等於左上角坐標(全局的)

            //參數里是移動到的位置

    }

}

void Widget::paintEvent(QPaintEvent *)

{

    QPainter p(this);

    p.drawPixmap(0, 0, QPixmap("../Image/sunny.png"));

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM