所谓双缓冲绘图,就是在进行绘制时,先将所有内容都绘制到一个绘图设备(如QPixmap)上,然后再将整个图像绘制到部件上显示出来。使用双缓冲绘图可以避免显示时的闪烁现象。
从Qt4.0开始,QWidget部件上所有的绘制都自动使用了双缓冲,所以一般不需要在paintEvent()函数中使用双缓冲代码来避免绘制时的闪烁现象。
但是在实现一些绘图效果时,还是要借助于双缓冲的概念。
下面的程序将使用两个缓冲区实现双缓冲绘图效果:
widget.h头文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void mousePressEvent(QMouseEvent * event); //鼠标按下事件
void mouseMoveEvent(QMouseEvent * event); //鼠标移动事件
void mouseReleaseEvent(QMouseEvent * event); //鼠标释放事件
void paintEvent(QPaintEvent * event);
private:
Ui::Widget *ui;
QPixmap pix; //缓冲区
QPixmap tempPix; //临时缓冲区
QPoint startPoint;
QPoint endPoint;
bool isDrawing; //是否正在绘图的标志
};
#endif // WIDGET_H
widget.cpp源文件:
#include "widget.h"
#include "ui_widget.h"
#include<QMouseEvent>
#include<QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
pix = QPixmap(400,300);
pix.fill(Qt::white);
tempPix = pix;
isDrawing = false;
}
Widget::~Widget()
{
delete ui;
}
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton){
startPoint = event->pos(); //获取鼠标左键位置作为矩形的开始点
isDrawing = true; //标记正在绘图
}
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons()&Qt::LeftButton){
endPoint = event->pos(); //当鼠标移动时以当前位置为结束点
tempPix = pix; //将缓冲区内容复制到临时缓冲区,避免产生拖影现象
update(); //更新
}
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton){
endPoint = event->pos(); //以鼠标当前位置为结束点
isDrawing = false; //标记已经完成绘图
update(); //更新显示
}
}
void Widget::paintEvent(QPaintEvent *event)
{
int x = startPoint.x();
int y = startPoint.y();
int width = endPoint.x() - x;
int height = endPoint.y() - y;
QPainter painter;
painter.begin(&tempPix);
painter.drawRect(x,y,width,height);
painter.end();
painter.begin(this);
painter.drawPixmap(0,0,tempPix);
if(!isDrawing) pix = tempPix; //完成绘制时更新缓冲区
}
该程序实现的是在画布上绘制矩形,程序先将内容绘制到tempPix上,然后将tempPix绘制到界面上;而另一个pix作为缓冲区,用来保存已经完成的绘制。
注意:在移动鼠标过程中,为了避免显示拖影现象,需要每绘制一次都要在刚开始绘制的图像上进行绘制,所以需要将pix的内容复制到tempPix上。