QT关于实现paintView撤回和恢复的功能及遇到的问题总结

1.关于paintView重绘问题

正常情况只需要如下代码,解释,由于paintEvent采用了viewport()这里也使用viewport,另外由于重写的类的基类不是paintEvent,所以也尽量用viewport(),这边没有具体用代码实践过,有时间再补充

//Todo

this->viewport()->update();

此外有另外一种情况:这情况是这样的,在写绘画功能的时候,加入了双缓存绘图方法,撤回时保存的是上次lastPix,但其他条件一样,当正是画图时,不执行tempix,但是执行nowPix的重绘加之前的action,就变成了,当调用update()函数时,其实是调用了重绘函数,但是同时重绘了nowPix的action,展现的情况就是,相当于paintView没有重绘成功,因为显示是一样的。实际上,是调用updete()函数重绘成功了,但同时执行了action,所以,避免这种情况出现,需要跳过action,直接执行drawPixmap的函数。

void DrawScene::paintEvent(QPaintEvent *event)
{
    //! 双缓冲绘图,原理是在拖动过程中先把原来的图形复制到tempPix里面并在tempPix里面画,我们此时看到的就是在tempPix里的图形。只在鼠标释放的时候才在pix绘一次。

    int x, y, w, h;
    x = lasetPoint.x();
    y = lasetPoint.y();
    w = endPoint.x() - x;
    h = endPoint.y() - y;
    //! pixRect为画布大小,当mousePress的lasetPoint或mouseRelease的endPoint不在pixRect上,不执行paintView。
    if(!pixRect.contains(lasetPoint)||!pixRect.contains(endPoint)){
        return;
    }
    QPainter painter(this->viewport());
    if (isDrawing)
    {
     ...
        painter.drawPixmap(0, 0, tempPix);
    }
    else
    {
        //! 双缓存,实际画图部分
        QPainter pp(&pix);
        //! 当不是withdraw按钮,或者actionNull选择时候(除了两者其他动作,都执行withdrawGroup)
        //! 跳过action
        if(actionMode!=Withdraw && actionMode!=ActionNull){
            withdrawPix=pix;
            withdrawGroup.append(pix);
        }
        switch (actionMode) {
              ...
        case Withdraw:
            //! 执行完withdraw,马上设置为原来的actionMode
            actionMode=lastAtionMode;
            break;
        case Redraw:
            actionMode=lastAtionMode;
            break;
        }
        painter.drawPixmap(0, 0, pix);
        QVector<QPointF> nullGroup;
        pointGroup.swap(nullGroup);
    }
    QGraphicsView::paintEvent(event);
}

2.关于鼠标(point)是否落在画布上的判断

pixRect为画布大小,当mousePress的lasetPoint或mouseRelease的endPoint不在pixRect上,不执行paintView。

 if(!pixRect.contains(lasetPoint)||!pixRect.contains(endPoint)){
        return;
    }

3.关于撤回withdraw()和redraw()功能能实现

3.1withdraw():

这里代码涉及的东西有点多,主要讲述原理,和分几个步骤。

原理:用数组QVector<QPixmap>withdrawGroup记录每次action的pix,当需要退回的时候,执行withdraw(),就会退回上一次的lastPix,同时把当次的nowPix,加入到redrawGroup,当每次不是退回,而是执行其他命令时,清除redrawGroup。这基本符合要求。

一,初始化

​ 先用保存每次action的后的pix.这一步很重要,原因是,withdraw()和redraw()要配合,redrawGroup是保存withdrawGroups删除的pix,如果withdrawGroup,保存的是action前的pix,就无法用redraw()恢复到最新的,所以withdrawGroups只能保存action后的pix,这样问题就来了,由于是保存action后pix,当退回到处原始的时候,会发现是第一次action后的pix,而不是初始的pix,所以才有了这一步。

QVector<QPixmap> withdrawGroup;
withdrawGroup.append(pix);

二、withdraw()和redraw()函数

void DrawScene::withdraw()
{
    //这里判断主要是由于上一,添加的初始pix,所以退回到这里后就停止
    if(withdrawGroup.length()>1){
        //这里是改变执行的action的mode,如果不声明,会不能退回,原因是actionMode不变
        //action会重新执行的,
        //效果变成:相当于没有执行退回,
        //实际执行了退回回,但又重绘了一次
        actionMode=Withdraw;
        //先把pix加入保存复原的redrawGroup
        redrawGroup.append(pix);
        //再把在withdrawGroup中pix删去
        withdrawGroup.pop_back();
        //当前的pix等于删去最新的action的pix
        pix=withdrawGroup.last();
        //执行重绘
        this->viewport()->update();
        //当退回到初始pix,通知父界面已经不可以退回并禁用按钮
        if(withdrawGroup.length()==1){
            emit sendDraw(WithdrawOff);
        }
        //每次退回,都通知父界面恢复键可用
        emit sendDraw(RedrawOn);
    }
}

//原理基本和上面一致
void DrawScene::redraw()
{
    if(redrawGroup.length()>0){
        actionMode=Redraw;
        pix=redrawGroup.last();
        withdrawGroup.append(pix);
        redrawGroup.pop_back();
        qDebug()<<"recoverGroup.pop_back.length"<<redrawGroup.length();
        this->viewport()->update();
        if(redrawGroup.length()==0){
            emit sendDraw(RedrawOff);
        }
    }
}

三、paintView()

注意点:

  • 当actionMode为初始的actionNull时,withdrawGroup不执行对pix的保存,原因是很多事件,自动执行paintView()的重绘,如果都进行,重绘,会发现无法退回,或者需要退回非常多次,容易变成,不知道自己有没有点退回。
  • 点击事件,即使在点击界面外部仍然会执行paintView()的重绘。
//当actionMode为初始的actionNull时,不执行对pix的保存,同理,由于点击事件,几时点击界面外部  
if(actionMode!=ActionNull &&lastEndPoint!=endPoint){
            lastEndPoint=endPoint;
            withdrawPix=pix;
            withdrawGroup.append(pix);
            //qDebug()<<"backupGroup.length"<<withdrawGroup.length();
            emit sendDraw(WithdrawOn);
            if(redrawGroup.length()>0) {
                QVector<QPixmap> redrawNullGroup;
                redrawGroup.swap(redrawNullGroup);
                emit sendDraw(RedrawOff);
            }
        }
tag(s): none
show comments · back · home
Edit with Markdown