文章目录
- 一、绘图设备
- 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"));
}