【Qt】2D绘图之涂鸦板 Dear 丶 2022-11-12 15:59 179阅读 0赞 ## 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(); } } 当鼠标按键释放时也进行重绘。现在运行程序,使用鼠标在白色画布上进行绘制,发现已经实现了简单的涂鸦板功能,效果如下图所示。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70] ## 04. 程序设计(放大功能) ## 4.1 添加放大按钮。到dialog.h文件中,先添加头文件: #include <QDialog> #include <QMouseEvent> #include <QPushButton> QT_BEGIN_NAMESPACE namespace Ui { class Dialog; } QT_END_NAMESPACE class Dialog : public QDialog { Q_OBJECT public: 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); //设置初始放大倍数为1 scale = 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); } 现在运行程序,效果如下图所示。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 1] 然后按下zoomIn按钮,效果如下图所示。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 2] 现在再用鼠标进行绘制,发现图形已经不能和鼠标轨迹重合了,效果如下图所示。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 3] 窗口的坐标扩大了,但是画布的坐标并没有扩大,而我们画图用的坐标值是鼠标指针的,鼠标指针又是获取的窗口的坐标值。现在窗口和画布的同一点的坐标并不相等,所以就出现了这样的问题。 其实解决办法很简单,窗口放大了多少倍,就将获得的鼠标指针的坐标值缩小多少倍就行了。我们将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); } ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 4] 这种用改变窗口坐标大小来改变画布面积的方法,实际上是有损图片质量的。就像将一张位图放大一样,越放大越不清晰。原因就是,它的像素的个数没有变,如果将可视面积放大,那么单位面积里的像素个数就变少了,所以画质就差了。 ## 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按钮,发现以前的内容并没有放大,而当我们再次绘画时,发现鼠标指针和绘制的线条又不重合了。效果如下图所示。 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 5] 这并不是我们想要的结果,为了实现按下放大按钮,画布和图形都进行放大,我们可以使用缓冲画布(就是一个辅助画布)来实现。将paintEvent()函数内容更改如下。 //绘图事件 void Dialog::paintEvent(QPaintEvent *) { if (1 != scale) { //临时画布 QPixmap copyPix(pix.size() * scale); QPainter pp(©Pix); pp.scale(scale, scale); //将以前画布上的内容复制到现在的画布上 pp.drawPixmap(0, 0, pix); //将放大后的内容在复制到原来的画布上 pix = copyPix; //让scale重新置1 scale = 1; } QPainter p(&pix); p.scale(scale, scale); //根据鼠标指针前后两个位置绘制直线 p.drawLine(lastPoint / scale, endPoint / scale); //前一个坐标值等于后一个坐标值 lastPoint = endPoint; QPainter painter(this); painter.drawPixmap(0, 0, pix); } 运行结果 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 6] ## 06. 附录 ## 源码下载:[【Qt】2D绘图之涂鸦板.rar][Qt_2D_.rar] [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70]: /images/20221022/84098e8c6b284b6ba7faec4e24f705ad.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 1]: /images/20221022/4be2e1b5cd954da49d72c56908d07ffd.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 2]: /images/20221022/c0cf29b5217b4890892dd2da747a44d3.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 3]: /images/20221022/662818fa11e84388897bd29c402c331d.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 4]: /images/20221022/1115ed0490864c92957db68e92979185.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 5]: /images/20221022/a2e10db4662b452dadaf7d9bac2612b9.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2RlbmdqaW4yMDEwNDA0MjA1Ng_size_16_color_FFFFFF_t_70 6]: /images/20221022/f44cd153d7da4b79b1eff88532973ab6.png [Qt_2D_.rar]: https://download.csdn.net/download/dengjin20104042056/16084042
相关 【Qt】2D绘图之双缓冲绘图 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 绘制矩形 04. 青旅半醒/ 2022年11月13日 00:48/ 0 赞/ 224 阅读
相关 【Qt】2D绘图之涂鸦板 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 程序设计(基本功能) Dear 丶/ 2022年11月12日 15:59/ 0 赞/ 180 阅读
相关 【Qt】2D绘图之绘图中其它问题 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 重绘事件 04. 怼烎@/ 2022年11月12日 14:57/ 0 赞/ 203 阅读
相关 【Qt】2D绘图之绘制图片 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 简单绘制图片 04 - 日理万妓/ 2022年11月12日 10:58/ 0 赞/ 223 阅读
相关 【Qt】2D绘图之绘制路径 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 绘制简单路径 04 男娘i/ 2022年11月12日 10:52/ 0 赞/ 319 阅读
相关 【Qt】2D绘图之坐标系统 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. Qt坐标系统 04 约定不等于承诺〃/ 2022年11月12日 09:52/ 0 赞/ 214 阅读
相关 【Qt】2D绘图之渐变填充 00. 目录 文章目录 00. 目录 01. 概述 02. 开发环境 03. 线性渐变 04. 刺骨的言语ヽ痛彻心扉/ 2022年11月12日 09:45/ 0 赞/ 232 阅读
还没有评论,来说两句吧...