文章目录
一、绘图设备
1. QPixmap
1.1 QPixmap 简介
1.2 QPixmap 演示
2. QBitmap
2.1 QBitmap 简介
2.2 QBitmap 演示见 QPixmap 和 QBitmap 的区别。
3. QImage
3.1 QImage 简介
3.2 QImage 演示
4. QPicture
4.1 QPicture 简介
4.2 QPicture 演示
二、QPixmap 和 QBitmap 的区别
1. widget.h
2. widget.cpp
3. 实现结果
三、QPixmap 与 QImage 的区别和相互转换
1. QImage 与 QPixmap 的区别
2. QImage 与 QPixmap 的相互转换
四、不规则窗口
由于每次代码都是在原有程序上修改,因此除了新建项目,不然一般会在学完后统一展示代码。
提示:具体项目创建流程和注意事项见
QT 学习笔记(一)
提示:具体项目准备工作和细节讲解见
QT 学习笔记(二)
一、绘图设备
绘图设备是指继承 QPainterDevice 的子类。 QT 一共提供了四个这样的类,分别是 QPixmap、QBitmap、QImage 和 QPicture。
QPixmap 专门为图像在屏幕上的显示做了优化,和平台相关,不能对图片进行修改。
QBitmap 是 QPixmap 的一个子类,它的色深限定为 1,可以使用 QPixmap 的 isQBitmap() 函数来确定这个 QPixmap 是不是一个 QBitmap。
QImage 专门为图像的像素级访问做了优化。,和平台无关,可以对图片进行修改, 在线程中绘图。
QPicture 可以记录和重现 QPainter 的各条命令,保存绘图的状态(二进制文件)。
1. QPixmap
- 生成一个新的项目,具体步骤过程见提示。
1.1 QPixmap 简介
(1) QPixmap 继承了 QPaintDevice 。因此,可以使用 QPainter 直接在上面绘制图形。
(2) QPixmap 可以接受一个字符串作为一个文件的路径来显示这个文件,比如想在程序之中打开 png、jpeg 之类的文件,就可以使用 QPixmap。
(3) 使用 QPainter 的 drawPixmap() 函数可以把这个文件绘制到一个 QLabel、QPushButton 或者其他的设备上面。
(4) QPixmap 是针对屏幕进行特殊优化的。因此,它与实际的底层显示设备息息相关。注意,这里说的显示设备并不是硬件,而是操作系统提供的原生的绘图引擎。所以,在不同的操作系统平台下,QPixmap 的显示可能会有所差别。
1.2 QPixmap 演示
- 我们现在指定绘图设备 QPixmap,不是窗口。因此,我们可以直接在构造函数里面编写代码。
- 运行后,在 QT 的运行结果上并没有现象。但是,在我们的文件当中,会生成一个 QPixmap.png 的图片文件。打开后,我们发现图片的背景颜色是黑色。
- 在应用的时候,我们往往按照需求对背景色进行填充。在这里以背景色为白色举例。
- 实现代码如下:
//绘图设备大小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("../tuoian/5.jpg")); //保存图片 pixmap.save("../pixmap.png");
2. QBitmap
2.1 QBitmap 简介
(1) QBitmap 继承于 QPixmap,因此具有 QPixmap 的所有特性,提供单色图像。
(2) QBitmap 的色深始终为1,色深这个概念来自计算机图形学,是指用于表现颜色的二进制的位数。计算机里面的数据都是使用二进制表示的。为了表示一种颜色,我们也会使用二进制。比如我们要表示 8 种颜色,需要用 3 个二进制位,这时我们就说色深是 3。因此,所谓色深为 1,也就是使用 1 个二进制位表示颜色。1 个位只有两种状态:0 和 1,因此它所表示的颜色就有两种,黑和白。因此,QBitmap 实际上是只有黑白两色的图像数据。
(3) 由于 QBitmap 色深小,因此只占用很少的存储空间,所以适合做光标文件和笔刷。
2.2 QBitmap 演示见 QPixmap 和 QBitmap 的区别。
3. QImage
- 生成一个新的项目,具体步骤过程见提示。
3.1 QImage 简介
(1) QImage 是使用独立于硬件的绘制系统,实际上是自己绘制自己,因此提供了像素级别的操作,并且能够在不同系统之上提供一个一致的显示形式。
(2) 我们声明了一个 QImage 对象,大小是 300 x 300,颜色模式是 RGB32,即使用 32 位数值表示一个颜色的 RGB 值,也就是说每种颜色使用 8 位。然后我们对每个像素进行颜色赋值,从而构成了这个图像。我们可以把 QImage 想象成一个 RGB 颜色的二维数组,记录了每一像素的颜色。
3.2 QImage 演示
- 我们现在指定绘图设备 QImage ,不是窗口。因此,我们可以直接在构造函数里面编写代码
ARGB 应用背景是透明色,RGB 的背景是黑色。在这里我们选用 QImage::Format_ARGB32 背景是透明,现象如下图所示:
QImage 可以对像素点进行操作,现象如下图所示:
- 实现代码如下:
//创建一个绘图设备,QImage::Format_ARGB32 背景是透明 QImage image(400,300,QImage::Format_ARGB32); QPainter p; p.begin(&image); //绘图 p.drawImage(0,0,QImage("../tuoian/5.jpg")); //对绘图设备前50个像素点进行操作 for(int i=0;i<50;i++) { for(int j=0;j<50;j++) { image.setPixel(QPoint(i, j), qRgb(0,255,0)); } } p.end(); //保存图片 image.save("../image.png");
4. QPicture
- 生成一个新的项目,具体步骤过程见提示。
4.1 QPicture 简介
(1) QPicture 是一个可以记录和重现 QPainter 命令的绘图设备。
(2) QPicture 将 QPainter 的命令序列化到一个 I/O 设备,保存为一个平台独立的文件格式。这种格式有时候会是“元文件(meta- files)”。QT 的这种格式是二进制的,不同于某些本地的元文件,QT 的 pictures 文件没有内容上的限制,只要是能够被 QPainter 绘制的元素,不论是字体还是 pixmap,或者是变换,都可以保存进一个 picture 中。
(3) QPicture 是平台无关的,因此它可以使用在多种设备之上,比如 svg、pdf、ps、打印机或者屏幕。这里所说的 QPaintDevice,实际上是说可以有 QPainter 绘制的对象。QPicture 使用系统的分辨率,并且可以调整 QPainter 来消除不同设备之间的显示差异。
(4) 如果要记录下 QPainter 的命令,首先要使用 QPainter::begin() 函数,将 QPicture 实例作为参数传递进去,以便告诉系统开始记录,记录完毕后使用 QPainter::end() 命令终止。
4.2 QPicture 演示
- 我们现在指定绘图设备 QPicture ,不是窗口。因此,我们可以直接在构造函数里面编写代码。
- QPicture 文件生成的图片是二进制文件,在文件路径下图片是无法打开的,实现代码和现象如下图所示:
QPicture picture; QPainter p; p.begin(&picture); //绘图 p.drawPixmap(0,0,80,80,QPixmap("../tuoian/5.jpg")); p.drawLine(50,50,150,50); p.end(); //保存的是二进制文件 picture.save("../picture.png");
如果我们想观察到生成的图片,需要在头文件 widget.h 当中的 protected 下进行 paintEvent 的声明,在源文件 widget.cpp 下进行实现,实现代码和现象如下图所示:
void Widget::paintEvent(QPaintEvent *) { QPicture pic; pic.load("../picture.png"); QPainter p(this); p.drawPicture(0,0,pic); }
二、QPixmap 和 QBitmap 的区别
- 生成一个新的项目,具体步骤过程见提示。
- QPixmap 主要是画彩色;QBitmap 只有黑白两种颜色。
- 下面进行同一个图像文件在 QPixmap 和 QBitmap 下的不同表现,以便于我们可以更直观的观察到区别。
1. widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = nullptr); ~Widget(); protected: //重写绘图事件 //如果给窗口绘图,一定要在paintEvent()中实现 void paintEvent(QPaintEvent *); private: Ui::Widget *ui; }; #endif // WIDGET_H
2. widget.cpp
#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); }
3. 实现结果
这里我们采用两张 png 图片。butterfly1.png 是没有透明色的纯白背景,而 butterfly.png 是具有透明色的背景。我们分别使用 QPixmap 和 QBitmap 来加载它们。
可以很明显知道它们的区别:白色的背景在 QBitmap 中消失了,而透明色在 QBitmap 中转换成了黑色;其他颜色则是使用点的疏密程度来体现的。
三、QPixmap 与 QImage 的区别和相互转换
1. QImage 与 QPixmap 的区别
1) QPixmap 主要是用于绘图,针对屏幕显示而最佳化设计;QImage 主要是为图像 I/O、图片访问和像素修改而设计的。
(2) QPixmap 依赖于所在的平台的绘图引擎,故例如反锯齿等一些效果在不同的平台上可能会有不同的显示效果;QImage 使用 QT 自身的绘图引擎,可在不同平台上具有相同的显示效果。
(3) QImage 是独立于硬件的,也是一种 QPaintDevice,因此我们可以在另一个线程中对其进行绘制,而不需要在 GUI 线程中处理,使用这一方式可以很大幅度提高 UI 响应速度。
(4) QImage 可通过 setPixpel() 和 pixel() 等方法直接存取指定的像素。
2. QImage 与 QPixmap 的相互转换
- (1) QImage 转换为 QPixmap :
- 使用 QPixmap 的静态成员函数 fromImage()。
QPixmap tempPixmap = QPixmap::fromImage(image);
- (2) QPixmap 转换为 QImage :
- 使用 QPixmap 类的成员函数 toImage()。
QImage tempImage = pixmap.toImage();
四、不规则窗口
- 生成一个新的项目,具体步骤过程见提示。
- 常见的窗体是各种方形的对话框,但有时候也需要非方形的窗体,如圆形,椭圆甚至是不规则形状的对话框。
- 不规则窗口的实现步骤:
(1) 新建一个项目,比如项目名称叫做 ShapeWidget,给此项目添加一个类 ShapeWidget,基类选择 QWidget。
(2) 为了使该不规则窗体可以通过鼠标随意拖拽,在类中重定义鼠标事件:mousePressEvent()、mouseMoveEvent()、以及绘制函数 paintEvent()。
(3) ShapeWidget 的构造函数部分是实现该不规则窗体的关键,具体代码如下:
//新建一个Pixmap对象 QPixmap pixmap; //加载图片 pixmap.load("../tuoian/7.jpg"); //固定窗口大小,将窗口大小设置为图片大小 setFixedSize( pixmap.width(), pixmap.height() ); //给窗口去掉边框,设置窗口的flags setWindowFlags(Qt::FramelessWindowHint | windowFlags() ); //设置透明背景 setAttribute(Qt::WA_TranslucentBackground);
- 4) 重新实现鼠标事件和绘制函数,具体代码如下:
void ShareWidget::mousePressEvent(QMouseEvent *ev) { if(ev->button() == Qt::LeftButton) { //求坐标插值 //当前点击坐标-窗口左上角坐标 m_dragPoint = ev->globalPos()-frameGeometry().topLeft(); } else if(ev->button() == Qt::RightButton) { // 鼠标右键关闭窗口 close(); } } void ShareWidget::mouseMoveEvent(QMouseEvent *ev) { if(ev->buttons() & Qt::LeftButton) { // 如果是鼠标左键拖动, 移动窗口 move(ev->globalPos() - m_dragPoint); } } void ShareWidget::paintEvent(QPaintEvent *ev) { Q_UNUSED(ev) QPainter painter(this); // 重新绘制图片 painter.drawPixmap(0, 0, QPixmap(":/ButterFly")); }