Qt双缓冲绘图
1. 双缓冲绘图
双缓冲绘图就是绘图时先将绘画过程的图形暂存在临时画布上,当绘制完成后一次性输出到显示设备。
2. 程序实现
下面以简单的绘画板程序为例介绍双缓冲绘图的实现。程序实现自由画线、画矩形、画线段。
首先在头文件中添加画布变量,与鼠标起始点、终点坐标变量,工作模式变量,开始绘图标志
QPixmap m_pic; //图片
QPixmap m_tempPic; //辅助画布 用于显示绘制过程
// 鼠标起始点 结束点
QPoint m_startPoint;
QPoint m_endPoint;
bool m_DrawFlag = false; //绘图标志
//工作模式
enum workMode
{
MODE_DRAW_LINE, //画线
MODE_DRAW_RECT, //画矩形
MODE_DRAW_LINES, //画线段
};
workMode m_modeFlag;//工作模式
需要重新实现鼠标事件mousePressEvent
,mouseMoveEvent
,mouseReleaseEvent
,和绘图事件paintEvent
virtual void paintEvent(QPaintEvent* e);
virtual void mouseMoveEvent(QMouseEvent* e);
virtual void mousePressEvent(QMouseEvent* e);
virtual void mouseReleaseEvent(QMouseEvent* e);
mousePressEvent
表示按下鼠标开始绘图,同时将当前图像存入临时画布m_tempPic
,所有的过程绘制都在m_tempPic
中进行。
//鼠标点击事件
void workZoneWidget::mousePressEvent(QMouseEvent* e)
{
m_startPoint = e->pos(); //获取起始点
m_DrawFlag = true; //开始绘图
//将以前pic中的内容复制到tempPic中,保证以前的内容不消失
m_tempPic = m_pic; //准备备份图片
}
mouseMoveEvent
记录每次微小移动的落点为结束点,在paintEvent
中绘制拖动过程。
//鼠标移动事件
void workZoneWidget::mouseMoveEvent(QMouseEvent* e)
{
if (e->buttons() & Qt::LeftButton) //鼠标左键按下的同时移动鼠标
{
m_endPoint = e->pos();
update(); //产生绘图事件
}
}
mouseReleaseEvent
鼠标释放表示一次绘图结束,同时记录终点,通知绘图。
//鼠标释放事件
void workZoneWidget::mouseReleaseEvent(QMouseEvent* e)
{
if (e->button() == Qt::LeftButton) //鼠标左键释放
{
m_endPoint = e->pos();
update();//产生绘图事件
m_DrawFlag = false; //结束绘图
}
}
paintEvent
绘图事件中主要是根据鼠标事件中获得的坐标在辅助画布中绘图,当绘图结束是将辅助画布中的最终图片绘制到绘图区域上。
void workZoneWidget::paintEvent(QPaintEvent* e)
{
QPainter painter(this); //显示区域画家
//设置抗锯齿
painter.setRenderHints(QPainter::SmoothPixmapTransform |
QPainter::Antialiasing);
//双缓冲绘图
int x, y, w, h; //绘制矩形相关变量
x = m_startPoint.x();
y = m_startPoint.y();
w = m_endPoint.x() - x;
h = m_endPoint.y() - y;
if (m_DrawFlag) //正在绘图
{
//如果正在绘图,就在辅助画布上绘制
//绘制的是拖动的过程
QPainter pp(&m_tempPic); //辅助画布画家
switch (m_modeFlag) //判断绘画模式
{
case MODE_DRAW_LINE: //自由绘图
pp.drawLine(m_startPoint, m_endPoint); //画线
//使结束点作为下一次的起点 画连续曲线 屏蔽为画直线段
m_startPoint = m_endPoint;
break;
case MODE_DRAW_LINES:
//用m_pic清屏 避免每次过程叠加 不适用于连续过程 如画曲线
//可以屏蔽此句看看效果
pp.drawPixmap(0, 0, m_pic);//在m_tempPic 上重绘一次 m_pic 实现清屏
pp.drawLine(m_startPoint, m_endPoint); //画线
//m_startPoint = m_endPoint;
break;
case MODE_DRAW_RECT:
//用m_pic清屏 避免每次过程叠加 不适用于连续过程 如画曲线
pp.drawPixmap(0, 0, m_pic);//在m_tempPic 重绘一次 m_pic 实现清屏
pp.drawRect(x, y, w, h); //绘制矩形
break;
}
painter.drawPixmap(0, 0, m_tempPic);//工作区显示m_tempPic 即每个拖动过程
}
else //绘制完成 刷新图片到显示设备
{
if (!m_tempPic.isNull()) //不在绘图 且辅助画布已经画过图片 即 绘画已完成
{
m_pic = m_tempPic; // 绘图过程结束 此时m_tempPic为最终绘制图像
m_tempPic = QPixmap(); //绘制完成清空备份
}
//刷新图片 到显示区域
painter.drawPixmap(0, 0, m_pic);
}
}
参考
Qt 快速入门系列教程(作者:yafeilinux):第17篇 2D绘图(七)涂鸦板
Qt 快速入门系列教程(作者:yafeilinux):第18篇 2D绘图(八)双缓冲绘图