Qt学习之路(32): 一个简易画板的实现(Graphics View)

QT学习:图形视图Graphics View 一、Graphics View框架结构的主要特点 (1)在Graphics View框架结构中,系统可以利用Qt绘图系统的反锯齿、OpenGL工具来改善绘图性能。 (2) Graphics View支持事件传播体系结构,可以使图元在场景(scene) 中的交互能力提高1倍,图元能够处理键盘事件和鼠标事件。其中,鼠标事件包括鼠标被按下、移动、释放和双击,还可以跟踪鼠标的移动。 (3)在Graphics View框架中,通过二元空间划分树(Binary Space Pritining, BSP) 提供快速的图元 阅读详情
这一次将介绍如何使用Graphics View来实现前面所说的画板。前面说了很多有关Graphics View的好话,但是没有具体的实例很难说究竟好在哪里。现在我们就把前面的内容使用Graphics View重新实现一下,大家可以对比一下看有什么区别。
 
同前面相似的内容就不再叙述了,我们从上次代码的基础上进行修改,以便符合我们的需要。首先来看MainWindow的代码:
 
mainwindow.cpp
#include  "mainwindow.h" 
 
MainWindow::MainWindow(QWidget *parent) 
        : QMainWindow(parent) 
{ 
        QToolBar *bar =  this->addToolBar( "Tools"); 
        QActionGroup *group =  new QActionGroup(bar); 
 
        QAction *drawLineAction =  new QAction( "Line", bar); 
        drawLineAction->setIcon(QIcon( ":/line.png")); 
        drawLineAction->setToolTip(tr( "Draw a line.")); 
        drawLineAction->setStatusTip(tr( "Draw a line.")); 
        drawLineAction->setCheckable( true); 
        drawLineAction->setChecked( true); 
        group->addAction(drawLineAction); 
 
        bar->addAction(drawLineAction); 
        QAction *drawRectAction =  new QAction( "Rectangle", bar); 
        drawRectAction->setIcon(QIcon( ":/rect.png")); 
        drawRectAction->setToolTip(tr( "Draw a rectangle.")); 
        drawRectAction->setStatusTip(tr( "Draw a rectangle.")); 
        drawRectAction->setCheckable( true); 
        group->addAction(drawRectAction); 
        bar->addAction(drawRectAction); 
 
        QLabel *statusMsg =  new QLabel; 
        statusBar()->addWidget(statusMsg); 
 
        PaintWidget *paintWidget =  new PaintWidget( this); 
        QGraphicsView *view =  new QGraphicsView(paintWidget,  this); 
        setCentralWidget(view); 
 
        connect(drawLineAction, SIGNAL(triggered()), 
                         this, SLOT(drawLineActionTriggered())); 
        connect(drawRectAction, SIGNAL(triggered()), 
                         this, SLOT(drawRectActionTriggered())); 
        connect( this, SIGNAL(changeCurrentShape(Shape::Code)), 
                        paintWidget, SLOT(setCurrentShape(Shape::Code))); 
} 
 
void MainWindow::drawLineActionTriggered() 
{ 
        emit changeCurrentShape(Shape::Line); 
} 
 
void MainWindow::drawRectActionTriggered() 
{ 
        emit changeCurrentShape(Shape::Rect); 
} 
 
由于mainwindow.h的代码与前文相同,这里就不再贴出。而cpp文件里面只有少数几行与前文不同。由于我们使用Graphics View,所以,我们必须把item添加到QGprahicsScene里面。这里,我们创建了scene的对象( paintWidget),而scene对象需要通过view进行观察,因此,我们需要再使用一个QGraphcisView对象,并且把这个view添加到MainWindow里面。
 
我们把PaintWidget当做一个scene,因此PaintWidget现在是继承QGraphicsScene,而不是前面的QWidget。
 
paintwidget.h
#ifndef PAINTWIDGET_H 
#define PAINTWIDGET_H 
 
#include <QtGui> 
#include <QDebug> 
 
#include  "shape.h" 
#include  "line.h" 
#include  "rect.h" 
 
class PaintWidget :  public QGraphicsScene 
{ 
        Q_OBJECT 
 
public: 
        PaintWidget(QWidget *parent = 0); 
 
public slots: 
         void setCurrentShape(Shape::Code s) 
        { 
                 if(s != currShapeCode) { 
                        currShapeCode = s; 
                } 
        } 
 
protected: 
         void mousePressEvent(QGraphicsSceneMouseEvent * event);
         void mouseMoveEvent(QGraphicsSceneMouseEvent * event);
         void mouseReleaseEvent(QGraphicsSceneMouseEvent * event);
 
private: 
        Shape::Code currShapeCode; 
        Shape *currItem; 
         bool perm; 
}; 
 
#endif  // PAINTWIDGET_H
 
paintwidget.cpp
#include  "paintwidget.h" 
 
PaintWidget::PaintWidget(QWidget *parent) 
        : QGraphicsScene(parent), currShapeCode(Shape::Line), currItem(NULL), perm( false) 
{ 
 
} 
 
void PaintWidget::mousePressEvent(QGraphicsSceneMouseEvent * event) 
{ 
         switch(currShapeCode) 
        { 
         case Shape::Line: 
                { 
                        Line *line =  new Line; 
                        currItem = line; 
                        addItem(line); 
                         break; 
                } 
         case Shape::Rect: 
                { 
                        Rect *rect =  new Rect; 
                        currItem = rect; 
                        addItem(rect); 
                         break; 
                } 
        } 
         if(currItem) { 
                currItem->startDraw( event); 
                perm =  false; 
        } 
        QGraphicsScene::mousePressEvent( event); 
} 
 
void PaintWidget::mouseMoveEvent(QGraphicsSceneMouseEvent * event) 
{ 
         if(currItem && !perm) { 
                currItem->drawing( event); 
        } 
        QGraphicsScene::mouseMoveEvent( event); 
} 
 
void PaintWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) 
{ 
        perm =  true; 
        QGraphicsScene::mouseReleaseEvent( event); 
}
 
我们把继承自QWidget改成继承自QGraphicsScene,同样也会有鼠标事件,只不过在这里我们把鼠标事件全部转发给具体的item进行处理。这个我们会在下面的代码中看到。另外一点是,每一个鼠标处理函数都包含了调用其父类函数的语句。
 
shape.h
#ifndef SHAPE_H 
#define SHAPE_H 
 
#include <QtGui> 
 
class Shape 
{ 
public: 
 
         enum Code { 
                Line, 
                Rect 
        }; 
 
        Shape(); 
 
         virtual  void startDraw(QGraphicsSceneMouseEvent *  event) = 0; 
         virtual  void drawing(QGraphicsSceneMouseEvent *  event) = 0; 
}; 
 
#endif  // SHAPE_H
 
shape.cpp
#include  "shape.h" 
 
Shape::Shape() 
{ 
} 
 
Shape类也有了变化:还记得我们曾经说过,Qt内置了很多item,因此我们不必全部重写这个item。所以,我们要使用Qt提供的类,就不需要在我们的类里面添加新的数据成员了。这样,我们就有了不带有额外的数据成员的Shape。那么,为什么还要提供Shape呢?因为我们在scene的鼠标事件中需要修改这些数据成员,如果没有这个父类,我们就需要按照Code写一个长长的switch来判断是那一个图形,这样是很麻烦的。所以我们依然创建了一个公共的父类,只要调用这个父类的draw函数即可。
 
line.h
#ifndef LINE_H 
#define LINE_H 
 
#include <QGraphicsLineItem> 
#include  "shape.h" 
 
class Line :  public Shape,  public QGraphicsLineItem 
{ 
public: 
        Line(); 
 
         void startDraw(QGraphicsSceneMouseEvent *  event); 
         void drawing(QGraphicsSceneMouseEvent *  event); 
}; 
 
#endif  // LINE_H
 
line.cpp
#include  "line.h" 
 
Line::Line() 
{ 
} 
 
void Line::startDraw(QGraphicsSceneMouseEvent *  event) 
{ 
        setLine(QLineF( event->scenePos(),  event->scenePos())); 
} 
 
void Line::drawing(QGraphicsSceneMouseEvent *  event) 
{ 
        QLineF newLine(line().p1(),  event->scenePos()); 
        setLine(newLine); 
} 
 
Line类已经和前面有了变化,我们不仅仅继承了Shape,而且继承了QGraphicsLineItem类。这里我们使用了C++的多继承机制。这个机制是很危险的,很容易发生错误,但是这里我们的Shape并没有继承其他的类,只要函数没有重名,一般而言是没有问题的。如果不希望出现不推荐的多继承(不管怎么说,多继承虽然危险,但它是符合面向对象理论的),那就就想办法使用组合机制。我们之所以使用多继承,目的是让Line类同时具有Shape和QGraphicsLineItem的性质,从而既可以直接添加到QGraphicsScene中,又可以调用startDraw()等函数。
 
同样的还有Rect这个类:
 
rect.h
#ifndef RECT_H 
#define RECT_H 
 
#include <QGraphicsRectItem> 
#include  "shape.h" 
 
class Rect :  public Shape,  public QGraphicsRectItem 
{ 
public: 
        Rect(); 
 
         void startDraw(QGraphicsSceneMouseEvent *  event); 
         void drawing(QGraphicsSceneMouseEvent *  event); 
}; 
 
#endif  // RECT_H
 
rect.cpp
#include  "rect.h" 
 
Rect::Rect() 
{ 
} 
 
void Rect::startDraw(QGraphicsSceneMouseEvent *  event) 
{ 
        setRect(QRectF( event->scenePos(), QSizeF(0, 0))); 
} 
 
void Rect::drawing(QGraphicsSceneMouseEvent *  event) 
{ 
        QRectF r(rect().topLeft(), 
                         QSizeF( event->scenePos().x() - rect().topLeft().x(),  event->scenePos().y() - rect().topLeft().y())); 
        setRect(r); 
} 
 
Line和Rect类的逻辑都比较清楚,和前面的基本类似。所不同的是,Qt并没有使用我们前面定义的两个Qpoint对象记录数据,而是在QGraphicsLineItem中使用QLineF,在QGraphicsRectItem中使用QRectF记录数据。这显然比我们的两个点的数据记录高级得多。其实,我们也完全可以使用这样的数据结构去重定义前面那些Line之类。
 
这样,我们的程序就修改完毕了。运行一下你会发现,几乎和前面的实现没有区别。这里说“几乎”,是在第一个点画下的时候,scene会移动一段距离。这是因为scene是自动居中的,由于我们把Line的第一个点设置为(0, 0),因此当我们把鼠标移动后会有一个偏移。
 
看到这里或许并没有显示出Graphics View的优势。不过,建议在Line或者Rect的构造函数里面加上下面的语句,
 
setFlag(QGraphicsItem::ItemIsMovable,  true); 
setFlag(QGraphicsItem::ItemIsSelectable,  true);
 
此时,你的Line和Rect就已经支持选中和拖放了!值得试一试哦!不过,需要注意的是,我们重写了scene的鼠标控制函数,所以这里的拖动会很粗糙,甚至说是不正确,你需要动动脑筋重新设计我们的类啦!

本文出自 “豆子空间” 博客,请务必保留此出处http://devbean.blog.51cto.com/448512/244181

QT之QGraphicsView详细介绍 是 Qt GUI 库中的一个核心类,它是 Qt 图形视图框架的一部分,主要用于可视化地显示中的内容。QGraphicsView 提供了一个灵活且可定制的二维图形界面,支持丰富的交互功能,如平移、缩放、旋转,并能够管理和布局复杂的图形场景。基本特性:视图与场景分离类本身负责渲染和显示图形场景 (),而场景则负责存储和管理所有的图形项 (),这些图形项可以是文本、形状、图片等任何可视化元素。视口与坐标系统QGraphicsView 内部有一个视口,视口映射的是场景的部分或全部内容。 阅读详情

相关推荐

QGraphicsView 全详解

视口类型的视口可以是任何类型的QWidget,包括QGLWidget,这使得可以在视口中使用OpenGL进行渲染。视口事件:可以通过重写的函数来处理视口级别的事件,例如触摸事件和多点触控事件。类提供了许多常用的函数、信号和槽,用于管理和操作图形视图。

github_37290846的博客 6447

Qt项目实战之网络电子白板

本课程使用Qt技术实现了网络电子白板,支持直线、矩形、椭圆、三角形、涂鸦等图形元素。本课程实现的电子白板,可以在多人之间共享,每个人都可以进行任意绘制,每个人的绘制都可以同步显示在其它人的白板上。服务器端使用Qt Network开发,客户端使用Qt Network和Qt Graphics View Framework开发,数据传输使用JSON数据格式。

AI如何革新问卷设计:从知识图谱到智能组卷

智能问卷设计正通过知识图谱和NLP技术重塑传统调研方法。其核心原理是构建动态知识网络,结合多目标优化算法实现自动组卷,在保证统计学指标(如难度系数、区分度)的同时大幅提升效率。这类技术尤其适用于教育测评、市场调研等需要大规模标准化问卷的场景,典型工具如虎贲等考系统已实现分钟级生成专业问卷。相比人工设计,AI方案在知识点覆盖率、难度控制和成本效益方面展现显著优势,同时支持实时质量监测和风格迁移等高级功能。随着大模型技术的发展,智能问卷系统正在向个性化评估和适应性测试方向演进。

weixin_34079177的博客 345

Qt图形视图框架:QGraphicsView 详解

Qt图形视图框架:QGraphicsView详解

友善啊,朋友的博客 7万+

人工智能快速发展的核心要素,大数据、算法和超级计算的介绍

人工智能涉及的学科非常多。比如说计算机科学、脑科学、哲学、心理学、语言学等。学术界目前还没有统一的人工智能定义,不同研究方向的专家对人工智能的理解不一样,定义也有所侧重。目前比较通俗的定义是:人工智能就是用人工的方法在机器上实现的智能,被称为机器智能。 根据人工智能的智能水平,从低到高可以划分为三个层次,第一个层次是计算智能,就是能存会算,各种棋类游戏、专家系统体现的就是计算智能;第二个层次是感知...

5709

AI素养教育四维模型:赋能教师应对人工智能时代教学变革

人工智能作为当今教育变革的核心驱动力,其本质是基于数据、算法和算力的复杂工具系统。理解机器学习的基本原理,关键在于认识其依赖模式识别与概率计算的工作机制,而非具备真正的思考能力。这一技术价值在于重塑知识的生产与传播方式,推动教育从知识传授向能力培养转型。在应用场景上,AI工具能够辅助教学设计、个性化学习路径规划与教学资源生成,实现人机协同增效。本文聚焦AI素养教育的四维框架——认知理解、应用实践、批判评估与伦理责任,通过课堂落地的三级推进策略,系统解决教师面临的数字鸿沟、学术诚信边界模糊等挑战,为教育工作者

weixin_30110543的博客 520

数学建模实战:用Python构建AI教育影响评价体系与TOPSIS分析

综合评价是数据分析与决策支持中的核心方法,它通过构建多维度指标体系,将复杂抽象的问题转化为可量化、可比较的模型。其基本原理在于指标筛选、权重确定与信息聚合,技术价值在于为多准则决策提供客观依据。在实践层面,综合评价广泛应用于教育评估、绩效管理、项目优选等场景。本文聚焦于人工智能对大学生学习影响的评价问题,通过层次分析法(AHP)与熵权法结合确定指标权重,并运用TOPSIS模型进行量化分析,结合Python实现了从数据清洗、信效度检验到模型求解与可视化(如雷达图、热力图)的完整流程,为教育技术领域的量化研究提

weixin_29079671的博客 296

数学建模竞赛实战:AHP与模糊综合评价在AI教育影响评估中的应用

在数据分析与决策科学领域,综合评价是处理多指标、多维度复杂问题的核心方法。其基本原理是通过构建系统化的指标体系,将抽象概念转化为可量化的数据,再运用数学模型进行综合分析与判断。这一技术价值在于能够将主观判断与客观数据相结合,为决策提供科学依据,广泛应用于教育评估、绩效管理、项目评审等场景。层次分析法(AHP)通过两两比较确定指标权重,有效量化专家经验;模糊综合评价则擅长处理问卷数据中的模糊语义,将定性描述转化为定量分析。本文将AHP与模糊综合评价融合,构建了一套从指标设计、权重计算到综合评判的完整技术方案,

weixin_27310417的博客 249

AI项目成败关键: Adoption设计实战方法论

AI落地的核心挑战从来不是模型精度,而是用户是否真正使用——即‘采用率(Adoption)’。它源于人因工程与技术逻辑的深度耦合:人类需要可解释、可干预、低认知负荷的交互,而非黑盒式最优解。Adoption设计本质是将AI嵌入真实工作流,通过最小信任单元(MTU)、渐进式授权、人机协作热键等机制,降低首次使用门槛并构建正向反馈闭环。其技术价值在于 bridging the gap between algorithmic correctness and operational practicality,应用场

weixin_30487201的博客 455

【人工智能】模糊推理:从“差不多”到“算得准”的智能决策引擎

本文探讨了模糊推理在人工智能领域的应用,特别是在智能决策系统中的重要性。通过智能温控系统的实例,详细解析了模糊集合论、隶属函数设计和模糊规则库构建等核心技术,展示了如何将模糊的人类语言转化为精确的计算机指令。文章还介绍了模糊推理在智能家居、农业和工业等领域的广泛应用,以及其在提升系统能效和用户满意度方面的显著效果。

weixin_30764771的博客 382

AI如何提升硕士开题报告写作效率与质量

文献综述与研究问题定位是学术写作的基础环节,传统人工处理面临信息过载与认知局限。通过自然语言处理技术构建的智能文献分析系统,能够自动提取关键词共现网络、识别理论框架冲突,显著提升文献调研效率。深度学习算法如BERT+BiLSTM混合模型可实现对海量学术文献的语义理解,结合逆向问题求解算法,帮助研究者快速定位学术gap。这类AI写作辅助工具已在实际应用中展现价值,例如使开题报告文献调研时间缩短68%,格式错误率下降92%,特别适合研究方法选择、理论框架构建等典型学术场景。PaperZZ AI等系统通过智能提纲

weixin_33158887的博客 300

别再死记硬背了!用‘相亲匹配’的故事5分钟搞懂Transformer里的Q、K、V

本文通过相亲派对的生动类比,深入浅出地解释了Transformer模型中的Q、K、V向量及其Attention机制。文章将复杂的AI概念转化为日常场景,帮助读者快速理解查询向量(Q)、键向量(K)和值向量(V)的相互作用原理,以及它们在自注意力和多头注意力中的实际应用。

weixin_30904593的博客 363

Mac/Windows跨平台PDF与AI高效解决方案

摘要:本文系统介绍了AI技术在跨平台PDF处理中的创新应用,涵盖Mac/Windows环境下的10大核心场景和20个拓展功能。智能分类、多语言翻译、合同风险标记等场景展示了NLP与OCR技术的深度整合,而电子签名验证、表格提取等功能则体现了计算机视觉的应用价值。技术实现上,重点采用Electron框架保障跨平台兼容性,结合CoreML/DirectML加速本地运算,并推荐了Adobe Acrobat、PDFelement等主流工具。Office生产力工具部分则聚焦Word排版、Excel数据分析和PPT动态

keny-大成的博客 914

MuleSoft企业级LLM编排:AI落地的流程治理与合规实践

大语言模型(LLM)作为非结构化语义处理的核心能力,其真正价值释放依赖于与企业现有系统(如SAP、Salesforce、HL7)的安全、可控、可审计集成。MuleSoft作为成熟的企业集成平台,提供API治理、流程编排、熔断降级、Prompt版本管理、全链路追踪等关键能力,本质是将LLM调用纳入SOA/ESB级别的工程化治理体系。它解决的不是‘能否调用模型’,而是‘如何稳定、合规、低成本、可追溯地调度AI服务’——尤其适用于金融、保险、制造等强监管、多遗留系统的行业场景。本文聚焦MuleSoft在LLM编排

diandingyin9417的博客 404

AI论文写作工具评测与学术生产力提升指南

随着自然语言处理技术的突破,AI写作辅助工具正深刻改变学术研究范式。基于Transformer架构的大语言模型通过语义理解与生成能力,为研究者提供从文献综述到论文润色的全流程支持。这类工具的技术价值在于将传统写作中机械性工作的效率提升300%-500%,同时通过检索增强生成(RAG)技术确保学术严谨性。在科研应用场景中,Elicit等专业工具能自动构建文献关系图谱,ChatGPT学术版可解释复杂统计结果,而Scite.ai则能智能分析数百万引用上下文。合理使用这些AI工具组合,研究者可将文献处理时间缩短70

weixin_29043895的博客 331

关于某大学宿舍空调的相关问题

AI题目

学校题目记录日常 600

AI高考全卷评测:大模型教育能力的实证边界

高考作为高信度、高区分度的标准化认知任务,本质是时间压力下多学科知识协同调用与表达的过程。其能力评估不能止于单点测试,而需覆盖跨模态理解、符号推理、语义辨析、步骤逻辑等复合维度。AI高考全卷评测正是以此为出发点,通过真实真题、无联网约束、双盲人工批改等严苛条件,系统测量大模型在语文古诗鉴赏、数学步骤分获取、英语语感判断、理综图像-公式联合推理等关键场景的表现。该评测不追求参数规模,而是聚焦‘现学现用’能力与‘教育可用性’落差,为教研员选型、工程师优化、教师预判AI教学影响提供可验证的技术标尺。

weixin_34192816的博客 418

嵌入式AI日志调教:从幻觉污染到可信信源

嵌入式日志是系统状态的客观镜像,而AI日志常因资源错配沦为统计幻觉。其本质是轻量级LLM在算力、内存与确定性受限环境下,对原始日志的语义覆盖而非事实记录。理解日志生成原理(固件层宏展开、中断安全队列)、掌握二进制编码(TLV协议、编译期元编程)与硬件协同(RTS/CTS流控、MPU只读内存映射),才能将AI从干扰源转化为性能分析与故障聚类的可信辅助工具。本文聚焦ARM Cortex-M与RTOS环境下的落地实践,覆盖日志源头去AI化、传输链路抗污染、AI框架驯化三重防线,适用于工业PLC、电力终端等无云依赖

weixin_34116110的博客 255
上一篇: Qt学习之路(31): 一个简易画板的实现(QWidget)
下一篇: Qt学习之路(33): 国际化(上)
flowingFire2012
博客等级 码龄14年 6粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值