当前位置:   article > 正文

Qt绘图与图形视图之移动鼠标手动绘制任意多边形的简单介绍

Qt绘图与图形视图之移动鼠标手动绘制任意多边形的简单介绍

往期回顾

【QT进阶】Qt线程与并发之QtConcurrent返回值与run方法的参数说明-CSDN博客

Qt绘图与图形视图之绘图技术知识点的简单介绍-CSDN博客

Qt绘图与图形视图之常见图形、路径、文字、图片的绘制介绍-CSDN博客

 Qt绘图与图形视图之移动鼠标手动绘制任意多边形的简单介绍

一、最终效果

左键点击画板,就可以移动鼠标开始绘制,双击左键结束绘制,或者右键点击也结束绘制。

二、具体实现

1、简单思路

主要两个类实现,一个负责绘制的逻辑实现,一个负责实现菜单,用了ui设计。

 2、菜单实现

我们要实现一个菜单,当用户单击鼠标右键时,会弹出一个菜单,让用户进行选择。

2.1、为什么在构造函数里创建菜单

在创建菜单的过程中,我们并没有把创建菜单封装成一个类,而是放在了构造函数里。为什么不把菜单栏创建过程放在contextMenuEvent方法里?而要放在构造函数里。

因为如果放在contextMenuEvent方法里,这意味着用户每单击鼠标一次,都会调用这个方法去创建一次菜单栏,而放在构造函数里就只用创建一次

2.2、假动作设计
 QAction* pAc3 = new QAction(QString::fromLocal8Bit("退出菜单"), this);

这是个假动作,为了让菜单消失,且不影响绘制路径

2.3、fromLocal8Bit()方法

fromLocal8Bit()将本地编码转换为QString,使用setShortcut方法为该QAction对象添加了快捷键"Ctrl+E" 

  1. //fromLocal8Bit()将本地编码转换为QString
  2. QAction* pAc1 = new QAction(QString::fromLocal8Bit("结束绘制"), this);
  3. //使用setShortcut方法为该QAction对象添加了快捷键"Ctrl+E"
  4. pAc1->setShortcut(QKeySequence("Ctrl+E")); //添加快捷键
2.4、完整代码

 注释很详细,可以慢慢看。

  1. MainWindow::MainWindow(QWidget *parent)
  2. : QMainWindow(parent)
  3. , ui(new Ui::MainWindow)
  4. {
  5. ui->setupUi(this);
  6. //setFocusPolicy(Qt::StrongFocus);
  7. //setFocus();
  8. //下面是菜单栏创建过程,整体是很简单的,就不过多赘述
  9. //有一个问题,为什么不把菜单栏创建过程放在contextMenuEvent方法里
  10. //因为这意味着用户每单击鼠标一次,都会调用这个方法去创建一次菜单栏,而放在构造函数里就只用创建一次
  11. m_pMenu = new QMenu(this);
  12. //fromLocal8Bit()将本地编码转换为QString
  13. QAction* pAc1 = new QAction(QString::fromLocal8Bit("结束绘制"), this);
  14. //使用setShortcut方法为该QAction对象添加了快捷键"Ctrl+E"
  15. pAc1->setShortcut(QKeySequence("Ctrl+E")); //添加快捷键
  16. QAction* pAc2 = new QAction(QString::fromLocal8Bit("清除"), this);
  17. pAc2->setShortcut(QKeySequence("Ctrl+D"));
  18. // 这是个假动作,为了让菜单消失,且不影响绘制路径
  19. QAction* pAc3 = new QAction(QString::fromLocal8Bit("退出菜单"), this);
  20. m_pMenu->addAction(pAc1);
  21. m_pMenu->addAction(pAc2);
  22. m_pMenu->addAction(pAc3);
  23. m_pMenu->setStyleSheet("QMenu{font:18px;}");
  24. connect(pAc1, &QAction::triggered, [=] {
  25. ui->graphicsPainter->endDraw();
  26. });
  27. connect(pAc2, &QAction::triggered, [=] {
  28. ui->graphicsPainter->clearPath();
  29. });
  30. }
  31. MainWindow::~MainWindow()
  32. {
  33. delete ui;
  34. }
  35. // 右键菜单
  36. void MainWindow::contextMenuEvent(QContextMenuEvent* event)
  37. {
  38. //获取鼠标当前位置,并把菜单栏move到该位置
  39. m_pMenu->move(cursor().pos());
  40. //然后进行显示
  41. m_pMenu->show();
  42. //如果没有这一步,那么单击鼠标右键,菜单栏会在桌面左上角(00)位置处显示
  43. }

3、绘图功能实现 

 3.1、主要的五个类
  1. void paintEvent(QPaintEvent *) override;
  2. void mousePressEvent(QMouseEvent *e) override; //按下
  3. void mouseMoveEvent(QMouseEvent *e) override; //移动
  4. void mouseReleaseEvent(QMouseEvent *e) override; //松开
  5. void mouseDoubleClickEvent(QMouseEvent *event) override; //双击
3.2、鼠标跟踪函数

首先是构造函数里的鼠标跟踪函数,这个是必须要有的 

  1. MyPainterWidget::MyPainterWidget(QWidget *parent) : QWidget(parent)
  2. {
  3. // 设置鼠标跟踪,以便在鼠标移动时能够及时更新绘图
  4. setMouseTracking(true);
  5. //清空点列表
  6. pointList.clear();
  7. }
3.3、鼠标按下前清空画板

每次鼠标按下绘画之前,都会先清空画板 

  1. // 按下
  2. void MyPainterWidget::mousePressEvent(QMouseEvent *e)
  3. {
  4. if (e->button() == Qt::LeftButton)
  5. {
  6. if(!m_bStartDraw)
  7. {
  8. //每次按下后开始绘画之前,也就是m_bStartDraw设置为真之前
  9. //都应该先清空整个画板
  10. pointList.clear();
  11. m_bStartDraw = true;
  12. }
  13. }
  14. }
3.4、重写绘图事件

 其次是重写绘图事件,这里创建了一个vector容器来存储线段,用for循环实现相邻点之间的线段连接,最后再绘制所有线段,注意,是先把需要绘制的线段都放在vector容器里,最后一起绘制的

  1. void MyPainterWidget::paintEvent(QPaintEvent *)
  2. {
  3. //在窗口上绘制内容
  4. QPainter painter(this);
  5. painter.setPen(QColor(255,0,0)); // 设置画笔颜色为红色
  6. QVector<QLineF> lines; // 存储线段的容器
  7. for(int i = 0; i < pointList.size()-1; i++)
  8. {
  9. //在点列表pointList中的相邻点之间创建线段
  10. QLineF line(QPointF(pointList[i].x(), pointList[i].y()),
  11. QPointF(pointList[i+1].x(), pointList[i+1].y()));
  12. lines.push_back(line); // 将线段添加到容器中
  13. }
  14. 如果正在绘制状态,则绘制鼠标移动到的点与最后一个点之间的线段
  15. if (m_bStartDraw)
  16. {
  17. int size = pointList.size();
  18. if (bMove && size > 0)
  19. {
  20. QLineF line(QPointF(pointList[pointList.size() - 1].x(), pointList[pointList.size() - 1].y()),
  21. movePoint);
  22. lines.push_back(line); // 将线段添加到容器中
  23. }
  24. }
  25. painter.drawLines(lines); // 绘制所有线段
  26. }

可能会有个疑惑?最后才绘制所有线段,为什么实际操作的过程中感觉是一条一条绘制的

因为每次鼠标按下和松开的时候,都是进行了update()的,也就是说在每次添加新线段到lines容器时,都会触发paintEvent的调用,从而实时更新界面。这样就会看到每次添加新线段时都会立即绘制出来,就有一种逐条绘制的感觉。

  1. // 移动
  2. void MyPainterWidget::mouseMoveEvent(QMouseEvent *e)
  3. {
  4. if(m_bStartDraw)
  5. {
  6. movePoint = e->pos(); // 更新移动点的位置
  7. this->update(); // 更新绘图
  8. // 先刷新再设为true, 防止第一点和(0,0)连在一块
  9. bMove = true;
  10. }
  11. }
  1. // 松开
  2. void MyPainterWidget::mouseReleaseEvent(QMouseEvent *e)
  3. {
  4. if (e->button() == Qt::LeftButton)
  5. {
  6. // 鼠标松开后,将点添加到路径中,并更新绘图
  7. if (m_bStartDraw)
  8. {
  9. // 鼠标松开后的点需要添加到路径中
  10. pointList.push_back(QPointF(e->x(), e->y()));
  11. bMove = false;
  12. this->update();
  13. }
  14. }
  15. }

以上就是Qt里移动鼠标手动绘制任意多边形的简单介绍

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/526235
推荐阅读
相关标签
  

闽ICP备14008679号