天天看点

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

<a target="_blank" href="http://bbs.qter.org/forum.php?mod=viewthread&amp;tid=119">楼主</a>

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

 发表于 2013-5-2 21:37:41 | 查看:

1255| 回复: 16

涂鸦板

版权声明

导语

       通过前面几节的学习,大家应该已经对qt中2d绘图有了一定的认识,这一节我们将应用前面讲到的内容,编写一个简单的涂鸦板程序,这一节只是实现最基本的鼠标画线功能。

环境:windows xp + qt 4.8.4+qtcreator 2.6.2

目录

一、实现涂鸦板

二、实现放大功能

正文

1.新建qt gui应用,项目名称为pianter_3,基类这次还用qdialog,类名保持dialog不变即可。

2.到dialog.h文件中,先添加头文件包含:#include &lt;qmouseevent&gt;

然后添加几个函数的声明:

protected:

    void paintevent(qpaintevent *);

    void mousepressevent(qmouseevent *);

    void mousemoveevent(qmouseevent *);

    void mousereleaseevent(qmouseevent *);

       第一个是绘制事件处理函数,后面分别是鼠标按下、移动和释放事件的处理函数。

下面再添加几个private私有变量声明:

qpixmap pix;

qpoint lastpoint;

qpoint endpoint;

因为在函数里声明的qpixmap类对象是临时变量,不能存储以前的值,为了实现保留上次的绘画结果,我们需要将其设为全局变量。后面两个qpoint变量存储鼠标指针的两个坐标值,我们需要用这两个坐标值完成绘图。

2.到dialog.cpp文件中,先添加头文件包含:#include &lt;qpainter&gt;

然后在构造函数中添加如下初始代码:

resize(600, 500);    //窗口大小设置为600*500

pix = qpixmap(200, 200);

pix.fill(qt::white);

下面添加几个函数的定义:

void dialog::paintevent(qpaintevent *)

{    

      qpainter pp(&amp;pix); 

  // 根据鼠标指针前后两个位置就行绘制直线    

      pp.drawline(lastpoint, endpoint); 

  // 让前一个坐标值等于后一个坐标值,这样就能实现画出连续的线    

      lastpoint = endpoint; 

      qpainter painter(this); 

      painter.drawpixmap(0, 0, pix); 

}

       这里使用了两个点来绘制线条,这两个点在下面的鼠标事件中获得。

void dialog::mousepressevent(qmouseevent *event)

{   

               if(event-&gt;button()==qt::leftbutton) //鼠标左键按下 

               lastpoint = event-&gt;pos(); 

       当鼠标左键按下时获得开始点。

void dialog::mousemoveevent(qmouseevent *event)

         if(event-&gt;buttons()&amp;qt::leftbutton) //鼠标左键按下的同时移动鼠标 

        {        

                  endpoint = event-&gt;pos(); 

                  update(); //进行绘制 

         }

当鼠标移动时获得结束点,并更新绘制。调用update()函数会执行paintevent()函数进行重新绘制。

void dialog::mousereleaseevent(qmouseevent *event)

            if(event-&gt;button() == qt::leftbutton) //鼠标左键释放 

             {        

                      endpoint = event-&gt;pos(); 

                      update();    

             }

       当鼠标按键释放时也进行重绘。

       现在运行程序,使用鼠标在白色画布上进行绘制,发现已经实现了简单的涂鸦板功能,效果如下图所示。

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

       前面已经实现了简单的绘制功能,下面我们将实现放大功能,将画布放大后继续进行涂鸦。这里将使用两种方法来实现,也是对上一节坐标系统后面的问题的更进一步的应用实践。

1.添加放大按钮。到dialog.h文件中,先添加头文件:

#include &lt;qpushbutton&gt;

然后添加下面private私有变量声明:

qreal scale;

qpushbutton *button;

最后再添加一个私有槽声明:

private slots:

    void zoomin();

2.到dialog.cpp文件中,先在构造函数中添加如下代码:

//设置初始放大倍数为1,即不放大

scale =1;

//新建按钮对象

button = new qpushbutton(this);

//设置按钮显示文本

button-&gt;settext(tr("zoomin"));

//设置按钮放置位置

button-&gt;move(500, 450);

//对按钮的单击事件和其槽函数进行关联

connect(button, signal(clicked()), this, slot(zoomin()));

       这里使用代码创建了一个按钮对象,并将其单击信号关联到了放大槽上,也就是说按下这个按钮,就会执行zoomin()槽。

3.下面添加zoomin()的定义:

void dialog::zoomin()

{

    scale *=2;

    update();

    这里我们让每按下这个按钮,放大值都扩大两倍。后面调用update()函数来更新显示。

4. 通过上一节的学习,我们应该已经知道想让画布的内容放大有两个办法,一个是直接放大画布的坐标系统,一个是放大窗口的坐标系统。下面我们先来放大窗口的坐标系统。更改paintevent()函数如下:

    qpainter pp(&amp;pix);

    pp.drawline(lastpoint, endpoint); 

    lastpoint = endpoint; 

    qpainter painter(this);

    //进行放大操作

    painter.scale(scale, scale);

    painter.drawpixmap(0, 0, pix);

    现在运行程序,先在白色画布上任意绘制一个图形,效果如下图所示。

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

    然后按下zoomin按钮,效果如下图所示。

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

       现在再用鼠标进行绘制,发现图形已经不能和鼠标轨迹重合了,效果如下图所示。

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

有了前面一节的知识,就不难理解出现这个问题的原因了。窗口的坐标扩大了,但是画布的坐标并没有扩大,而我们画图用的坐标值是鼠标指针的,鼠标指针又是获取的窗口的坐标值。现在窗口和画布的同一点的坐标并不相等,所以就出现了这样的问题。

其实解决办法很简单,窗口放大了多少倍,就将获得的鼠标指针的坐标值缩小多少倍就行了。我们将paintevent()函数更改如下:

    pp.drawline(lastpoint/scale, endpoint/scale);

    lastpoint = endpoint;

       运行程序,效果如下图所示。可以看到,已经能够在放大以后继续绘图了。

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

这种用改变窗口坐标大小来改变画布面积的方法,实际上是有损图片质量的。就像将一张位图放大一样,越放大越不清晰。原因就是,它的像素的个数没有变,如果将可视面积放大,那么单位面积里的像素个数就变少了,所以画质就差了。

5.方法二。扩大画布坐标系统。先将paintevent()更改如下:

    pp.scale(scale, scale);

    pp.drawline(lastpoint,endpoint);

       这时运行程序,先进行绘制,然后点击zoomin按钮,发现以前的内容并没有放大,而当我们再次绘画时,发现鼠标指针和绘制的线条又不重合了。效果如下图所示。

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

       这并不是我们想要的结果,为了实现按下放大按钮,画布和图形都进行放大,我们可以使用缓冲画布(就是一个辅助画布)来实现。将paintevent()函数内容更改如下。

    if(scale!=1) //如果进行放大操作

    {

       //临时画布,大小变化了scale倍

       qpixmap copypix(pix.size()*scale);

       qpainter pter(&amp;copypix);

       pter.scale(scale, scale);

       //将以前画布上的内容复制到现在的画布上

       pter.drawpixmap(0, 0, pix);

       //将放大后的内容再复制回原来的画布上

       pix = copypix;

       //让scale重新置1

       scale =1;

    }

    pp.scale(scale,scale);

    pp.drawline(lastpoint/scale,endpoint/scale);

    painter.drawpixmap(0,0,pix);

       现在运行程序,效果如下图所示。

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

结语

      本节讲到的涂鸦板,只是为了实践前面的知识,起到抛砖引玉的作用。大家可以根据自己的理解继续探究下去。在下一节,我们将讲解怎样在涂鸦板上绘制出矩形、椭圆等图形。

涉及到的源码: 

[Qt教程] 第17篇 2D绘图(七)涂鸦板 [Qt教程] 第17篇 2D绘图(七)涂鸦板

kb, 下载次数: 22)