双缓冲绘图
在Qt4中,所有的窗口部件默认都使用双缓冲进行绘图。使用双缓冲,可以减轻绘制的闪烁感。在有些情况下,用户要关闭双缓冲,自己管理绘图。下面的语句设置了窗口部件的Qt::WA_PaintOnScreen属性 ,就关闭了窗口部件的双缓冲.
mywidget->setAttribute(Qt::WA_PaintOnScreen);

由于Qt4不再提供异或笔,组合模式QPainter::CompostionMode_Xor()并不是异或笔,Qt4只提供了QRubberBand实现矩形和直线的绘图反馈。因此要实现在绘图中动态
反馈必须使用其他方法。程序中使用双环冲来解决这个问题。在绘图过程中,一个缓冲区绘制临时内存,一个缓冲区保存绘制好的内容,最后进行合并。
在交互绘图过程中,程序将图像缓冲区复制到临时缓冲区,并在临时缓冲区上绘制,绘制完毕在将结果复制到图像缓冲区,如果没有交互复制,则直接将图像缓冲区绘制显示到屏幕上。

Qt组件中的双缓冲无闪烁绘图
闪烁首先,要想把闪烁减弱,请设置组件的背景模式为NoBackground. 
setBackgroundMode(NoBackground);

其次,重载组件的paintEvent()函数,如下改写: 
void MyWidget::paintEvent(QPaintEvent *e) 

QRect ur=e->rect();//得到组件尺寸 
QPixmap pix(ur.size());//以此为参数创建一个位图变量 
pix.fill(this,ur.topLeft());//填充位图 
QPainter p(&pic);//以位图为参数创建一个QPainter 对象

p.translate(-ur.x(),-ur.y());//在QPainter 上绘画 
//......//Drawing

p.End();//绘画完毕

bitBlt(this,ur.topLeft().&pix);//把位图贴到组件上

//注从qt4开始,bitBlt函数不在使用,取而代之的是drawPixmap。
}

// 这是能随机绘点的关键,没有设置此属性,默认相当于每次Qt都会完整的将上一次的屏幕擦除,

// 新版的Qt中已经没有了repaint(bool)接口了。

w.setAttribute(Qt::WA_OpaquePaintEvent);

老电视机雪花效果中每次都需要擦除重绘避免点的叠加所以一下语句注释掉

//    w.setAttribute(Qt::WA_OpaquePaintEvent);

(

以下是私有函数的实现:

void Plotter::updateRubberBandRegion()

{

QRect rect = rubberBandRect.normalized();

    update(rect.left(), rect.top(), rect.width(), 1);
    update(rect.left(), rect.top(), 1, rect.height());
    update(rect.left(), rect.bottom(), rect.width(), 1);
    update(rect.right(), rect.top(), 1, rect.height());
}
函数updateRubberBand()在mousePressEvent(),mouseMoveEvent()和mouseReleaseEvent()中被调用,用来删除或者重新绘制橡皮线。函数中调用了四次update(),用四个绘制事件完成由橡皮线(两条垂直和水平的线)组成的四个小矩形的绘制。Qt也提供了一个类QRubberBand用来绘制橡皮线,但是控件自己提供的绘制函数会更好
void Plotter::refreshPixmap()
{
    pixmap = QPixmap(size());
    pixmap.fill(this, 0, 0);
    QPainter painter(&pixmap);
    painter.initFrom(this);
    drawGrid(&painter);
    drawCurves(&painter);
    update();
}
函数refreshPixmap()把plot绘制到图片上,并且更新显示。首先我们把图片的大小调整为和当前控件大小相同,然后用控件的背景颜色填充整个图片。这个颜色是当前调色版的“dark”部分,因为在Plotter构造函数中调用setBackgroundRole() 。如果背景用的刷子是非实心的(solid brush,刷子的样式,只有颜色,没有花纹的那种最简单的),QPixmap::fill()需要知道控件中刷子的偏移量,以便图片对齐刷子模式。这里图片对应整个控件,因此偏移位置为(0,0)。
接下来我们创建了一个QPainter对象来绘制图片,QPainter::initFrom()设置绘制图片所需画笔,背景和字体,参数this表示这些设置和Plotter控件的相应设置是一致的。然后我们调用drawGrid(),drawCurves()绘制网格和曲线。最后,update()函数安排整个控件的绘制事件,在painteEvent()函数中把图片拷贝到控件上。
void Plotter::drawGrid(QPainter *painter)
{
   QRect rect(Margin, Margin,
               width() - 2 * Margin, height() - 2 * Margin);
    if (!rect.isValid())
        return;
    PlotSettings settings = zoomStack[curZoom];
    QPen quiteDark = palette().dark().color().light();
    QPen light = palette().light().color();
    for (int i = 0; i <= settings.numXTicks; ++i) {
        int x = rect.left() + (i * (rect.width() - 1)
                                 / settings.numXTicks);
        double label = settings.minX + (i * settings.spanX()
                                           / settings.numXTicks);
        painter->setPen(quiteDark);
        painter->drawLine(x, rect.top(), x, rect.bottom());
        painter->setPen(light);
        painter->drawLine(x, rect.bottom(), x, rect.bottom() + 5);
       painter->drawText(x - 50, rect.bottom() + 5, 100, 15,
                          Qt::AlignHCenter | Qt::AlignTop,
                          QString::number(label));
    }
    for (int j = 0; j <= settings.numYTicks; ++j) {
        int y = rect.bottom() - (j * (rect.height() - 1)
                                   / settings.numYTicks);
        double label = settings.minY + (j * settings.spanY()
                                          / settings.numYTicks);
        painter->setPen(quiteDark);
        painter->drawLine(rect.left(), y, rect.right(), y);
        painter->setPen(light);
        painter->drawLine(rect.left() - 5, y, rect.left(), y);
        painter->drawText(rect.left() - Margin, y - 10, Margin - 5, 20,
                          Qt::AlignRight | Qt::AlignVCenter,
                          QString::number(label));
    }
    painter->drawRect(rect.adjusted(0, 0, -1, -1));
}
函数drawGrid()在坐标轴和曲线的下面绘制网格。这个区域由一个矩形确定,如果控件太小,则不绘制立即返回。第一个循环绘制网格的垂直线,及沿x坐标轴的刻度。第二个循环绘制网格的水平线,及沿y坐标轴的刻度。最后,沿边界绘制一个矩形。drawText()绘制数字,对应两个坐标轴上刻度的标记。
函数painter->drawText()语法如下:
painter->drawText(x, y, width, height, alignment, text);
其中(x,y,width,height)所确定的矩形,alignment确定文字在矩形中的位置。
void Plotter::drawCurves(QPainter *painter)
{
    static const QColor colorForIds[6] = {
        Qt::red, Qt::green, Qt::blue, Qt::cyan, Qt::magenta, Qt::yellow
    };
    PlotSettings settings = zoomStack[curZoom];
    QRect rect(Margin, Margin,
               width() - 2 * Margin, height() - 2 * Margin);
    if (!rect.isValid())
        return;
    painter->setClipRect(rect.adjusted(+1, +1, -1, -1));
    QMapIterator<int, QVector<QPointF> > i(curveMap);
    while (i.hasNext()) {
        i.next();
        int id = i.key();
        const QVector<QPointF> &data = i.value();
        QPolygonF polyline(data.count());
        for (int j = 0; j < data.count(); ++j) {
            double dx = data[j].x() - settings.minX;
            double dy = data[j].y() - settings.minY;
            double x = rect.left() + (dx * (rect.width() - 1)
                                          / settings.spanX());
            double y = rect.bottom() - (dy * (rect.height() - 1)
                                           / settings.spanY());
            polyline[j] = QPointF(x, y);
        }
        painter->setPen(colorForIds[uint(id) % 6]);
        painter->drawPolyline(polyline);
    }
}
函数drawCurves()在网格的上层绘制曲线。调用了QPainter::setClipRect()函数设置QPainter的剪切区域为包含曲线的矩形区域(不包括四周的间隙和图片的外框)。QPainter会忽略这个区域外的象素。
然后我们使用Java风格的迭代器,遍历所有的曲线,对每一条曲线,遍历它所有的QPointF点。函数key()得到曲线的id,value()函数得到曲线的QVector<QPointF>类型的数据。内层循环把每个QPointF记录的plotter坐标转换为控件坐标,把结果保存在polyline变量中。

转换坐标后,我们设置画笔的颜色(使用函数前面预定义的颜色),调用drawPolyline()绘制曲线,经过所有的曲线上的点。

http://blog.csdn.net/Last_Impression/archive/2008/05/20/2463647.aspx

Qt组件中的双缓冲无闪烁绘图的更多相关文章

  1. C++零食:WTL中使用双缓冲避免闪烁

    双缓冲的原理可以这样形象的理解:把电脑屏幕看作一块黑板.首先我们在内存环境中建立一个"虚拟"的黑板,然后在这块黑板上绘制复杂的图形,等图形全部绘制完毕的时候,再一次性的把内存中绘制 ...

  2. C#中利用双缓冲技术解决绘图闪屏问题。

    这段时间在做一个小型游戏,在界面显示的时候用到了一些图形.一开始涉及到的图形全都用控件的背景图片代替了.这样游戏运行的时候存在的一个很大的问题是游戏运行很慢.小组成员费尽周折,即将放弃,每一个成员都愁 ...

  3. OpenGL中实现双缓冲技术

    在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | G ...

  4. MFC中的双缓冲技术(解决绘图闪烁问题)

    转自 MFC绘图不闪烁——双缓冲技术[转] 在VC/MFC用CDC绘图时,频繁的刷新,屏幕会出现闪烁的现象,CPU时间占用率相当高,绘图效率极低,很容易出现程序崩溃. 所谓双缓冲技术,下面是百度百科的 ...

  5. C#中使用双缓冲来避免绘制图像过程中闪烁

    自己所做项目中,在显示医学图像的界面中,当鼠标拖动图像时,不断刷新从后台获取新的图像,而整个过程就很诡异,一直闪个不停. 找到的一个可行方法是:在用户控件的构造函数中加入以下代码: SetStyle( ...

  6. [Qt2D绘图]-06QPainter的复合模式&&双缓冲绘图&&绘图中的其他问题

    本篇读书笔记主要记录QPainter的复合模式&&双缓冲绘图&&绘图中的其他问题   大纲:     复合模式     双缓冲绘图     绘图中的其他问题       ...

  7. VC使用双缓冲避免绘图闪烁的正确使用方法【转】

    使用内存DC绘图,然后实现双缓冲,避免绘图闪烁,这个小技术简单但很有效.但是仍然有很多人说使用了双缓冲,图片却仍然有闪烁,分析了几个这样的例子,发现 其实不是双缓冲的技术问题,而是使用者没有正确理解和 ...

  8. C# GDI+双缓冲技术

    我想有很多搞图形方面的朋友都会用到双缓冲技术的时候,而且有的时候她的确是个头疼的问题.最近我也要用双缓冲技术,程序怎么调试都不合适,当要对图形进行移动时,总是会出现闪烁抖动.在网上找了些资料,说得都不 ...

  9. java的双缓冲技术

    Java的强大特性让其在游戏编程和多媒体动画处理方面也毫不逊色.在Java游戏编程和动画编程中最常见的就是对于屏幕闪烁的处理.本文从J2SE的一个再现了屏幕闪烁的Java Appilication简单 ...

随机推荐

  1. 第二百零四天 how can i 坚持

    我应该不会看错吧.最近媒体热炒小米衰落了,有必要那么大张旗鼓的报道吗?小米.华为,坚决看好小米.感觉华为品牌有些杂乱,在走三星的老路,小米有些苹果的影子,但是,多了个互联网.互联网... 未来孰优孰劣 ...

  2. <<海闻电子发票接口 ESB 封装文档>>

    <<海闻电子发票接口 ESB 封装文档>> 章节目录结构: 发票验证接口 发票开具接口 ESB请求地址: 发票验证接口: http://10.15.22.120:8866/42 ...

  3. Spring中的BeanUtils与apache commons中的BeanUtils用法[1]

    1. 前言 在开发过程中,经常遇到把要给一个bean的属性赋给另外一个bean.最笨的方法是每个属性都单独写一个,聪明的方法是应用反射写一个工具方法.考虑到这个需求基本每个程序员都会遇到,那么一定已经 ...

  4. [iOS微博项目 - 2.6] - 获取微博数据

    github: https://github.com/hellovoidworld/HVWWeibo   A.新浪获取微博API 1.读取微博API     2.“statuses/home_time ...

  5. Python基础 数字、字符串、列表、元组、字典

    Number(数字)---> int.float.complex(复数) class int 在Python3中,整形(int)就是常见的整数:1,100,500,1000...... 浮点型( ...

  6. How Tomcat Works(三)

    上文中描述的简单的服务器是不符合Servlet规范的,所以本文进一步描述一个简单的Servlet容器是怎么实现的 所以我们首先要明白Servlet接口规范,规范有不同版本,本人就先一视同仁了: pub ...

  7. mongodb的查询方式与sql语句对比

    下面是sql和Mongodb对应的一些语法: SQL Statement Mongo Query Language Statement CREATE TABLE USERS (a Number, b ...

  8. UI:数据持久化

    数据持久化    参考1  参考2  参考3 什么是数据持久化,就是将文件保存在本地的硬盘中,使得应用程序或者机器重启后可以继续访问以前保留的数据.IOS开发中有许多的数据持久化方案. 如下面五种方案 ...

  9. MVC的System.Web.Mvc.ViewPage小结

    Inherits="System.Web.Mvc.ViewPage<dynamic>这一句最好是自己手动修改,如果是维护用户数据,用户对象名是User,改成Inherits=&q ...

  10. 本地存储(cookie&sessionStorage&localStorage)

    好文章,最全面.就查它吧:https://segmentfault.com/a/1190000004556040 1.DOM存储:https://developer.mozilla.org/zh-CN ...