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

本文介绍了如何在Qt中使用鼠标绘制任意多边形,包括菜单的设计、鼠标事件处理和绘图逻辑。重点讲解了如何创建菜单、使用QActions以及处理鼠标按下、移动和释放事件以实现实时绘制。
摘要由CSDN通过智能技术生成

往期回顾

【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" 

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

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

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

 //setFocusPolicy(Qt::StrongFocus);
 //setFocus();

 //下面是菜单栏创建过程,整体是很简单的,就不过多赘述
 //有一个问题,为什么不把菜单栏创建过程放在contextMenuEvent方法里
 //因为这意味着用户每单击鼠标一次,都会调用这个方法去创建一次菜单栏,而放在构造函数里就只用创建一次
 m_pMenu = new QMenu(this);

 //fromLocal8Bit()将本地编码转换为QString
 QAction* pAc1 = new QAction(QString::fromLocal8Bit("结束绘制"), this);
 //使用setShortcut方法为该QAction对象添加了快捷键"Ctrl+E"
 pAc1->setShortcut(QKeySequence("Ctrl+E")); //添加快捷键
 QAction* pAc2 = new QAction(QString::fromLocal8Bit("清除"), this);
 pAc2->setShortcut(QKeySequence("Ctrl+D"));

 // 这是个假动作,为了让菜单消失,且不影响绘制路径
 QAction* pAc3 = new QAction(QString::fromLocal8Bit("退出菜单"), this);

 m_pMenu->addAction(pAc1);
 m_pMenu->addAction(pAc2);
 m_pMenu->addAction(pAc3);

 m_pMenu->setStyleSheet("QMenu{font:18px;}");

 connect(pAc1, &QAction::triggered, [=] {
  ui->graphicsPainter->endDraw();
  });

 connect(pAc2, &QAction::triggered, [=] {
  ui->graphicsPainter->clearPath();
  });
}

MainWindow::~MainWindow()
{
    delete ui;
}

// 右键菜单
void MainWindow::contextMenuEvent(QContextMenuEvent* event)
{
 //获取鼠标当前位置,并把菜单栏move到该位置
 m_pMenu->move(cursor().pos());
 //然后进行显示
 m_pMenu->show();

 //如果没有这一步,那么单击鼠标右键,菜单栏会在桌面左上角(0,0)位置处显示
}

3、绘图功能实现 

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

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

MyPainterWidget::MyPainterWidget(QWidget *parent) : QWidget(parent)
{
    // 设置鼠标跟踪,以便在鼠标移动时能够及时更新绘图
    setMouseTracking(true);

    //清空点列表
    pointList.clear();
}
3.3、鼠标按下前清空画板

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

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

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

void MyPainterWidget::paintEvent(QPaintEvent *)
{
    //在窗口上绘制内容
    QPainter painter(this);
    painter.setPen(QColor(255,0,0)); // 设置画笔颜色为红色

    QVector<QLineF> lines; // 存储线段的容器

    for(int i = 0; i < pointList.size()-1; i++)
    {
        //在点列表pointList中的相邻点之间创建线段
        QLineF line(QPointF(pointList[i].x(), pointList[i].y()), 
                           QPointF(pointList[i+1].x(), pointList[i+1].y()));

        lines.push_back(line); // 将线段添加到容器中
    }
    
     如果正在绘制状态,则绘制鼠标移动到的点与最后一个点之间的线段
    if (m_bStartDraw)
    {
        int size = pointList.size();

        if (bMove && size > 0)
        {
            QLineF line(QPointF(pointList[pointList.size() - 1].x(), pointList[pointList.size() - 1].y()),
                movePoint);

            lines.push_back(line); // 将线段添加到容器中
        }
    }

    painter.drawLines(lines); // 绘制所有线段
}

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

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

// 移动
void MyPainterWidget::mouseMoveEvent(QMouseEvent *e)
{
    if(m_bStartDraw)
    {
        movePoint = e->pos(); // 更新移动点的位置
        
        this->update(); // 更新绘图

        // 先刷新再设为true, 防止第一点和(0,0)连在一块
        bMove = true;
    }
}
// 松开
void MyPainterWidget::mouseReleaseEvent(QMouseEvent *e)
{
   
    if (e->button() == Qt::LeftButton)
    {
        // 鼠标松开后,将点添加到路径中,并更新绘图
        if (m_bStartDraw)
        {
            // 鼠标松开后的点需要添加到路径中
            pointList.push_back(QPointF(e->x(), e->y()));
            bMove = false;
            this->update();
        }
    }
}

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

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

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

Qt中,可以使用QGraphicsView框架来实现鼠标绘图。以下是一个简单的示例,演示如何使用QGraphicsView框架来实现鼠标绘图: 1. 创建一个Qt Widgets应用程序,并将主窗口设置为QMainWindow。 2. 在主窗口中添加一个QGraphicsView部件,并设置其大小和位置。 3. 在主窗口中添加一个QGraphicsScene对象,并将其设置为QGraphicsView部件的场景。 4. 在主窗口中添加一个自定义的GraphicsItem对象,并将其添加到QGraphicsScene中。 5. 在自定义的GraphicsItem对象中,重写mousePressEvent和mouseMoveEvent事件处理程序,以捕获鼠标事件,并在场景中绘制图形。 以下是示例代码: mainwindow.h文件: ``` #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QGraphicsScene> #include "customgraphicsitem.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; QGraphicsScene *scene; CustomGraphicsItem *item; }; #endif // MAINWINDOW_H ``` mainwindow.cpp文件: ``` #include "mainwindow.h" #include "ui_mainwindow.h" #include <QGraphicsView> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // 创建场景和视图 scene = new QGraphicsScene(this); QGraphicsView *view = new QGraphicsView(scene, this); view->setGeometry(10, 10, 400, 400); // 创建自定义的GraphicsItem对象并添加到场景中 item = new CustomGraphicsItem(); scene->addItem(item); } MainWindow::~MainWindow() { delete ui; } ``` customgraphicsitem.h文件: ``` #ifndef CUSTOMGRAPHICSITEM_H #define CUSTOMGRAPHICSITEM_H #include <QGraphicsItem> class CustomGraphicsItem : public QGraphicsItem { public: CustomGraphicsItem(); QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); private: QList<QPointF> points; }; #endif // CUSTOMGRAPHICSITEM_H ``` customgraphicsitem.cpp文件: ``` #include "customgraphicsitem.h" #include <QPainter> #include <QGraphicsSceneMouseEvent> CustomGraphicsItem::CustomGraphicsItem() { // 设置图形项的矩形大小 setRect(0, 0, 100, 100); } QRectF CustomGraphicsItem::boundingRect() const { return rect(); } void CustomGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { // 绘制多边形 QPolygonF polygon(points); painter->drawPolygon(polygon); } void CustomGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { // 添加一个新点 QPointF point = event->pos(); points.append(point); // 重新绘制 update(); } void CustomGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { // 添加一个新点 QPointF point = event->pos(); points.append(point); // 重新绘制 update(); } ``` 运行应用程序后,单击并拖动鼠标,即可在场景中绘制多边形。每次单击鼠标时,都会在多边形中添加一个新点。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值