在控件graphicsView中实现绘图功能(三)

news2024/11/26 14:33:18

这里写自定义目录标题

  • 前言:
  • 效果展示:
    • 1.图片展示
    • 2.视频展示
  • 基础夯实:
    • 一.文本框焦点:
    • 二.QGraphicsItems:
      • 1.QGraphicsRectItem
      • 2.QGraphicsLineItem
      • 3.QGraphicsEllipseItem
      • 4.QGraphicsTextItem
      • 5.QGraphicsPathItem
    • 三.鼠标按键基础:
  • 实现功能:
  • 遇到问题:
    • 期待实现的功能:
  • 核心代码:
    • customgraphicsview.h:
    • customgraphicsview.cpp:
  • 仓库源码:

前言:

本文,对之前没有完成的绘图固定,文本添加,清屏,图片反转,以及自由画图功能进行了完善。也基本上实现了大部分简易绘图的功能,后面也会对一些细节和技术进行继续学习。

效果展示:

1.图片展示

示例图片1
示例图片2
出现bug,但是很好看,也保存了

2.视频展示

视频示例:

基础夯实:

一.文本框焦点:

在图形用户界面(GUI)编程中,文本框(或其他可编辑的控件,如文本编辑区、输入框等)获得焦点(focus)意味着该控件是当前接收键盘输入的目标。当文本框获得焦点时,用户可以通过键盘输入文本、修改文本或执行与该文本框相关联的其他键盘操作(如复制、粘贴等),而不会影响到界面上的其他控件。

焦点是GUI中用户交互的一个重要概念。在大多数图形界面中,一次只能有一个控件获得焦点。这意味着,如果用户尝试通过键盘与界面交互(例如,通过按键输入文本),只有获得焦点的控件会响应这些按键事件。

对于文本框来说,获得焦点通常伴随着一些视觉上的变化,以提示用户该控件是当前的活动控件。这些变化可能包括文本框边框颜色的变化、文本光标的出现或闪烁等。

在Qt中,您可以通过几种方式使文本框获得焦点:

程序性设置:您可以直接调用文本框的setFocus()方法来强制它获得焦点。这通常在您希望控件在显示时立即响应用户输入时很有用。
用户交互:用户可以通过点击文本框来使其获得焦点。在Qt中,当用户在图形视图(如QGraphicsView)中点击与QGraphicsTextItem相关联的文本框时,如果该文本框是可编辑的,并且没有其他控件阻止焦点传递,那么文本框应该会获得焦点。
键盘导航:在支持键盘导航的界面中,用户可以通过Tab键在控件之间切换焦点。如果您的文本框是键盘导航路径的一部分,那么用户可以通过按Tab键来使其获得焦点。
信号和槽:在Qt的信号和槽机制中,您可以连接一个信号(如鼠标点击事件)到一个槽函数,然后在该槽函数中调用setFocus()来使文本框获得焦点。
然而,需要注意的是,在某些情况下,文本框可能无法直接通过setFocus()方法获得焦点,特别是当它被嵌入到更复杂的控件或视图中时。在这些情况下,您可能需要检查控件的焦点策略或重写某些事件处理器来确保文本框能够按预期获得焦点。

二.QGraphicsItems:

在Qt框架中,QGraphicsItem 是所有图形项(包括二维图形项)的基类,用于在 QGraphicsScene 中表示一个项目,这些项目随后可以被 QGraphicsView 渲染和显示。QGraphicsItem 类本身不直接用于创建图形,而是提供了一套接口,用于管理这些图形项的位置、变换、选择、可见性等。下面是对您提到的几个特定派生类的详细解释:

1.QGraphicsRectItem

QGraphicsRectItem 是用于表示矩形的图形项。通过它可以很容易地在场景中添加、移动、缩放或旋转矩形。创建时,可以指定矩形的位置、大小、边框笔刷(QPen)和填充刷(QBrush)等属性。

cpp
QGraphicsRectItem *rectItem = nullptr;  
// 创建并初始化  
rectItem = new QGraphicsRectItem(QRectF(0, 0, 100, 50), nullptr); // 位置(0,0),大小100x50  
rectItem->setBrush(Qt::red); // 设置填充颜色为红色

2.QGraphicsLineItem

QGraphicsLineItem 用于表示直线段。通过它可以添加直线到场景中,并设置线条的样式、颜色等属性。

QGraphicsLineItem *lineItem = nullptr;  
// 创建并初始化  
lineItem = new QGraphicsLineItem(QLineF(0, 0, 100, 50), nullptr); // 从(0,0)到(100,50)的直线  
lineItem->setPen(QPen(Qt::blue, 2)); // 设置线条颜色和宽度

3.QGraphicsEllipseItem

QGraphicsEllipseItem 用于表示椭圆或圆。通过它可以向场景中添加椭圆或圆,并设置其边框和填充属性。

QGraphicsEllipseItem *ellipseItem = nullptr;  
// 创建并初始化  
ellipseItem = new QGraphicsEllipseItem(QRectF(-50, -25, 100, 50), nullptr); // 中心在(0,0),x轴半径50,y轴半径25的椭圆  
ellipseItem->setBrush(Qt::green); // 设置填充颜色为绿色

4.QGraphicsTextItem

QGraphicsTextItem 用于表示可编辑的文本项。它支持富文本格式,可以嵌入图片、链接等。使用它可以向场景中添加文本,并允许用户进行编辑。

QGraphicsTextItem *textItem = nullptr;  
// 创建并初始化  
textItem = new QGraphicsTextItem("Hello, QGraphicsTextItem!", nullptr);  
textItem->setDefaultTextColor(Qt::black); // 设置默认文本颜色

5.QGraphicsPathItem

QGraphicsPathItem 允许使用 QPainterPath 来绘制复杂的形状。QPainterPath 提供了一套命令来创建路径,包括线条、曲线、矩形、椭圆等,甚至可以通过组合和变换这些基本形状来创建更复杂的图形。

QGraphicsPathItem *pathItem = nullptr;  
QPainterPath path;  
path.addEllipse(QRectF(-50, -50, 100, 100)); // 添加一个椭圆  
pathItem = new QGraphicsPathItem(path, nullptr);  
pathItem->setBrush(Qt::yellow); // 设置填充颜色为黄色

这些类都是Qt图形视图框架中非常重要的部分,它们提供了丰富的接口来创建和管理图形项,使得开发者能够轻松地在Qt应用程序中实现复杂的图形界面。

三.鼠标按键基础:

推荐了解一下鼠标按键,再来实现代码:
在控件graphicsView中实现绘图功能(一)
在控件graphicsView中实现绘图功能(二)
QT中鼠标事件示例(包含点击,点击之后移动,释放的坐标获取)

实现功能:

如图所示,该实例实现了绘制直线,绘制椭圆,绘制矩形,绘制文字,自由绘画,清屏以及旋转等功能。

遇到问题:

文本无法输入,文本输入无法定位,清屏之后依然有残余。上述问题都已经解决

期待实现的功能:

连接数据库,将绘画好的图片保存到数据库,添加导入导出功能。

核心代码:

customgraphicsview.h:

#ifndef CUSTOMGRAPHICSVIEW_H
#define CUSTOMGRAPHICSVIEW_H

#include <QGraphicsView>
#include <QPointF>
#include <QMouseEvent>
#include <QPainterPath>
#include <QGraphicsTextItem>

class CustomGraphicsView : public QGraphicsView
{
    Q_OBJECT

public:
    enum DrawMode { RectMode,
                    LineMode,
                    EllipseMode,
                    FreeDrawMode,
                    TextHintMode
    };

    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;
    QGraphicsEllipseItem *ellipseItem = nullptr;
    QGraphicsTextItem *textItem = nullptr;
    QGraphicsPathItem *pathItem = nullptr;
    QPainterPath currentPath;
};

#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;
}

void CustomGraphicsView::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        isDrawing = true;
        startPoint = mapToScene(event->pos());

        switch (currentDrawMode) {
        case RectMode:
            // 矩形模式下,初始化矩形的两个角(实际上是同一个点,稍后在move事件中更新)
            rectItem = new QGraphicsRectItem(QRectF(startPoint, QSizeF(0, 0)));
            rectItem->setPen(QPen(Qt::blue)); // 示例颜色
            scene()->addItem(rectItem);
            break;

        case LineMode:
            // 线条模式下,不立即绘制线条,只在move事件中根据起点和当前点绘制
            lineItem = nullptr; // 如果之前有线条,则忽略它(或根据需要重置)
            break;

        case EllipseMode:
            ellipseItem = new QGraphicsEllipseItem(QRectF(startPoint, QSizeF(0, 0)));
            ellipseItem->setPen(QPen(Qt::green));
            ellipseItem->setBrush(QBrush(Qt::NoBrush));
            scene()->addItem(ellipseItem);
            break;
        case FreeDrawMode:
            if (!pathItem) {
                pathItem = new QGraphicsPathItem();
                scene()->addItem(pathItem);
            }
            currentPath.clear(); // 清除之前的路径,从头开始
            currentPath.moveTo(startPoint); // 初始化新路径的起点
            break;
        case TextHintMode:
        {
            if (!textItem) {
                textItem = new QGraphicsTextItem(tr("  ")); // 初始提示文本
                textItem->setTextInteractionFlags(Qt::TextEditorInteraction); // 允许文本编辑
                textItem->setFlag(QGraphicsItem::ItemIsMovable, true); // 可选:使文本框可移动
                textItem->setFlag(QGraphicsItem::ItemIsSelectable, true); // 可选:使文本框可选
                scene()->addItem(textItem);
                textItem->setPos(startPoint); // 设置文本框的初始位置
            }
            break;
        }
        default:
            // ...
            break;
        }
        emit mouseClicked(event->pos());
    }

    QGraphicsView::mousePressEvent(event);
}

void CustomGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    if (isDrawing) {
        QPointF endPoint = mapToScene(event->pos());

        switch (currentDrawMode) {
        case 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()));
            rectItem->setRect(QRectF(topLeft, bottomRight));
            break;
        }

        case LineMode:
        {
            if (!lineItem) {
                lineItem = scene()->addLine(startPoint.x(), startPoint.y(), endPoint.x(), endPoint.y(), QPen(Qt::red));
            } else {
                lineItem->setLine(QLineF(startPoint, endPoint));
            }
            break;
        }

        case EllipseMode:
        {
            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 ellipseRect(topLeft, QSizeF(bottomRight.x() - topLeft.x(), bottomRight.y() - topLeft.y()));
            ellipseItem->setRect(ellipseRect);
            break;
        }
        case FreeDrawMode:
        {
            currentPath.lineTo(endPoint); // 添加新点到路径
            pathItem->setPath(currentPath); // 更新路径项
            break;
        }

        default:
            // 处理默认情况
            break;
        }
    }
    emit mouseMoved(event->pos());
}

void CustomGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton && isDrawing) {
        isDrawing = false;
    }

    emit mouseReleased(event->pos());
    //重置模型项,以便下一次重写
    switch (currentDrawMode){
        {
            case RectMode:
                rectItem = nullptr;
                break;

            case LineMode:
                lineItem = nullptr;
                break;

            case EllipseMode:
                ellipseItem = nullptr;
                break;
            case FreeDrawMode:
                pathItem = nullptr;
                //清空绘图路径
                break;
            case TextHintMode:
            {
                textItem = nullptr;
                break;
            }
        }
    default:
        break;
    }

    QGraphicsView::mouseReleaseEvent(event);
}

仓库源码:

gitee仓库代码分享

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

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

相关文章

KI-DDI:知识图谱 + 大模型 + 图注意力,医学诊断

KI-DDI&#xff1a;知识图谱 大模型 图注意力&#xff0c;医学诊断 具体到点精细分析对话处理 SapBERT医学知识处理 - 图注意力网络(GAT)信息融合 - 对话嵌入 - 知识图谱嵌入知识图谱的权重 KI-DDI 图分析性关联图 知识图谱 大模型 VS KI-DDI更强的个性化 论文&#xff1a;T…

[数据集][目标检测]街灯路灯检测数据集VOC+YOLO格式1893张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1893 标注数量(xml文件个数)&#xff1a;1893 标注数量(txt文件个数)&#xff1a;1893 标注…

adaptive AUTOSAR UCM模块中SoftwareCluster与Software Package是什么样的关系,他们分别包含哪些元素?

在自适应AUTOSAR(Adaptive AUTOSAR)的更新和配置管理(UCM)模块中,SoftwareCluster和Software Package是软件更新过程中的两个关键概念,它们之间有着密切的关系: SoftwareCluster:通常指的是一组功能相关的软件组件,它们共同实现了车辆中的一个或多个特定功能。在UCM中…

钓鱼的常见几种方式

钓鱼的多种方式 office钓鱼攻击 宏与宏病毒 # 宏 宏是office自带的一种高级脚本特性&#xff0c;通过VBA代码&#xff0c;可以在office中去完成某项特定的任务&#xff0c;而不必再重复相同的动作&#xff0c;目的是让用户文档中一些任务自动化# 宏病毒 宏病毒是一种寄存在文…

Qt实现圆型控件的三种方法之设置样式表

前言 最近在研究绘制各种形状的控件&#xff0c;这里专门挑出圆形的控件进行记录&#xff0c;其它形状的也大差不差&#xff0c;会了圆形的之后其它的也类似。 正文 这里我挑出Label来进行举例。 通过设置样式表 (QSS) 这种方法简单且适用于不需要自定义绘制的场景。就是要…

uniapp实现应用内检测版本更新(Android直接下载/ios跳转app store)

背景&#xff1a;最近需要给app加一个可以检测到新版本并更新的功能&#xff0c; 之前没有考虑过这个问题&#xff0c;第一次尝试&#xff0c;特此记录一下。 我在这里使用到了uniapp上的更新插件&#xff0c;并在此插件基础上进行更改以适应我的项目。 插件链接&#xff1a;ht…

【专题】2023-2024中国游戏企业研发竞争力报告合集PDF分享(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p37447 在当今的数字时代&#xff0c;游戏产业已然成为经济与文化领域中一股不可忽视的重要力量。2023 年&#xff0c;中国自研游戏市场更是呈现出一片繁荣且复杂的景象&#xff0c;实际销售收入达到了令人瞩目的 2563.8 亿元&#x…

计算机毕业设计选题推荐-民宿可视化分析-Python爬虫-随机森林算法

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Catf1ag CTF Web(九)

前言 Catf1agCTF 是一个面向所有CTF&#xff08;Capture The Flag&#xff09;爱好者的综合训练平台&#xff0c;尤其适合新手学习和提升技能 。该平台由catf1ag团队打造&#xff0c;拥有超过200个原创题目&#xff0c;题目设计注重知识点的掌握&#xff0c;旨在帮助新手掌握C…

易趋产品升级 | EasyTrack11_V2.0功能更新合集

近日&#xff0c;易趋PPM&#xff08;EasyTrack PPM&#xff09;为了帮助企业全面提升数字化项目管理能力&#xff0c;完成了新一轮的产品升级&#xff0c;从【个人空间】、【项目组合管理】、【合同与外包管理】。除了以上三大功能模块之外&#xff0c;其他升级项暂略。 1.个人…

Ajax技术详解

Ajax简介 Ajax 即 "Asynchronous Javascript And XML"&#xff08;异步 JavaScript 和 XML&#xff09;&#xff0c;是指一种创建交互式、快速动态应用的网页开发技术&#xff0c;无需重新加载整个网页的情况下&#xff0c;能够更新页面局部数据的技术。 为什么要使…

c++习题25-判断字符串是否回文

目录 一&#xff0c;题目 二&#xff0c;思路 三&#xff0c;代码 一&#xff0c;题目 描述 输入一个字符串&#xff0c;输出该字符串是否回文。回文是指顺读和倒读都一样的字符串。 输入描述 输入为一行字符串&#xff08;字符串中没有空白字符&#xff0c;字符串长度不…

Linux文件属性和打包压缩详解

1、文件属性体系 1.1 文件系统概述 [rootyunwei /]# ls -lhi 总用量 72K3505 lrwxrwxrwx. 1 root root 7 3月 7 2019 bin -> usr/bin 262152 dr-xr-xr-x. 5 root root 4.0K 12月 19 16:00 boot 399635 drwxr-xr-x 2 root root 4.0K 11月 5 2019 data1026 drw…

【数据结构】二叉树基础知识

0. 前言 在前面几期博客&#xff0c;我们已经学习过了各种线性的数据结构&#xff0c;顺序表、链表、栈、队列&#xff0c; 本期博客我们一起来学习一种非线性的结构——树 1. 树的概念及结构 1.1 树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>…

学习嵌入式第二十九天

ipc进程间通信方式 PC&#xff0c;即进程间通信&#xff08;Inter-Process Communication&#xff09;&#xff0c;是操作系统中不同进程之间交换数据的一种机制。以下是一些常见的IPC方式&#xff1a; 管道&#xff1a;用于父子进程或兄弟进程之间的通信。消息队列&#xff…

火绒一键修复所有dll缺失?教你快速修复dll错误问题

你的电脑是否遇到过dll文件缺失的状态&#xff1f;那么应该如何将dll文件进行修复&#xff0c;不知道大家有没有听过火绒和电脑dll修复工具一键修复所有的dll缺失&#xff1f;今天我们就来了解一下如何使用火绒和电脑dll修复工具修复电脑错误dll文件丢失的问题。 dll是什么&…

海南云亿商务咨询有限公司靠谱不?

在这个短视频与直播浪潮席卷而来的时代&#xff0c;抖音电商以其独特的魅力迅速崛起&#xff0c;成为无数商家争相入驻的新战场。作为这一领域的佼佼者&#xff0c;海南云亿商务咨询有限公司凭借其专业的服务、前瞻性的视野和实战型的策略&#xff0c;正引领着一批又一批的商家…

【C语言进阶】数据如何安家?C语言内存中的存储艺术深度解析

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C语言 “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;C语言调试 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀C语言数据在内存中的存储 &#…

如何应对突发技术故障和危机:开发团队的应急策略

开发团队如何应对突发的技术故障和危机&#xff1f; 在数字化时代&#xff0c;软件服务的稳定性对于企业至关重要。然而&#xff0c;即使是大型平台&#xff0c;如网易云音乐&#xff0c;也可能遇到突发的技术故障。网页端出现502 Bad Gateway 报错&#xff0c;且App也无法正常…