Qt中update()和repaint()的区别

解释1

voidQWidget::repaint ( int x, int y, int w, int h, bool erase = TRUE ) [槽]

通过立即调用paintEvent()来直接重新绘制窗口部件,如果erase为真,Qt在paintEvent()调用之前擦除区域(x,y,w,h)。 

如果w是负数,它被width()-x替换,并且如果h是负数,它被height()-y替换。 如果你需要立即重新绘制,建议使用repaint(),

比如在动画期间。在绝大多数情况下,update()更好,因为它允许Qt来优化速度并且防止闪烁。 

警告:如果你在一个函数中调用repaint(),而它自己又被paintEvent()调用,你也许会看到无线循环。

update()函数从来不会产生循环。

void QWidget::update () [槽]

更新窗口部件,当Qt回到主事件中时,它规划了所要处理的绘制事件。这样允许Qt进行优化从而得到比调用repaint()更快的速度和

更少的闪烁。 几次调用update()的结果通常仅仅是一次paintEvent()调用。 Qt通常在paintEvent()调用之前擦除这个窗口部件的区域,仅仅只有在WRepaintNoErase窗口部件标记被设置的时候才不会。

在这区别中关键点是:repaint()是立即调用paintEvent(),而update()是几次执行才调用一次paintEvent()。

这样update()会造成这样的结果:paintEvent()中的任务没有执行完,就又被update().paintEvent()中被积压的任务越来越多。

程序例子:

(1)问题出现时候的情况(10毫秒每次,用update()。paintEvent()积累了很多处理任务):

#include

#include

#include

#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

    this->showMaximized();

    i = 0;

    realWidth = this->width();

    realHeight = this->height();

    pixmap =QPixmap(realWidth,realHeight);

   connect(this,SIGNAL(haveData(QPoint)),this,SLOT(getPointAndDraw(QPoint)));

   connect(&timer,SIGNAL(timeout()),this,SLOT(getPoint()));

    timer.start(10);

}

MainWindow::~MainWindow()

{

    delete ui;

}

void MainWindow::getPoint()

{

    if(i < realWidth)

    {

        point =QPoint(i,(uint(qrand())) % realHeight);

        i++;

    }

    else

    {

        i = i % realWidth;

        point =QPoint(i,(uint(qrand())) % realHeight);

        i++;

    }

    emit haveData(point);

}

void MainWindow::getPointAndDraw(QPoint point)

{

    index = point.x();

    QPainter painter(&pixmap);

    painter.setPen(Qt::green);

    painter.drawLine(lastPoint,point);

    painter.setPen(Qt::black);

    painter.setBrush(Qt::red);

   painter.drawRect(index+1,0,5,realHeight);

    if(point.x() < realWidth-1)

        lastPoint = point;

    else

        lastPoint =QPoint(0,0);

  update();

  // this->repaint(index-1,0,5,realHeight);

}

void MainWindow::paintEvent(QPaintEvent *e)

{

    //return ;

    QPainter painter(this);

    QRect target1(0, 0, realWidth,realHeight/5);

    QRect target2(0, realHeight/5,realWidth, realHeight/5);

    QRect target3(0, 2*realHeight/5,realWidth, realHeight/5);

    QRect target4(0, 3*realHeight/5,realWidth, realHeight/5);

    QRect target5(0, 4*realHeight/5,realWidth, realHeight/5);

    QRect source(0, 0, realWidth,realHeight);

   painter.drawPixmap(target1,pixmap,source);

    painter.drawPixmap(target2,pixmap,source);

   painter.drawPixmap(target3,pixmap,source);

   painter.drawPixmap(target4,pixmap,source);

   painter.drawPixmap(target5,pixmap,source);

}

void MainWindow::resizeEvent(QResizeEvent *e)

{

    realWidth = this->width();

    realHeight = this->height();

}

void MainWindow::changeEvent(QEvent *e)

{

    QMainWindow::changeEvent(e);

    switch (e->type()) {

    case QEvent::LanguageChange:

       ui->retranslateUi(this);

        break;

    default:

        break;

    }

}

(2)每隔1000毫秒刷新一次,用update().一秒种有足够的时间处理paintEvent(),无积累。

#include

#include

#include

#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

    this->showMaximized();

    i = 0;

    realWidth = this->width();

    realHeight = this->height();

    pixmap =QPixmap(realWidth,realHeight);

   connect(this,SIGNAL(haveData(QPoint)),this,SLOT(getPointAndDraw(QPoint)));

   connect(&timer,SIGNAL(timeout()),this,SLOT(getPoint()));

    timer.start(1000);

}

MainWindow::~MainWindow()

{

    delete ui;

}

void MainWindow::getPoint()

{

    if(i < realWidth)

    {

        point =QPoint(i,(uint(qrand())) % realHeight);

        i++;

    }

    else

    {

        i = i % realWidth;

        point =QPoint(i,(uint(qrand())) % realHeight);

        i++;

    }

    emit haveData(point);

}

void MainWindow::getPointAndDraw(QPoint point)

{

    index = point.x();

    QPainter painter(&pixmap);

    painter.setPen(Qt::green);

    painter.drawLine(lastPoint,point);

    painter.setPen(Qt::black);

    painter.setBrush(Qt::red);

   painter.drawRect(index+1,0,5,realHeight);

    if(point.x() < realWidth-1)

        lastPoint = point;

    else

        lastPoint =QPoint(0,0);

 update();

  //this->repaint(index-1,0,5,realHeight);

}

void MainWindow::paintEvent(QPaintEvent *e)

{

    //return ;

    QPainter painter(this);

    QRect target1(0, 0, realWidth,realHeight/5);

    QRect target2(0, realHeight/5, realWidth,realHeight/5);

    QRect target3(0, 2*realHeight/5,realWidth, realHeight/5);

    QRect target4(0, 3*realHeight/5,realWidth, realHeight/5);

    QRect target5(0, 4*realHeight/5,realWidth, realHeight/5);

    QRect source(0, 0, realWidth,realHeight);

   painter.drawPixmap(target1,pixmap,source);

   painter.drawPixmap(target2,pixmap,source);

   painter.drawPixmap(target3,pixmap,source);

   painter.drawPixmap(target4,pixmap,source);

   painter.drawPixmap(target5,pixmap,source);

}

void MainWindow::resizeEvent(QResizeEvent *e)

{

    realWidth = this->width();

    realHeight = this->height();

}

void MainWindow::changeEvent(QEvent *e)

{

    QMainWindow::changeEvent(e);

    switch (e->type()) {

    case QEvent::LanguageChange:

        ui->retranslateUi(this);

        break;

    default:

        break;

    }

}

(3)继续改进(10毫秒每次,用repaint()。一次repaint(),一次paintEvent(),无积累).

#include

#include

#include

#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

    this->showMaximized();

    i = 0;

    realWidth = this->width();

    realHeight = this->height();

    pixmap =QPixmap(realWidth,realHeight);

    connect(this,SIGNAL(haveData(QPoint)),this,SLOT(getPointAndDraw(QPoint)));

   connect(&timer,SIGNAL(timeout()),this,SLOT(getPoint()));

    timer.start(10);

}

MainWindow::~MainWindow()

{

    delete ui;

}

void MainWindow::getPoint()

{

    if(i < realWidth)

    {

        point =QPoint(i,(uint(qrand())) % realHeight);

        i++;

    }

    else

    {

        i = i % realWidth;

        point =QPoint(i,(uint(qrand())) % realHeight);

        i++;

    }

    emit haveData(point);

}

void MainWindow::getPointAndDraw(QPoint point)

{

    index = point.x();

    QPainter painter(&pixmap);

    painter.setPen(Qt::green);

    painter.drawLine(lastPoint,point);

    painter.setPen(Qt::black);

    painter.setBrush(Qt::red);

   painter.drawRect(index+1,0,5,realHeight);

    if(point.x() < realWidth-1)

        lastPoint = point;

    else

        lastPoint =QPoint(0,0);

   this->repaint(index-1,0,5,realHeight);

}

void MainWindow::paintEvent(QPaintEvent *e)

{

    //return ;

    QPainter painter(this);

    QRect target1(0, 0, realWidth,realHeight/5);

    QRect target2(0, realHeight/5,realWidth, realHeight/5);

    QRect target3(0, 2*realHeight/5,realWidth, realHeight/5);

    QRect target4(0, 3*realHeight/5,realWidth, realHeight/5);

    QRect target5(0, 4*realHeight/5,realWidth, realHeight/5);

    QRect source(0, 0, realWidth,realHeight);

   painter.drawPixmap(target1,pixmap,source);

   painter.drawPixmap(target2,pixmap,source);

   painter.drawPixmap(target3,pixmap,source);

   painter.drawPixmap(target4,pixmap,source);

    painter.drawPixmap(target5,pixmap,source);

}

void MainWindow::resizeEvent(QResizeEvent *e)

{

    realWidth = this->width();

    realHeight = this->height();

}

void MainWindow::changeEvent(QEvent *e)

{

    QMainWindow::changeEvent(e);

    switch (e->type()) {

    case QEvent::LanguageChange:

       ui->retranslateUi(this);

        break;

    default:

        break;

    }

}

 

解释2

Qt里面的重绘和Windows编程里面的重绘差不多。但是Qt的重绘更有特色,更加智能。

 

在讲之前,先说说paintEvent()

paintEvent()是一个虚函数槽(slot),子类可以对父类的paintEvent进行重写。当调用update()repaint()的时候,paintEvent()会被调用,另外,当界面有任何改变的时候,paintEvent()也会被调用,这种界面的改变包括界面从隐藏到显示,界面尺寸改变,当然还包括界面内容改变的时候会被调用。paintEvent()是已经被高度优化过的函数,它本身已经自动开启并实现了双缓冲(X11系统需要手动去开启双缓冲),因此Qt中重绘不会引起任何闪烁。

X11系列系统手动开启双缓冲的方法如下:

[cpp] view plaincopyprint?

1.  ...  

2.   extern void qt_x11_set_global_double_buffer(bool);  

3.   qt_x11_set_global_double_buffer(false);  

4.   ...  

 

 

有了paintEvent的知识,现在再来看看update()repaint()

updaterepaint是一类的,需要重绘的对象主动去调用,然后重绘。updaterepaint调用之后,都回去调用paintEvent().

 

 

repaint(),被调用之后,立即执行重绘,因此repaint是最快的,紧急情况下需要立刻重绘的可以使用repaint()。但是调用repaint的函数不能放到paintEvent中调用。举个例子:有一个继承于QWidget的子类MyWidget,并在子类中对paintEvent进行了重写。我们在MyWidget::myrepaint()中调用repaint()。但是,myrepaint()又被重写的paintEvent()调用。这样调用repaint()的函数又被paintEvent()调用,由于repaint()是立即重绘,而且repaint()在调用paintEvent之前几乎不做任何优化操作,而是会造成死循环,即:先调用repaint(),继而调用paintEvent()paintEvent()反过来有调用repaint()...如此死循环。

 

update()repaint()比较,update则更加有优越性。update()调用之后并不是立即重绘,而是将重绘事件放入主消息循环中,由mainevent loop来统一调度的(其实也是比较快的)update在调用paintEvent之前,还做了很多优化,如果update被调用了很多次,最后这些update会合并到一个大的重绘事件加入到消息队列,最后只有这个大的update被执行一次。同时也避免了repaint()中所提到的死循环。因此,一般情况下,我们调用update就够了,跟repaint()比起来,update是推荐使用的。

 


 

你可能感兴趣的:(QT)