Qt学习之路-简易画板3(双缓冲绘图)

首先说明双缓冲不能用在使用画笔或者橡皮擦的时候,学习完之后就能理解了,如果我们不使用双缓冲绘图,我们画矩形,椭圆等就会出现bug情况。

不是双缓冲即只有一个image画布,直接在上面作图。在我们的鼠标移动事件里,移动鼠标会更新结束点,注意这个时候我们的起点并没有改变,既鼠标按下在哪儿,起点就在哪儿,鼠标移动事件调用paint(image)函数将图形画在image画布上,,现在我们想一想会出现什么bug,对,会出现无数个图形,这个时候我们的图形如下:


看懂了吗?看懂了我们就可以接着往下走了。


现在我们学习双缓冲制图,双缓冲的优点是可以在画直线,矩形,椭圆等图形的时候移动鼠标时只让用户看到痕迹并且在鼠标释放后才生成图形,那么我们就得明白它的原理是什么。

首先你想象有两张空白画板QImage image和QImage tempImage(QPixmap也一样,都是画布),现在两张画板上什么都没有。

1.按鼠标,移动画图,现在你看到画的的图形是在tempImage上,image待机.

2.松开鼠标,将tempImage上的图形复制到image上,但是tempImage上的图形并没有消失,因为它不是临时变量,这时看到的图形其实就是image和tempImage上两张图重合在一起的图像。

3.按下鼠标再次绘图(这时image和tempImage上都有刚才画好的图了哟既历史记录都保存了下来),这时的图又画在tempImage上,此时image待机,松开鼠标,tempImage的图形又画在了image上.

现在我们可以总结出这样做的特点就是tempImage总是领先image一个图形。那么这样有什么用呢?我们想一下画图的时候移动鼠标,这时并不会改变lastPoint(既起点)的值,而是更新endPoint(终点)的值,我们每移动一下,就会调用paint(tempImage)把图画在tempImage显现出来,然而这是我们不希望的,那么怎么办呢?这时image画布就发挥作用了,image因为只在鼠标释放时才复制下tempImage上的图,所以你现在移动鼠标只是在tempImage上的某个区域绘制图形,而这个区域image上并没有任何图形。这时把image复制给tempImage,那么在tempImage上这块区域也变成空白的了,但是这时tempImage里保存着lastPoint与endPoint,所以就会在tempImage上画出唯一的一个图形。松开鼠标,image上也保存下来了。专业人士称之为交叉绘图。


现在我们回到开头,应该就能明白双缓冲不能在画笔或者橡皮擦上的原因了,因为画过的痕迹不会被保留,只有最后释放鼠标时才会成图,所以最后只会有一个点。

paintwidget.h代码

#ifndef PAINTWIDGET_H
#define PAINTWIDGET_H

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
class PaintWidget : public QWidget
{
    Q_OBJECT
public:
    explicit PaintWidget(QWidget *parent = 0);
    enum shape{//--------------------------------图形选择
        Line=1,
        Rect,
        Ellipse,
        Pen
    };

public  slots:
   void setShape(PaintWidget::shape t){//--------接受从mainwindow发射过来的信号
       if(t!=type)
           type = t;
       qDebug()<<type;// ------------------------检查是否接收成功
   }

protected:
    void paintEvent(QPaintEvent *);
    void mousePressEvent(QMouseEvent *);
    void mouseMoveEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *);

    void paint(QImage &theImage);
signals:

private:
    PaintWidget::shape type;
    QImage image;
    QImage tempImage;
    QRgb backColor;
    QPoint lastPoint;
    QPoint endPoint;
    bool isDrawing;
};

#endif // PAINTWIDGET_H

      
      
     
     
    
    
   
   
paintwidget.cpp文件代码

#include "paintwidget.h"
#include 
   
   
    
    
#include 
    
    
     
     
PaintWidget::PaintWidget(QWidget *parent) :
    QWidget(parent)
{
    isDrawing = false;
    type = PaintWidget::Line;//-------------默认为线类型
    image = QImage(700,500,QImage::Format_RGB32);
    backColor = qRgb(255,255,255);
    image.fill(backColor);
    tempImage = image;//--------------------tempImage也填充为白色
}

void PaintWidget :: paintEvent(QPaintEvent *){
    QPainter painter(this);
    if(isDrawing == true){
    painter.drawImage(0,0,tempImage);//-------如果正在绘图,既鼠标点击或者正在移动,画在tempImage上
    }else{
    painter.drawImage(0,0,image);//-----------如果鼠标释放,将图保存在image上
    }
}

void PaintWidget :: mousePressEvent(QMouseEvent *event){
    if(event->button() == Qt::LeftButton){
        lastPoint = event->pos();
        isDrawing = true;//-------------------鼠标点击开始绘图,移动表示正在绘图
    }
}

void PaintWidget :: mouseMoveEvent(QMouseEvent *event){ 

    if(event->buttons() & Qt::LeftButton){//-----鼠标为左键且正在移动
        endPoint = event->pos();
        tempImage = image;             
        if(type == Pen){//------------如果工具为画笔,不用双缓冲直接画在画板上
        paint(image);        
    }else{ //-------------------------否则用双缓冲绘图
            paint(tempImage);
        }
    }
}
void PaintWidget :: mouseReleaseEvent(QMouseEvent *event){
     isDrawing = false;
     if(type != Pen){
    paint(image);
    }

}


void PaintWidget :: paint (QImage &theImage){
    QPainter p(&theImage); 
        QPen apen;
      apen.setWidth(4);
        p.setPen(apen);//-----------设置绘图工具画笔线条宽度为4
    switch (type) {//---------------画图,自己脑补百度
    case  PaintWidget::Line:{
        p.drawLine(lastPoint,endPoint);
        break;
        }
    case PaintWidget::Rect:{
        p.drawRect(lastPoint.x(),lastPoint.y(),endPoint.x()-lastPoint.x(),endPoint.y()-lastPoint.y());
        break;
        }
    case PaintWidget::Ellipse:{
        p.drawEllipse(lastPoint.x(),lastPoint.y(),endPoint.x()-lastPoint.x(),endPoint.y()-lastPoint.y());
        break;
        }
    case PaintWidget::Pen:{
        p.drawLine(lastPoint,endPoint);
            lastPoint = endPoint;
            break; 
            }
    default:
        break;
    }

    update();//----------------------重绘
}
    
    
   
   
mainwindow头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
   
   
    
    
#include "paintwidget.h"
#include 
    
    
     
     


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
signals:
    void drawShape(PaintWidget::shape newShape);//-------发送给paintwidget,改变线条类型
private slots://----------------------------槽函数 接受工具栏按钮触发事件
    void drawLineActionTriggered();
    void drawRectActionTriggered();
    void drawEllipseActionTriggered();
    void drawPenActionTriggered();
private:

    PaintWidget *area;//-----------------新建paintwidget部件
    QScrollArea *scrollArea;//-----------滚动条
};

#endif // MAINWINDOW_H

    
    
   
   
mainwindow.cpp文件

#include "mainwindow.h"
#include 
   
   
    
    
#include 
    
    
     
     
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    //-------------加工具栏,加动作,状态栏,基础不懂自学
    this->setWindowTitle(tr("Drawing Board"));
    QToolBar *bar = this->addToolBar("Tools");
    QActionGroup *group = new QActionGroup(bar);//-----------把所有的按钮动作放在group里面,这样触发了一个按钮后之前的按钮会自动关闭

    QAction *drawLineAction = new QAction("Line", bar);
    drawLineAction->setIcon(QIcon(":/images/zhixian.png"));//-------图标自己去找吧,或者最后去我给的链接下,不过要积分哈。
    drawLineAction->setToolTip(tr("Line"));
    drawLineAction->setStatusTip(tr("Draw a line."));
    drawLineAction->setCheckable(true);
    drawLineAction->setChecked(true);//---------------------因为在paintwidget构造函数里面默认为线类型,所以这里默认为触发了画线动作
    group->addAction(drawLineAction);
    bar->addAction(drawLineAction);

    QAction *drawRectAction = new QAction("Rectangle", bar);
    drawRectAction->setIcon(QIcon(":/images/juxing.png"));
    drawRectAction->setToolTip(tr("Rectangle"));
    drawRectAction->setStatusTip(tr("Draw a rectangle."));
    drawRectAction->setCheckable(true);
    group->addAction(drawRectAction);
    bar->addAction(drawRectAction);

    QAction *drawEllipseAction = new QAction("Ellipse",bar);
    drawEllipseAction->setIcon(QIcon(":/images/yuan.png"));
    drawEllipseAction->setToolTip(tr("Ellipse"));
    drawEllipseAction->setCheckable(true);
    group->addAction(drawEllipseAction);
    bar->addAction(drawEllipseAction);

    QAction *drawPenAction = new QAction("Pen",bar);
    drawPenAction->setIcon(QIcon(":/images/huabi.png"));
    drawPenAction->setText(tr("Pen"));
    drawPenAction->setCheckable(true);
    group->addAction(drawPenAction);
    bar->addAction(drawPenAction);

    statusBar();

    area = new PaintWidget;// -------------------------------area为paintwidget的组件
    resize(700,500);
   scrollArea = new QScrollArea;
   scrollArea->setBackgroundRole(QPalette::Dark);
   scrollArea->setWidget(area);
   scrollArea->widget()->setMinimumSize(800,600);
   setCentralWidget(scrollArea);

    connect(drawLineAction,SIGNAL(triggered()),//------------触发了某个动作按钮就触发对应的触发动作函数
            this,SLOT(drawLineActionTriggered()));

    connect(drawRectAction,SIGNAL(triggered()),
            this,SLOT(drawRectActionTriggered()));

    connect(drawEllipseAction,SIGNAL(triggered()),
            this,SLOT(drawEllipseActionTriggered()));

    connect(drawPenAction,SIGNAL(triggered()),
            this,SLOT(drawPenActionTriggered()));

    connect(this,SIGNAL(drawShape(PaintWidget::shape)),//------把触发动作函数与paintwidget连接起来,发送信号给paintwidget
            area,SLOT(setShape(PaintWidget::shape)));

}

void MainWindow::drawLineActionTriggered()
{
        emit drawShape(PaintWidget::Line);//--------------发射信号
}

void MainWindow::drawRectActionTriggered()
{
        emit drawShape(PaintWidget::Rect);
}

void MainWindow::drawEllipseActionTriggered()
{
        emit drawShape(PaintWidget::Ellipse);
}
 void MainWindow::drawPenActionTriggered()
 {
        emit drawShape(PaintWidget::Pen);
 }

MainWindow::~MainWindow()
{

}


    
    
   
   

大功高成,运行,OK。


需要的图标,链接:http://download.csdn.net/detail/u012891055/8226205



  • 8
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值