• 12239阅读
  • 7回复

十九、Qt 2D绘图(九)双缓冲绘图简介(原创) [复制链接]

上一主题 下一主题
离线yafei86
 
只看楼主 倒序阅读 楼主  发表于: 2010-02-13
声明:本文原创于yafeilinux的百度博客,http://hi.baidu.com/yafeilinux 转载请注明出处。

上面一节我们实现了涂鸦板的功能,但是如果我们想在涂鸦板上绘制矩形,并且可以动态地绘制这个矩形,也就是说我们可以用鼠标画出随意大小的矩形,那该怎么办呢?
我们先进行下面的三步,最后引出所谓的双缓冲绘图的概念。

第一步:
我们更改上一节的那个程序的重绘函数。
void Dialog::paintEvent(QPaintEvent *)
{  
    QPainter painter(this);
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    painter.drawRect(x,y,w,h);

}

然后运行,效果如下。

这时我们已经可以拖出一个矩形了,但是这样直接在窗口上绘图,以前画的矩形是不能保存住的。所以我们下面加入画布,在画布上进行绘图。


第二步:
我们先在构造函数里将画布设置大点:pix = QPixmap(400,400);
然后更改函数,如下:
void Dialog::paintEvent(QPaintEvent *)
{  
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    QPainter pp(&pix);
    pp.drawRect(x,y,w,h);

    QPainter painter(this);
    painter.drawPixmap(0,0,pix);
}

这时运行程序,效果如下:

现在虽然能画出矩形,但是却出现了无数个矩形,这不是我们想要的结果,我们希望能像第一步那样绘制矩形,所以我们再加入一个临时画布。



第三步:
首先,我们在dialog.h中的private里添加变量声明:
QPixmap tempPix; //临时画布
bool isDrawing;   //标志是否正在绘图

然后在dialog.cpp中的构造函数里进行变量初始化:
isDrawing = false;
最后更改函数如下:
void Dialog::paintEvent(QPaintEvent *)
{  
    int x,y,w,h;
    x = lastPoint.x();
    y = lastPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;

    QPainter painter(this);
    if(isDrawing)     //如果正在绘图
    {
        tempPix = pix;    //将以前pix中的内容复制到tempPix中,这样实现了交互绘图
        QPainter pp(&tempPix);
        pp.drawRect(x,y,w,h);
        painter.drawPixmap(0,0,tempPix);
    }
    else
    {
        QPainter pp(&pix);
        pp.drawRect(x,y,w,h);
        painter.drawPixmap(0,0,pix);
    }
}

void Dialog::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton) //鼠标左键按下
    {
        lastPoint = event->pos();
        isDrawing = true;   //正在绘图
    }
}

void Dialog::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons()&Qt::LeftButton) //鼠标左键按下的同时移动鼠标
    {
        endPoint = event->pos();
        update();
    }
}
void Dialog::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) //鼠标左键释放
    {
        endPoint = event->pos();
        isDrawing = false;    //结束绘图
        update();
    }
}

我们使用两个画布,就解决了绘制矩形等图形的问题。
其中tempPix = pix;一句代码很重要,就是它,才实现了消除那些多余的矩形。

双缓冲绘图简介:
根据我的理解,如果将第一步中不用画布,直接在窗口上进行绘图叫做无缓冲绘图,那么第二步中用了一个画布,将所有内容都先画到画布上,在整体绘制到窗口上,就该叫做单缓冲绘图,那个画布就是一个缓冲区。这样,第三步,用了两个画布,一个进行临时的绘图,一个进行最终的绘图,这样就叫做双缓冲绘图。
我们已经看到,利用双缓冲绘图可以实现动态交互绘制。其实,Qt中所有部件进行绘制时,都是使用的双缓冲绘图。就算是第一步中我们没有用画布,Qt在进行自身绘制时也是使用的双缓冲绘图,所以我们刚才那么说,只是为了更好地理解双缓冲的概念。

----------------------------------------------------------------------------------------------------------
到这里,我们已经可以进行一些Qt 2D绘图方面的设计了。我这里有两个例子,一个是那个绘图软件(链接到那里),它是实践了我所讲的这几节的内容,可以说是对这几节内容的一个综合。还有一个例子,就是俄罗斯方块程序(链接到那里),那个是对这些知识的应用。如果你有兴趣,可以看一下。
欢迎访问我们的网站:www.yafeilinux.com
离线liyayao

只看该作者 1楼 发表于: 2010-02-14
太好了。。。。
离线yashika

只看该作者 2楼 发表于: 2010-03-24
有不采用事件通知和重载paintEvent的方法进行绘图的DEMO代码吗?这样的话似乎帧数还能提高不少哦.
离线forestarmy

只看该作者 3楼 发表于: 2010-04-06
引用第2楼yashika于2010-03-24 12:04发表的  :
有不采用事件通知和重载paintEvent的方法进行绘图的DEMO代码吗?这样的话似乎帧数还能提高不少哦.


我在QT3中见过这样使用的,但是QT4中没有,同问啊
离线断弦0205
只看该作者 4楼 发表于: 2013-01-15
qt设置Mainwindow背景颜色
qt设置Mainwindow背景颜色,为什么设置的背景覆盖了我画的图像
离线jdwx

只看该作者 5楼 发表于: 2013-01-15
回 4楼(断弦0205) 的帖子
既然都画图了,为什么还设置背景图像,背景图像直接画出来,不是更好。
发帖时要说明:操作系统、Qt版本、编译器,这样能更快的得到回复。
离线orafy

只看该作者 6楼 发表于: 2013-01-15
Qt中如果用QWidget不需要双缓冲啊,自带backing store...
离线xingkongn
只看该作者 7楼 发表于: 2013-02-19
我想通过读取txt文件中的数据获得双缓冲曲线图形,其中,已经绘制了图形,但是调用open事件还不能出现曲线界面
快速回复
限100 字节
 
上一个 下一个