Qt绘图


绘图事件

绘图事件重写的情景

  • 当你需要创建一个自定义控件,并且这个控件需要显示特殊的图形、颜色或形状时,重写 paintEvent 是必要的。例如,如果你需要绘制一个自定义的进度条、按钮、图表等
  • 当你需要在窗口中绘制复杂的图形,或者在应用程序中实现动画时,paintEvent 可以用来每次刷新窗口内容

示例

  • 首先需要在窗口的头文件声明这方法,表示要重写
  • 然后书写具体规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void MainWindow::paintEvent(QPaintEvent *) {
// 实例化画家对象 this 指定的是绘图设备
QPainter painter(this);
// 设置画笔
QPen pen(QColor(255,0,0));
// 设置画笔宽度
pen.setWidth(3);
// 设置画笔风格
pen.setStyle(Qt::DotLine);
// 让画家 使用这个笔
painter.setPen(pen);

// 设置画刷,寄填充颜色
QBrush brush(Qt::cyan);
// 设置画刷风格
brush.setStyle(Qt::Dense7Pattern);
// 让画家使用画刷
painter.setBrush(brush);

// 画线
painter.drawLine(QPoint(0,0), QPoint(100,100));
// 画圆 椭圆
painter.drawEllipse( QPoint(100,100), 50,50);
// 画矩形
painter.drawRect(QRect(20,20,50,50));
// 画文字,这个使用画刷不会填充,且这个矩形没有线框,默认
painter.drawText(QRect(10,200,150,50), "好好学习,天天向上");
}

高级设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void MainWindow::paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.drawEllipse(QPoint(100,50),50,50);
//设置 抗锯齿能力 效率较低
painter.setRenderHint(QPainter::Antialiasing);
painter.drawEllipse(QPoint(200,50),50,50);

painter.drawRect(QRect(20,20,50,50));
// 让画家移动到 (100, 0) 位置再画,此时以画家为基准,在 (20, 20) 位置画
painter.translate(100,0);
// 保存画家状态
painter.save();
painter.drawRect(QRect(20,20,50,50));
translate(150, 0);
// 恢复画家之前保存的状态
painter.restore();
}

利用画家画资源图片,并且实现点击按钮就移动图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 首先在 mainwindow 头文件定义一个变量 posX,作为移动的指标
// 然后在 mainwindow.ui 中放一个按钮,取名为 btn
void MainWindow::paintEvent(QPaintEvent *) {
QPainter painter(this);
// 超出屏幕范围,就从 0 开始
if(posX > this->width()) {
posX = 0;
}
painter.drawPixmap(posX, 0, QPixmap(":/111.png"));
}

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
connect(ui->btn, &QPushButton::clicked, this, [=]() {
posX += 20;
// 如果要手动调用绘图事件 用 update 更新
update();
});
}

绘图设备

绘图设备简单来说就是绘图所在地,也就是画的东西画在上面

  • QPixmap 专门为图像在屏幕上的显示做了优化
  • QBitmapQPixmap 的一个子类,只有黑白两种颜色
  • QImage 专门为图像的像素级访问做了优化,也就是可以修改图片中的像素
  • QPicture 是用来记录和重现 QPainter 的各条命令
  • 上面的案例中在窗口画画,是因为串口是绘图设备,MainWindow 继承 QWidget, QWidget 继承 QObjectQPaintDevice,能够在窗口上画画

QPixmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// QPixmap
// 定义绘图设备的大小
QPixmap pix(300,300);
// 填充颜色(默认为黑色)
pix.fill(Qt::white);

// 声明画家
QPainter painter(&pix);
painter.setPen(QPen(Qt::green)); // QPen 是画笔
// 画椭圆(圆)
painter.drawEllipse(QPoint(150,150), 100,100); // 圆心,两个半径,一样就是圆

// 保存,保存在 E 盘,名字叫 pix.png
// 程序运行后,在 E 盘就能看到这个图片
pix.save("E:\\pix.png");

QImage

1
2
3
4
5
6
7
8
9
10
// QImage 绘图设备,后面参数是格式,查阅文档填写
QImage img(300,300, QImage::Format_RGB32);
img.fill(Qt::white);

QPainter painter(&img);
painter.setPen(QPen(Qt::blue));
painter.drawEllipse(QPoint(150,150),100,100);

//保存
img.save("E:\\img.png");

对像素修改例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 重写 painEvent 事件,需要现在 mainwindow 头文件定义
void MainWindow::paintEvent(QPaintEvent *) {
QPainter painter(this); // 这里 this 是指在这个窗口绘图、

// 利用&Image对像素进行修改
QImage img;
img.load(":/111.png");

// 修改像素点,会看到左上角部分有红色的矩形,这就是修改的
for(int i = 50; i < 100; i++) {
for(int j = 50; j < 100; j++) {
QRgb value = qRgb(255,0,0);
img.setPixel(i, j, value);
}
}
// 在 (0, 0) 处绘图
painter.drawImage(0, 0, img);
}

QPicture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
QPicture pic;
QPainter painter;

// 开始往 pic 上画
painter.begin(&pic);
painter.setPen(QPen(Qt::cyan));
painter.drawEllipse(QPoint(150,150),100,100);
// 结束画画
painter.end();

//保存到磁盘
pic.save("E:\\pic.txt");

// 重现
QPainter painter1(this);
// 重现 QPicture 的绘图指令
QPicture pic1;
pic1.load("E:\\pic.txt");
painter.drawPicture(0, 0, pic);

说明:参考 https://space.bilibili.com/396491181