00. 目录

文章目录

  • 00. 目录
  • 01. 概述
  • 02. 开发环境
  • 03. 程序设计(基本功能)
  • 04. 程序设计(放大功能)
  • 05. 程序设计(放大功能)
  • 06. 附录

01. 概述

结合前面所学内容,编写一个简单的涂鸦板程序。

02. 开发环境

Windows系统:Windows10

Qt版本:Qt5.15或者Qt6

03. 程序设计(基本功能)

3.1 新建Qt Widgets应用,项目名称为12Draw,基类这次还用QDialog,类名保持Dialog不变即可。

3.2 到dialog.h文件中,先添加头文件包含:#include ,然后添加几个事件处理函数的声明:

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

3.3 再添加几个private私有变量定义:

private:QPixmap pix;QPoint lastPoint;QPoint endPoint;

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

3.4 在dialog.cpp文件中,先添加头文件包含:#include ,然后在构造函数中添加如下初始代码:

//设置窗口大小resize(600, 500);//设置画布大小和背景pix = QPixmap(200, 200);pix.fill(Qt::white);

3.5 在paintEvent添加如下代码

//绘图事件
void Dialog::paintEvent(QPaintEvent *)
{QPainter p(&pix);//根据鼠标指针前后两个位置绘制直线p.drawLine(lastPoint,  endPoint);//前一个坐标值等于后一个坐标值lastPoint = endPoint;QPainter painter(this);painter.drawPixmap(0, 0, pix);
}

3.6 在mousePressEvent添加如下代码

void Dialog::mousePressEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){lastPoint = e->pos();}endPoint = lastPoint;
}

当鼠标左键按下时获得开始点,每次开始绘制都让结束点和开始点重合,这样确保这两个点的值都是预期的值。

3.7 在mouseMoveEvent添加如下代码

//鼠标移动事件
void Dialog::mouseMoveEvent(QMouseEvent *e)
{if (e->button() & Qt::LeftButton){endPoint = e->pos();update();}
}

当鼠标移动时获得结束点,并更新绘制,注意这里的buttons()函数可以获取鼠标移动过程中按下的所有按键,然后用&Qt::LeftButton来判断是否按下了左键,在mouseMoveEvent()中必须使用该方法来判断按下的鼠标按键。最后调用update()函数会执行paintEvent()函数进行重新绘制。

3.8 在mouseReleaseEvent添加如下代码

//鼠标释放事件
void Dialog::mouseReleaseEvent(QMouseEvent *e)
{if (e->button() == Qt::LeftButton){endPoint = e->pos();update();}}

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

04. 程序设计(放大功能)

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

#include <QDialog>
#include <QMouseEvent>
#include <QPushButton>QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACEclass Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = nullptr);~Dialog();protected:void paintEvent(QPaintEvent *);void mousePressEvent(QMouseEvent *);void mouseMoveEvent(QMouseEvent *);void mouseReleaseEvent(QMouseEvent *);private slots:void zoomIn();private:Ui::Dialog *ui;QPixmap pix;QPoint lastPoint;QPoint endPoint;qreal scale;QPushButton *button;
};
#endif // DIALOG_H

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

Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog)
{ui->setupUi(this);//设置窗口大小resize(600, 500);//设置画布大小和背景pix = QPixmap(300, 250);pix.fill(Qt::white);//设置初始放大倍数为1scale = 1;//新建按钮对象button = new QPushButton(this);//设置按钮显示文本button->setText(tr("放大"));//设置按钮的位置button->move(500, 450);//信号与槽关联connect(button, &QPushButton::clicked, this, &Dialog::zoomIn);}

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

4.3 添加zoomIn函数

//槽函数 放大
void Dialog::zoomIn()
{scale *= 2;update();
}

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

4.4 让画布的内容放大有两个办法,一个是直接放大画布的坐标系统,一个是放大窗口的坐标系统。下面我们先来放大窗口的坐标系统。更改paintEvent()函数如下:

//绘图事件
void Dialog::paintEvent(QPaintEvent *)
{QPainter p(&pix);//根据鼠标指针前后两个位置绘制直线p.drawLine(lastPoint,  endPoint);//前一个坐标值等于后一个坐标值lastPoint = endPoint;QPainter painter(this);painter.scale(scale, scale);painter.drawPixmap(0, 0, pix);
}

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

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

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

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

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

//绘图事件
void Dialog::paintEvent(QPaintEvent *)
{QPainter p(&pix);//根据鼠标指针前后两个位置绘制直线p.drawLine(lastPoint / scale,  endPoint / scale);//前一个坐标值等于后一个坐标值lastPoint = endPoint;QPainter painter(this);painter.scale(scale, scale);painter.drawPixmap(0, 0, pix);
}

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

05. 程序设计(放大功能)

方法二

5.1 扩大画布坐标系统。先将paintEvent()更改如下:

//绘图事件
void Dialog::paintEvent(QPaintEvent *)
{QPainter p(&pix);p.scale(scale, scale);//根据鼠标指针前后两个位置绘制直线p.drawLine(lastPoint,  endPoint);//前一个坐标值等于后一个坐标值lastPoint = endPoint;QPainter painter(this);painter.drawPixmap(0, 0, pix);
}

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

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


//绘图事件
void Dialog::paintEvent(QPaintEvent *)
{if (1 != scale){//临时画布QPixmap copyPix(pix.size() * scale);QPainter pp(&copyPix);pp.scale(scale, scale);//将以前画布上的内容复制到现在的画布上pp.drawPixmap(0, 0, pix);//将放大后的内容在复制到原来的画布上pix = copyPix;//让scale重新置1scale = 1;}QPainter p(&pix);p.scale(scale, scale);//根据鼠标指针前后两个位置绘制直线p.drawLine(lastPoint / scale,  endPoint / scale);//前一个坐标值等于后一个坐标值lastPoint = endPoint;QPainter painter(this);painter.drawPixmap(0, 0, pix);
}

运行结果

06. 附录

源码下载:【Qt】2D绘图之涂鸦板.rar

【Qt】2D绘图之涂鸦板相关推荐

  1. Qt 2D绘图之二:抗锯齿渲染和坐标系统

    一.抗锯齿渲染 1.1 逻辑绘图 图形基元的大小(宽度和高度)始终与其数学模型相对应,下图示意了忽略其渲染时使用的画笔的宽度的样子. 1.2 物理绘图(默认情况) 在默认的情况下,绘制会产生锯齿,并且 ...

  2. Qt 2D绘图功能简单总结

    文章目录 Qt 2D绘图功能简单总结 Qt 2D绘图功能简单总结 Qt 的绘图功能非常强大,它可以绘制一切想要的图形,从最简单的一条直线到其他任何复杂的图形,还可以用来绘制文本和图片. Qt的绘图系统 ...

  3. Qt 2D绘图(5):绘制图像基础

    Qt 2D绘图(5):绘制图像基础 本文为原创文章,转载请注明出处,或注明转载自"黄邦勇帅(原名:黄勇) 本文出自本人原创著作<Qt5.10 GUI完全参考手册>网盘地址: ht ...

  4. Qt中国象棋一—— Qt 2D 绘图入门

    最近想用Qt写一个中国象棋的项目,在网上找了几个例子后,发现关于绘图部分基础为0 ,于是根据项目需要学习一下.查了一些网上的资料,在此总结一下:我比较喜欢的方式是用到什么学什么,或者自己想做一个东西, ...

  5. QT 2d绘图优化(一)

    最近在用QT做一款白板软件,在开发过程中,发现了有如下几个问题 void drawLine(QPointF endpt) {path.quadTo(path.currentPosition(),(pa ...

  6. [转载]Qt涂鸦板程序图文详细教程..Qt涂鸦板程序图文详

    原文地址:Qt涂鸦板程序图文详细教程..Qt涂鸦板程序图文详细教程..作者:棰滈櫟鍚 Technorati 标签: QT http://www.yafeilinux.com/?p=379 (说明:这是 ...

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

    [Qt教程] 第17篇 2D绘图(七)涂鸦板 楼主  发表于 2013-5-2 21:37:41 | 查看: 1255| 回复: 16 涂鸦板 版权声明 该文章原创于Qter开源社区(www.qter ...

  8. 【Qt入门第17篇】 2D绘图(七)涂鸦板

    导语 通过前面几节的学习,大家应该已经对Qt中2D绘图有了一定的认识,这一节我们将应用前面讲到的内容,编写一个简单的涂鸦板程序,这一节只是实现最基本的鼠标画线功能. 环境:Windows Xp + Q ...

  9. 第17篇 2D绘图(七)涂鸦板

    导语 通过前面几节的学习,大家应该已经对Qt中2D绘图有了一定的认识,这一节我们将应用前面讲到的内容,编写一个简单的涂鸦板程序,这一节只是实现最基本的鼠标画线功能. 环境:Windows Xp + Q ...

最新文章

  1. Xamarin 2017.9.19更新
  2. web页面版权部分的显示问题
  3. OpenCV parallel_for_并行化代码
  4. 一个最简单的WebSocket hello world demo
  5. 如何存储和恢复 HTML5 Canvas 状态
  6. linux查看ip命令_不可不知的Linux文本查看命令
  7. 在Mac下配置Appium环境
  8. devsecops automation
  9. DSP28335定时器
  10. 写给非网工的CCNA教程(4)聊聊ping命令后的原理(续)
  11. python第三方库的安装方式_Python第三方库的几种安装方式(小结)
  12. Redis入门学习笔记--附Redis工具类
  13. 小米最新系统android 10,小米新系统到来!基于Android Q的MIUI 10到底有哪些变化?小米9可尝鲜...
  14. java正则表达式获取书名
  15. 再生龙备份linux文件多大,使用再生龙Clonezilla备份还原Linux系统
  16. 深入理解Camera 基础知识点
  17. 莫名其妙出现各种syntax error的解决方案
  18. 数据采集时总提示未登录_做电商必须学会这一招!教你用爬虫工具免费采集网易考拉商品数据...
  19. 数据挖掘技术的应用领域
  20. matlab矩阵保存到表格,将matlab求出的矩阵保存在Excel表格中

热门文章

  1. Windows SharePoint Services 3.0编码开发工具和技巧(Part 1 of 2)
  2. UVA 494(Kindergarten Counting Game)
  3. AX中对Programmable section的动态控制
  4. 在使用Asp.net制作网站的时候遇到的问题(二)
  5. 第9章例题 7-2 学生成绩排序
  6. 每日程序C语言47-找到年龄最大的人并输出
  7. c语言ifft,用于ARM上的FFT与IFFT源代码-C语言
  8. Python 面向对象编程 day7
  9. Unity手游之路九自动寻路Navmesh之高级主题
  10. 你方唱罢我登场,“全宇宙仅此一回”的小米手机青春版竞争策略分析