zl程序教程

您现在的位置是:首页 >  工具

当前栏目

Qt 绘图进阶之二:双缓冲机制与实例

Qt实例 机制 进阶 绘图 之二 缓冲
2023-09-27 14:29:13 时间

一、双缓冲机制

所谓双缓冲机制,是指在绘制控件时,首先将要绘制的内容绘制在一个图片中,再将图片一次性地绘制到控件上。

在早期的Qt版本中,若直接在控件上进行绘制工作,则在控件重绘时会产生闪烁的现象,控件重绘频繁时,闪烁尤为明显。双缓冲机制可以有效地消除这种闪烁现象。自 Qt 5 版本之后,QWidget 控件已经能够自动处理闪烁的问题。

因此,在控件上直接绘图时,不用再操心显示的闪烁问题,但双缓冲机制在很多场合仍然有其用武之地。当所需绘制的内容较复杂并需要频繁刷新,或者每次只需要刷新整个控件的一小部分时,仍应尽量采用双缓冲机制。

二、实例效果图

实现一个简单的绘图工具,可以选择线形,线宽,颜色等基本要素。效果图如下所示:

Qt_PaintPic_A.png


三、实例核心代码

PaintArea.h:

#ifndef PAINTAREA_H
#define PAINTAREA_H

#include <QWidget>
#include <QPen>
#include <QBrush>
#include <QMouseEvent>
#include <QPainter>

// 绘图区域
class PaintArea : public QWidget
{
    Q_OBJECT
public:
    enum Shape{Dot, Line, Rectangle, RoundRect, Ellipse, Polygon, Polyline, Points, Arc, Path, Text, Pixmap};
    explicit PaintArea(QWidget *parent = nullptr);
    void setShape(Shape shape); // 设置形状
    void setPen(QPen pen); // 设置画笔
    void setBrush(QBrush brush); // 设置画刷
    void clear(); // 清除绘图区域

protected:
    void mousePressEvent(QMouseEvent *event); // 鼠标点击事件
    void mouseMoveEvent(QMouseEvent *event); // 鼠标移动事件
    void paintEvent(QPaintEvent *event); // 绘图事件

private:
    Shape m_shape; // 形状
    QPen m_pen; // 画笔
    QBrush m_brush; // 画刷

    QPixmap *m_pix; // 画布
    QPoint m_posStart; // 鼠标移动绘图的开始坐标
    QPoint m_posEnd; // 鼠标移动绘图的结束坐标
};

#endif // PAINTAREA_H

PaintArea.cpp:

#include "PaintArea.h"

PaintArea::PaintArea(QWidget *parent) :
    QWidget(parent)
{
    // 设置尺寸
    this->setMinimumSize(600, 300);

    // 用调色板设置背景色
    this->setPalette(QPalette(Qt::white));
    this->setAutoFillBackground(true);

    // 初始化画布
    m_pix = new QPixmap(size()); // 此QPixmap对象用来准备随时接收绘制的内容
    m_pix->fill(Qt::white); // 填充背景色为白色
}

// 鼠标点击事件
void PaintArea::mousePressEvent(QMouseEvent *event)
{
    m_posStart = event->pos();
}

// 鼠标移动事件
void PaintArea::mouseMoveEvent(QMouseEvent *event)
{
    QPainter *painter = new QPainter;

    // 鼠标移动绘图在画布pix上
    painter->begin(m_pix);
    painter->setPen(m_pen);

    if(m_shape == Dot)
        painter->drawLine(m_posStart, event->pos());
    else if(m_shape == Line)
        painter->drawLine(m_posStart, event->pos());

    painter->end();

    // 形状为Dot时,也就是自由绘图模式时,才时刻更新开始点击坐标
    if(m_shape == Dot)
        m_posStart = event->pos();

    this->update();
}

// 绘图事件
void PaintArea::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.drawPixmap(QPoint(0,0),*m_pix);
}

// 设置形状
void PaintArea::setShape(Shape shape)
{
    m_shape = shape;
}

// 设置画笔
void PaintArea::setPen(QPen pen)
{
    m_pen = pen;
}

// 设置画刷
void PaintArea::setBrush(QBrush brush)
{
    m_brush = brush;
}

// 清除绘图区域
void PaintArea::clear()
{
    QPixmap *clearPix  =new QPixmap(size());
    clearPix->fill(Qt::white);
    m_pix = clearPix;
    this->update();
}

四、双缓冲具体实现代码

下面是实现双缓冲区域的地方:

PaintArea::PaintArea(QWidget *parent) :
    QWidget(parent)
{
    // 设置尺寸
    this->setMinimumSize(600, 300);

    // 用调色板设置背景色
    this->setPalette(QPalette(Qt::white));
    this->setAutoFillBackground(true);

    // 初始化画布
    m_pix = new QPixmap(size()); // 此QPixmap对象用来准备随时接收绘制的内容
    m_pix->fill(Qt::white); // 填充背景色为白色
}

// 鼠标移动事件
void PaintArea::mouseMoveEvent(QMouseEvent *event)
{
    QPainter *painter = new QPainter;

    // 鼠标移动绘图在画布pix上
    painter->begin(m_pix);
    painter->setPen(m_pen);

    if(m_shape == Dot)
        painter->drawLine(m_posStart, event->pos());
    else if(m_shape == Line)
        painter->drawLine(m_posStart, event->pos());

    painter->end();

    // 形状为Dot时,也就是自由绘图模式时,才时刻更新开始点击坐标
    if(m_shape == Dot)
        m_posStart = event->pos();

    this->update();
}

// 绘图事件
void PaintArea::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.drawPixmap(QPoint(0,0), *m_pix);
}

我们不是直接在面板上画画,而且在 Pixmap 里面画画,在这里,我们调用drawPixmap()函数,将用于接收图形绘制的 QPixmap 对象绘制在绘制区窗体控件上,这样就实现了双缓冲机制。

五、代码下载

GitHub 下载地址:https://github.com/confidentFeng/QtAppProject