当前位置:网站首页>QT—双缓冲绘图
QT—双缓冲绘图
2022-07-04 20:49:00 【Half-up】
所谓双缓冲(double-buffers)绘图
,就是在进行绘制时,先将所有内容都绘制到一个绘图设备(如 QPixmap)上,然后再将整个图像绘制到部件上显示出来。
使用双缓冲绘图可以避免显示时的闪烁现象。
从Qt 4.0开始,QWidget部件的所有绘制都自动使用了双缓冲,所以一般没有必要在 paintEvent()函数中使用双缓冲代码来避免闪烁。
虽然在一般的绘图中无须手动使用双缓冲绘图,不过要想实现一些绘图效果,还是要借助于双缓冲的概念。
下面的程序实现使用鼠标在界面上绘制一个任意大小的矩形的功能。
这里需要两张画布,它们都是QPixmap
实例,其中一个tempPix
用来作为临时缓冲区
,当鼠标正在拖动矩形进行绘制时,将内容先绘制到tempPix
上,然后将tempPix
绘制到界面上;而另一个pix
作为缓冲区,用来保存已经完成的绘制。
当松开鼠标完成矩形的绘制后,则将tempPix
的内容复制到pix
上。
为了绘制时不显示拖影,在移动鼠标过程中,每绘制一次都要在刚开始绘制这个矩形的图像上进行绘制,所以需要在每次绘制tempPix
之前,先将pix的内容复制到tempPix 上
。
新建Qt Widgets应用,项目名称为mydoublebuffers,基类选择QWidget,类名为 Widget。
建立完成后,在 widget.h文件中添加如下内容:
private:
Ui::Widget *ui;
// 缓冲区
QPixmap pix;
// 临时缓冲区
QPixmap tempPix;
QPoint startPoint;
QPoint endPoint;
// 是否正在绘图的标志
bool isDrawing;
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
在这里定义了方法和绘画设备等
然后到widget.cpp文件中,先添加头文件
#include <QMouseEvent>
#include <QPainter>
然后到构造函数里面添加一些变量并初始化
pix = QPixmap(400, 300);
pix.fill(Qt::white);
tempPix = pix;
isDrawing = false;
pix是400,300尺寸的QPixmap设备,白色,复制给tempPix防止重影,isDrawing 关闭
下面是鼠标事件处理函数:
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
中进行绘图,然后将其绘制到界面上。
最后判断是否已经完成了绘制,如果是,则将临时缓冲区中的内容复制到缓冲区中,这样就完成了整个矩形的绘制。
这个例子中的关键是pix和 tempPix的相互复制
,如果想将这个程序进行扩展,可以查看一下网站上的涂鸦板程序。
与这个例子很相似的一个应用是橡皮筋线,就是我们在Windows桌面上拖动鼠标出现的橡皮筋选择框。Qt中提供了QRubberBand类来实现橡皮筋线,使用它只需要在几个鼠标事件处理函数中进行设置即可,具体应用可以查看该类的帮助文档。
边栏推荐
猜你喜欢
torch. Tensor and torch The difference between tensor
How to implement Devops with automatic tools
Analyzing the maker space contained in steam Education
Three or two things about the actual combat of OMS system
【C語言】符號的深度理解
Case sharing | integrated construction of data operation and maintenance in the financial industry
改善机器视觉系统的方法
OMS系统实战的三两事
Keep on fighting! The city chain technology digital summit was grandly held in Chongqing
How was MP3 born?
随机推荐
WGCNA analysis basic tutorial summary
历史最全混合专家(MOE)模型相关精选论文、系统、应用整理分享
杰理之AD 系列 MIDI 功能说明【篇】
__ init__ () missing 2 required positive arguments
Flutter在 release版本,打开后随机白屏不显示内容
每日一题-LeetCode556-下一个更大元素III-字符串-双指针-next_permutation
Compréhension approfondie du symbole [langue C]
Super detailed tutorial, an introduction to istio Architecture Principle and practical application
华为ensp模拟器 给路由器配置DHCP
【C語言】符號的深度理解
旋变串判断
Golang interview finishing three resumes how to write
【C语言】符号的深度理解
2021 CCPC 哈尔滨 I. Power and Zero(二进制 + 思维)
Flutter WebView示例
杰理之AD 系列 MIDI 功能说明【篇】
redis RDB AOF
Huawei ENSP simulator configures DHCP for router
For MySQL= No data equal to null can be found. Solution
Three or two things about the actual combat of OMS system