在控件graphicsView中实现绘图功能

news2024/11/29 20:33:59

文章目录

  • 基础夯实:
  • 效果展示:
  • 一、目标:
  • 二、遇到的问题
  • 三、实例代码
    • customgraphicsview.h
    • customgraphicsview.cpp
    • mainwindow.h
    • mainwindow.cpp
    • mian.cpp


基础夯实:

在Qt框架中,QGraphicsView 是一个非常强大的控件,用于显示 QGraphicsScene 中的图形项(QGraphicsItem)。这个控件提供了滚动和缩放视图的功能,使得用户能够查看和操作复杂的图形场景。QGraphicsView 和 QGraphicsScene 的组合是Qt中用于二维图形显示的推荐方式,因为它们提供了高度的灵活性和强大的功能。

QGraphicsView
QGraphicsView 提供了视图窗口,用户通过这个窗口来查看和操作 QGraphicsScene 中的图形项。它支持缩放、平移以及多种渲染选项。QGraphicsView 并不直接存储图形项;相反,它仅仅是一个展示窗口,所有的图形项都存储在与之关联的 QGraphicsScene 中。

QGraphicsScene
QGraphicsScene 是一个用于存储和管理图形项的容器。你可以向场景中添加、移动、删除或修改图形项。场景本身不直接进行渲染;渲染工作由视图(QGraphicsView)完成。

鼠标事件
在Qt中,你可以通过重写控件的鼠标事件处理函数来响应用户的鼠标动作。对于 QGraphicsView 来说,如果你想要处理鼠标事件(如点击、拖动等),你通常需要处理这些事件在 QGraphicsScene 中的图形项上,而不是直接在 QGraphicsView 上。

重写图形项的鼠标事件处理函数:
mousePressEvent(QGraphicsSceneMouseEvent *event):处理鼠标按下事件。
mouseMoveEvent(QGraphicsSceneMouseEvent *event):处理鼠标移动事件(如果鼠标被按下并拖动)。
mouseReleaseEvent(QGraphicsSceneMouseEvent *event):处理鼠标释放事件。
将事件传递给图形项:
QGraphicsView 默认会将鼠标事件传递给场景中的图形项。如果图形项对事件进行了处理(即返回了true),则事件不会继续传播。如果图形项没有处理事件,事件可能会继续传播给视图或其他对象。
绘图事件
在Qt中,绘图通常是通过重写 paintEvent(QPaintEvent *event) 函数来完成的。然而,在 QGraphicsView 架构中,你通常不会直接在 QGraphicsView 上进行绘图。相反,你会在 QGraphicsScene 中创建和管理图形项,这些图形项会在需要时被渲染到视图上。

如果你需要自定义图形项的绘制行为,你应该继承 QGraphicsItem 并重写其 paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) 函数。这个函数提供了绘制图形项所需的 QPainter 对象和其他信息。

总结来说,QGraphicsView 提供了展示 QGraphicsScene 中图形项的视图窗口,并允许用户通过鼠标事件与之交互。绘图则是在 QGraphicsScene 中的图形项上进行的,通过重写这些图形项的 paint 方法来实现。
如果不清楚鼠标事件和QGraphicsView控件的,可以参考一下文档:
鼠标学习链接
[控件学习链接]


效果展示:

在这里插入图片描述
在这里插入图片描述
提示:如果你也想实现上图中的效果,欢迎继续阅读

一、目标:

需求:在QGraphicsView控件上面进行绘图,鼠标事件无法在控件上实现点击,拖动,释放的鼠标事件,但是需要在控件上进行绘图,就离不开鼠标事件。所以记录本文,以及我的实例,供大家参考学习:

二、遇到的问题

一开始使用了事件分发器,事件过滤器等操作,但是我并没有成功,最终使用了自定义信号,对原来的QGraphicsView控件进行了重写,最终实现了,在图片上显示矩形移动框和直线。暂时未实现的功能:不能把图形绘制到照片上,如果后面实现了,会继续更新,如果你对自定义控件和函数重写不太熟悉,可以查找资料,也可以看一下我之前的文章

三、实例代码

customgraphicsview.h

#ifndef CUSTOMGRAPHICSVIEW_H
#define CUSTOMGRAPHICSVIEW_H

#include <QGraphicsView>
#include <QPointF>
#include <QMouseEvent>

class CustomGraphicsView : public QGraphicsView
{
    Q_OBJECT

public:
    enum DrawMode { RectMode, LineMode };

    explicit CustomGraphicsView(QWidget *parent = nullptr);

    void setDrawMode(DrawMode mode);

signals:
    void mouseClicked(const QPointF &pos);
    void mouseMoved(const QPointF &pos);
    void mouseReleased(const QPointF &pos);

protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

private:
    DrawMode currentDrawMode;
    bool isDrawing = false;
    QPointF startPoint;
    QGraphicsRectItem *rectItem = nullptr;
    QGraphicsLineItem *lineItem = nullptr;  

    // 辅助函数,用于清理线条
    void clearLineItem();
};

#endif // CUSTOMGRAPHICSVIEW_H

customgraphicsview.cpp

#include "CustomGraphicsView.h"
#include <QGraphicsRectItem>
#include <QGraphicsScene>
#include <QMouseEvent>

CustomGraphicsView::CustomGraphicsView(QWidget *parent)
    : QGraphicsView(parent)
{
}

void CustomGraphicsView::setDrawMode(DrawMode mode)
{
    currentDrawMode = mode;
    // 清理之前可能存在的线条
    clearLineItem();
}

void CustomGraphicsView::clearLineItem()
{
    if (lineItem && scene()) {
        scene()->removeItem(lineItem);
        delete lineItem;
        lineItem = nullptr;
    }
}

void CustomGraphicsView::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        isDrawing = true;
        startPoint = mapToScene(event->pos());
        // 清理之前可能存在的线条或矩形
        clearLineItem();
        if (rectItem) {
            scene()->removeItem(rectItem);
            delete rectItem;
            rectItem = nullptr;
        }
    }
    emit mouseClicked(event->pos());
    QGraphicsView::mousePressEvent(event);
}

void CustomGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    if (isDrawing) {
        QPointF endPoint = mapToScene(event->pos());
        if (currentDrawMode == RectMode) {
            QPointF topLeft = QPointF(qMin(startPoint.x(), endPoint.x()), qMin(startPoint.y(), endPoint.y()));
            QPointF bottomRight = QPointF(qMax(startPoint.x(), endPoint.x()), qMax(startPoint.y(), endPoint.y()));
            QRectF rect(topLeft, bottomRight);

            if (!rectItem) {
                rectItem = scene()->addRect(rect, QPen(Qt::red), QBrush(Qt::NoBrush));
            } else {
                rectItem->setRect(rect);
            }
        } else if (currentDrawMode == LineMode) {
            if (!lineItem) {
                lineItem = scene()->addLine(startPoint.x(), startPoint.y(), endPoint.x(), endPoint.y(), QPen(Qt::blue));
            } else {
                lineItem->setLine(startPoint.x(), startPoint.y(), endPoint.x(), endPoint.y());
            }
        }
    }
    emit mouseMoved(event->pos());
}

void CustomGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && isDrawing) {
        isDrawing = false;
        // 如果需要,可以在这里处理矩形或线条的最终状态
        emit mouseReleased(event->pos());
    }
    QGraphicsView::mouseReleaseEvent(event);
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "CustomGraphicsView.h"
#include <QPixmap>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void onMouseClicked(const QPointF &pos);
    void onMouseMoved(const QPointF &pos);
    void onMouseReleased(const QPointF &pos);

    void on_pushButton_paint_rect_clicked();
    void on_pushButton_paint_line_clicked();

private:
    Ui::MainWindow *ui;
    CustomGraphicsView *customGraphicsView;
    QPixmap pixmap;
    QGraphicsScene *scene;
    QGraphicsPixmapItem *pixmapItem;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsRectItem>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , scene(new QGraphicsScene(this))
    , pixmapItem(nullptr)
{
    ui->setupUi(this);
    pixmap.load(":/new/prefix1/24.jpg");
    pixmapItem = new QGraphicsPixmapItem(pixmap);
    scene->addItem(pixmapItem);
    scene->setSceneRect(0, 0, 901, 504);
    ui->graphicsView->setScene(scene);

    // 注意这里连接时使用了 QPointF
    connect(ui->graphicsView, &CustomGraphicsView::mouseClicked, this, &MainWindow::onMouseClicked);
    connect(ui->graphicsView, &CustomGraphicsView::mouseMoved, this, &MainWindow::onMouseMoved);
    connect(ui->graphicsView, &CustomGraphicsView::mouseReleased, this, &MainWindow::onMouseReleased);
}

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

void MainWindow::onMouseClicked(const QPointF &pos) {
    QString text = QString("Mouse clicked at: (%1, %2)").arg(pos.x()).arg(pos.y());
    ui->mouse_press->setText(text);
    qDebug() << "Mouse clicked at:" << pos;
}

void MainWindow::onMouseMoved(const QPointF &pos) {
    QString text = QString("Mouse moved to: (%1, %2)").arg(pos.x()).arg(pos.y());
    ui->mouse_move->setText(text);
    qDebug() << "Mouse moved to:" << pos;
}

void MainWindow::onMouseReleased(const QPointF &pos) {
    QString text = QString("Mouse released at: (%1, %2)").arg(pos.x()).arg(pos.y());
    ui->mouse_release->setText(text);
    qDebug() << "Mouse released at:" << pos;
}



void MainWindow::on_pushButton_paint_rect_clicked()
{
    ui->graphicsView->setDrawMode(CustomGraphicsView::RectMode);
}

void MainWindow::on_pushButton_paint_line_clicked()
{
    ui->graphicsView->setDrawMode(CustomGraphicsView::LineMode);
}

mian.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2059854.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

读论文《Temporal Graph Networks for Deep Learning on Dynamic Graphs》

论文地址&#xff1a;[2006.10637] Temporal Graph Networks for Deep Learning on Dynamic Graphs (arxiv.org) 项目地址&#xff1a;GitHub - twitter-research/tgn: TGN: Temporal Graph Networks 作者提出了一种名为Temporal Graph Networks&#xff08;TGNs&#xff09;…

解决selenium 常见版本不兼容问题

目录 1、解决urllib3库不兼容的问题 2、解决chromedriver与浏览器版本不兼容的问题 【测试环境】 selenium&#xff1a;3.141.0Python&#xff1a;3.10 1、解决urllib3库不兼容的问题 背景&#xff1a;在尝试启动selenium时代码出现ValueError错误&#xff0c;代码如下&am…

Excel的使用总结

目录 1、汇总公式&#xff1a;TEXTJOIN 2、excel中选择某个区域的方法 3、excel中如何在复制的时候&#xff0c;不将公式一起复制过去 4、想要自动填充某个区域的值的方法 1、汇总公式&#xff1a;TEXTJOIN TEXTJOIN 函数 - Microsoft 支持 例&#xff1a;TEXTJOIN("…

下拉表格选择器ReTableSelect组件(API)

组件实现基于 Vue3 + Element Plus + Typescript,同时引用 vueUse + lodash-es + tailwindCss (不影响功能,可忽略) 基于ReTable和Popover组件封装的下拉表格选择器组件,支持本地分页以及远程请求两种方式。 交互与展示尽量的与ElSelect保持一致。 下拉表格选择器ReTableSel…

倍思Eil这款耳机怎么样吗?南卡、倍思、QCY四款开放式耳机无广避坑测评!

近期&#xff0c;我近期&#xff0c;我注意到后台有许多小伙伴向我咨询如何挑选合适的开放式耳机。市场上开放式耳机品牌琳琅满目&#xff0c;它们在音质表现、佩戴舒适度以及综合性能上均展现出各自的差异。对于追求耳朵极致舒适体验的朋友而言&#xff0c;选择一款合适的开放…

Qt5 编译 Qt creator 源码中的 designer 模块

文章目录 下载 Qt Creator 源码 下载 Qt Creator 源码 Github: https://github.com/qt/qttools 笔记打算用 Qt 5.12.12 来编译 qt creator-designer 所以笔者下载的是 tag - 5.12.12 &#xff0c;解压后如下&#xff0c;先删除多余的文件&#xff0c;后续还要删除更多文件方便…

教程:使用Python裁剪TIF影像为多个自定义大小的小块(分割栅格)

教程&#xff1a;使用Python裁剪TIF影像为多个自定义大小的小块(分割栅格) 随着遥感技术的不断发展&#xff0c;影像数据的处理和分析在地理信息系统&#xff08;GIS&#xff09;和遥感领域显得尤为重要。在实际项目中&#xff0c;处理大规模的TIF影像数据往往需要对影像进行裁…

【原创】java+swing+mysql房屋租赁管理系统设计与实现

个人主页&#xff1a;程序员杨工 个人简介&#xff1a;从事软件开发多年&#xff0c;前后端均有涉猎&#xff0c;具有丰富的开发经验 博客内容&#xff1a;全栈开发&#xff0c;分享Java、Python、Php、小程序、前后端、数据库经验和实战 文末有本人名片&#xff0c;希望和大家…

进程的退出概念

进程退出 缺页中断&#xff08;补充&#xff09;页表中的权限位进程退出异常exit 缺页中断&#xff08;补充&#xff09; 之前我们了解了页表相关的知识&#xff0c;现在问大家一个问题&#xff0c;用new和malloc开辟内存的时候是虚拟内存还是物理内存呢&#xff1f; 答案是虚…

谷粒商城实战笔记-231-商城业务-认证服务-单点登录简介

文章目录 一&#xff0c;跨域名共享登录1&#xff0c;父子域名共享登录2&#xff0c;跨域名登录 二&#xff0c;单点登录-SSO单点登录的必要性单点登录的原理 三&#xff0c;XXL-SSO&#xff0c;开源的单点登录解决方案 一&#xff0c;跨域名共享登录 1&#xff0c;父子域名共…

OSPF-基础多区域实验

1.ENSP下载 阿里云盘分享 ⭐/*无需密钥 免费下载 安装不成功&#xff0c;可关注并私信博主*/ 2.OSPF的基础需求和规则 实验规则&#xff1a; 1.接口地址→XY.XY.XY.R /24 X:两者之间最小的 Y:两者之间最大的 R:谁的接口就是谁的编号 以R1和R2之间的连接为例&#xff0…

中国植物性状数据库

中国植物性状的研究主要集中在植物的生理结构和功能&#xff0c;‌以及它们对环境的适应性上。‌中国植物性状的多样性体现在多个方面&#xff0c;‌包括植物的生理结构、‌生长习性、‌以及对环境的适应性等。 中国植物性状数据库&#xff0c;包含了来自140个样点的1529种植物…

Leetcode876. 链表的中间结点(双指针)

题目描述 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例&#xff1a; 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[3,4,5] 解释&#xff1a;链表只有一个中…

游泳耳机哪个品牌好?四大热门爆款游泳耳机实测体验速览!

游泳耳机作为水下运动的伴侣&#xff0c;有着不少喜爱的人群。然而&#xff0c;也有一部分人对其保持距离&#xff0c;原因往往是担心水下耳机进水损坏。但只要我们避开那些缺乏专业技术实力的产品&#xff0c;就能享受水下音乐带来的无限乐趣。作为一名资深音乐爱好者和游泳教…

减震组装对于哪些无人机是必不可少的!你知道吗?

高精度无人机 对于需要搭载高精度传感器或进行高精度测量的无人机&#xff0c;如测绘无人机、环境监测无人机等&#xff0c;减震组装是必不可少的。这些无人机需要确保在飞行过程中传感器数据的准确性和稳定性&#xff0c;因此必须采用有效的减震措施。 载重无人机 载重无人…

个人收藏个性化、实用性、可玩性在线网站持续更新,与君共享

1.https://handraw.top/ 支持中文手绘效果的白板工具&#xff0c;比较怀旧复古风格 界面简单风 2.https://app.diagrams.net 流程图、UML图、网络图、组织结构图、思维导图等&#xff0c;比较专业 可导出图片 PDF HTLM等各种格式 3.https://www.processon.com 主要用于生成…

杜占朋人物风采

杜占朋&#xff0c;衡水名校校长&#xff0c;一位荣获全国杰出青年称号的杰出教育家&#xff0c;同时也是全国范围内备受尊崇的红色基因传承者。他以其卓越的学术成就、丰富的实践经验以及不懈的教育创新精神&#xff0c;成为了当代教育领域的璀璨明星。他身兼数职&#xff0c;…

一文速通 Vue 基础

1、Vue 概述 官方文档中文&#xff1a;https://staging-cn.vuejs.org/ 英文&#xff1a;Vue.js - The Progressive JavaScript Framework | Vue.js 1.1、什么是 MVVM MVVM&#xff08;Model-View-ViewModel&#xff09;是一种软件设计模式&#xff0c;由微软WPF&#xff08…

C语言中的联合体和枚举类型

文章目录 &#x1f34a;联合体&#x1f34a;枚举类型 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以&#xff1a;点赞关注评论收藏&#xff08;一键四连&#xff09;哦~ &#x1f34a;联合体 1、概述   联合体该结构体的定义形式类似&#xff0c;但是它是所有的成…

信息安全保证人员CISAW:安全集成

信息安全保障人员认证(CISAW)在安全集成领域的认证&#xff0c;主要针对申请者在信息系统安全集成的知识和理论以及项目实施中的综合应用能力进行全面评估。 这一认证特别强调对申请者在安全集成方面的知识深度和利用这些知识分析、解决实际问题的能力的评价。 此外&#xff…