Qt学习之路(31): 一个简易画板的实现(QWidget)

Qt画线条 情况是这样的,现在设计一个地图,地图上的点(假设为pushButton)在Qt Designer中进行勾勒,都放在一个frame里面,然后将一些地图上联通的点使用直线连接起来.嗯....其实这是图的基本演示.....如果你没看明白我在说什么,那就看下面的图吧 上面的线条有锯齿.....官方有个demo,看截图 里面的线条十分优美....不过在下才疏学浅. 阅读详情
说实话,本来我是没有打算放一个很大的例子的,一则比较复杂,二来或许需要很多次才能说得完。不过,现在已经说完了绘图部分,所以计划还是上一个这样的例子。这里我会只做出一个简单的画板程序,大体上就是能够画直线和矩形吧。这样,我计划分成两种实现,一是使用普通的QWidget作为画板,第二则是使用Graphcis View Framework来实现。因为前面有朋友说不大明白Graphics View的相关内容,所以计划如此。
 
好了,现在先来看看我们的主体框架。我们的框架还是使用Qt Creator创建一个Gui Application工程。
 
简单的main()函数就不再赘述了,这里首先来看MainWindow。顺便说一下,我一般不会使用ui文件,所以这些内容都是手写的。首先先来看看最终的运行结果:
 
 
或许很简单,但是至少我们能够把前面所说的各种知识串连起来,这也就达到目的了。

( Shape --> Line/Rect --> paintwidget --> mainwindow --> main )

现在先来看看MainWindow的代码:
 
mainwindow.h
#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 
 
#include <QtGui> 
 
#include  "shape.h" 
#include  "paintwidget.h" 
 
class MainWindow :  public QMainWindow 
{ 
        Q_OBJECT 
 
public: 
        MainWindow(QWidget *parent = 0); 
 
signals: 
         void changeCurrentShape(Shape::Code newShape); 
 
private slots: 
         void drawLineActionTriggered(); 
         void drawRectActionTriggered(); 
 
}; 
 
#endif  // MAINWINDOW_H
 
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); 
        setCentralWidget(paintWidget); 
 
        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类里面声明了一个信号,changeCurrentShape(Shape::Code),用于按钮按下后通知画图板。注意,QActio的triggered()信号是没有参数的,因此,我们需要在QAction的槽函数中重新emit我们自己定义的信号。构造函数里面创建了两个QAction,一个是drawLineAction,一个是drawRectAction,分别用于绘制直线和矩形。MainWindow的中心组件是PainWidget,也就是我们的画图板。下面来看看PaintWidget类:
 
paintwidget.h
#ifndef PAINTWIDGET_H 
#define PAINTWIDGET_H 
 
#include <QtGui> 
#include <QDebug> 
#include  "shape.h" 
#include  "line.h" 
#include  "rect.h" 
 
class PaintWidget :  public QWidget 
{ 
        Q_OBJECT 
 
public: 
        PaintWidget(QWidget *parent = 0); 
 
public slots: 
         void setCurrentShape(Shape::Code s) 
        { 
                 if(s != currShapeCode) { 
                        currShapeCode = s; 
                } 
        } 
 
protected: 
         void paintEvent(QPaintEvent * event); 
         void mousePressEvent(QMouseEvent * event); 
         void mouseMoveEvent(QMouseEvent * event); 
         void mouseReleaseEvent(QMouseEvent * event); 
 
private: 
        Shape::Code currShapeCode; 
        Shape *shape; 
         bool perm; 
        QList<Shape*> shapeList; 
}; 
 
#endif  // PAINTWIDGET_H 
 
paintwidget.cpp
#include  "paintwidget.h" 
 
PaintWidget::PaintWidget(QWidget *parent) 
        : QWidget(parent), currShapeCode(Shape::Line), shape(NULL), perm( false) 
{ 
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 
} 
 
void PaintWidget::paintEvent(QPaintEvent * event) 
{ 
        QPainter painter( this); 
        painter.setBrush(Qt::white); 
        painter.drawRect(0, 0, size().width(), size().height()); 
         foreach(Shape * shape, shapeList) { 
                shape->paint(painter); 
        } 
         if(shape) { 
                shape->paint(painter); 
        } 
} 
 
void PaintWidget::mousePressEvent(QMouseEvent * event) 
{ 
         switch(currShapeCode) 
        { 
         case Shape::Line: 
                { 
                        shape =  new Line; 
                         break; 
                } 
         case Shape::Rect: 
                { 
                        shape =  new Rect; 
                         break; 
                } 
        } 
         if(shape != NULL) { 
                perm =  false; 
                shapeList<<shape; 
                shape->setStart( event->pos()); 
                shape->setEnd( event->pos()); 
        } 
} 
 
void PaintWidget::mouseMoveEvent(QMouseEvent * event) 
{ 
         if(shape && !perm) { 
                shape->setEnd( event->pos()); 
                update(); 
        } 
} 
 
void PaintWidget::mouseReleaseEvent(QMouseEvent * event) 
{ 
        perm =  true; 
} 
 
PaintWidget类定义了一个slot,用于接收改变后的新的ShapeCode。最主要的是,PaintWidget重定义了三个关于鼠标的事件:mousePressEvent,mouseMoveEvent和mouseReleaseEvent。
 
我们来想象一下如何绘制一个图形:图形的绘制与鼠标操作息息相关。以画直线为例,首先我们需要按下鼠标,确定直线的第一个点,所以在mousePressEvent里面,我们让shape保存下start点。然后在鼠标按下的状态下移动鼠标,此时,直线就会发生变化,实际上是直线的终止点在随着鼠标移动,所以在mouseMoveEvent中我们让shape保存下end点,然后调用update()函数,这个函数会自动调用paintEvent()函数,显示出我们绘制的内容。最后,当鼠标松开时,图形绘制完毕,我们将一个标志位置为true,此时说明这个图形绘制完毕。
 
为了保存我们曾经画下的图形,我们使用了一个List。每次按下鼠标时,都会把图形存入这个List。可以看到,我们在paintEvent()函数中使用了foreach遍历了这个List,绘制出历史图形。foreach是Qt提供的一个宏,用于遍历集合中的元素。
 
最后我们来看看Shape类。
 
shape.h
#ifndef SHAPE_H 
#define SHAPE_H 
 
#include <QtGui> 
 
class Shape 
{ 
public: 
 
         enum Code { 
                Line, 
                Rect 
        }; 
 
        Shape(); 
 
         void setStart(QPoint s) 
        { 
                start = s; 
        } 
 
         void setEnd(QPoint e) 
        { 
                end = e; 
        } 
 
        QPoint startPoint() 
        { 
                 return start; 
        } 
 
        QPoint endPoint() 
        { 
                 return end; 
        } 
 
         void  virtual paint(QPainter & painter) = 0; 
 
protected: 
        QPoint start; 
        QPoint end; 
}; 
 
#endif  // SHAPE_H 
 
shape.cpp
#include  "shape.h" 
 
Shape::Shape() 
{ 
} 
 
Shape类最重要的就是保存了start和end两个点。为什么只要这两个点呢?因为我们要绘制的是直线和矩形。对于直线来说,有了两个点就可以确定这条直线,对于矩形来说,有了两个点作为左上角的点和右下角的点也可以确定这个矩形,因此我们只要保存两个点,就足够保存这两种图形的位置和大小的信息。paint()函数是Shape类的一个纯虚函数,子类都必须实现这个函数。我们现在有两个子类:Line和Rect,分别定义如下:
 
line.h
#ifndef LINE_H 
#define LINE_H 
 
#include  "shape.h" 
 
class Line :  public Shape 
{ 
public: 
        Line(); 
 
         void paint(QPainter &painter); 
}; 
 
#endif  // LINE_H 
 
line.cpp
#include  "line.h" 
 
Line::Line() 
{ 
} 
 
void Line::paint(QPainter &painter) 
{ 
        painter.drawLine(start, end); 
} 
 
rect.h
#ifndef RECT_H 
#define RECT_H 
 
#include  "shape.h" 
 
class Rect :  public Shape 
{ 
public: 
        Rect(); 
 
         void paint(QPainter &painter); 
}; 
 
#endif  // RECT_H 
 
rect.cpp
#include  "rect.h" 
 
Rect::Rect() 
{ 
} 
 
void Rect::paint(QPainter &painter) 
{ 
        painter.drawRect(start.x(), start.y(), 
                                         end.x() - start.x(), end.y() - start.y()); 
} 
 
使用paint()函数,根据两个点的数据,Line和Rect都可以绘制出它们自身来。此时就可以看出,我们之所以要建立一个Shape作为父类,因为这两个类有几乎完全相似的数据对象,并且从语义上来说,Line、Rect与Shape也完全是一个is-a的关系。如果你想要添加颜色等的信息,完全可以在Shape类进行记录。这也就是类层次结构的好处。
 
代码很多也会比较乱,附件里面是整个工程的文件,有兴趣的朋友不妨看看哦!

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

《QT从基础到进阶·十五》用鼠标绘制矩形(QGraphicsView、QPainter、QGraphicsRectItem) 在GraphicsView类中创建矩形绘制对象,并初始化该对象用于绘制矩形。在GraphicsView类的鼠标事件中设置绘制矩形时鼠标按下,移动,释放操作。矩形长宽的拖动会在DrawROI类中实现,界面的缩放把DrawROI类中的功能放入GraphicsView中的滚轮事件中。以下是鼠标绘制矩形最全的一种用法,完整源码将会放在最后面。 阅读详情

相关推荐

Qt鼠标拖动绘制基本几何图形(直线、矩形、圆形、椭圆)

用Qt鼠标事件实现基本几何图形的绘制,支持直线、矩形、圆形、椭圆。后期可以在此基础上进行扩展。使用QGraphics完成。 本示例使用QGraphics体系来实现,因为要移动对象,所以生成的图形必须是一个单独的对象,鼠标拖动绘制的过程是在临时层中完成,release后生成一个矢量的图形item并添加到场景中。 博客地址:https://blog.youkuaiyun.com/luoyayun361/article/details/93890331

在QLabel上显示图片,并在图片上画矩形ROI

在QLabel上显示图片,并在图片上画矩形ROI

zhaojiandeai的博客 951

RV1126B芯片实战:如何用这款视觉处理器SoC打造你的第一个AI摄像头项目

本文详细介绍了如何利用瑞芯微RV1126B视觉处理器SoC从零构建AI摄像头项目。涵盖硬件选型、开发环境搭建、ISP配置、AI模型部署及系统集成等关键步骤,帮助开发者高效实现边缘计算方案,特别适合智能安防和工业检测应用。

dropout6artist的博客 931

qt制作一个画板_Qt学习之路(31): 一个简易画板的实现(QWidget)

说实话,本来我是没有打算放一个很大的例子的,一则比较复杂,二来或许需要很多次才能说得完。不过,现在已经说完了绘图部分,所以计划还是上一个这样的例子。这里我会只做出一个简单的画板程序,大体上就是能够画直线和矩形吧。这样,我计划分成两种实现,一是使用普通的QWidget作为画板,第二则是使用Graphcis View Framework来实现。因为前面有朋友说不大明白Graphics View的相关内...

weixin_39834149的博客 346

机器学习 -- 信用卡评分模型 -- 互联网金融风控

互联网金融主要分为资金类和资产类。资金类主要是理财产品,吸储,主要指标是用户转化、留存和复投,重在客户运营。资产类主要是贷款,包括消费金融和现金贷,小额贷款属于此类,主要目的是用户转化,还款和风险控制,信用卡评分模型就属于风险控制。 信用评分作用是对贷款申请人(信用卡申请人)做风险评估分值的方法。 信用卡评分是以大量数据的统计结果为基础,根据客户提供的资料和历史数据对客户的信用进行评估,评分卡模型...

XiaoMaEr66的博客 2419

BUCK降压电路设计实战:从理论到PCB的完整指南

本文详细介绍了BUCK降压电路的设计实战,从基础原理到PCB布局的完整指南。通过关键部件选型、PCB布局黄金法则和调试技巧,帮助工程师高效设计稳定可靠的开关电源。特别针对电感、MOSFET和电容选型提供实用公式和避坑指南,并分享高温环境下的工程经验与测试方法。

weixin_33744141的博客 452

一个简易画板的实现(QWidget)-31

说实话,本来我是没有打算放一个很大的例子的,一则比较复杂,二来或许需要很多次才能说得完。不过,现在已经说完了绘图部分,所以计划还是上一 个这样的例子。这里我会只做出一个简单的画板程序,大体上就是能够画直线和矩形吧。这样,我计划分成两种实现,一是使用普通的QWidget作为画板,第 二则是使用Graphcis View Framework来实现。因为前面有朋友说不大明白Graphics View的相关内容,所以计划如此。 好了,现在先来看看我们的主体框架。我们的框架还是使用Qt Creator创建一个Gu

啃骨头的小蚂蚁 515

从MC到DC:三维重建算法的核心原理与实战对比

本文深入对比了三维重建领域两大经典算法Marching Cubes(MC)与Dual Contouring(DC)的核心原理与实战表现。MC算法原理直观、实现简单,但存在特征丢失和二义性问题;DC算法通过求解二次误差函数(QEF)和利用法向量信息,能更好地保留模型的尖锐特征,但计算更复杂。文章结合医学影像处理实例,为开发者根据速度、精度和特征保真度需求选择合适算法提供了清晰指南。

weixin_29251131的博客 1032

Qt5_简易画板_详细注释

Qt5_简易画板_详细注释 代码下载链接: http://pan.baidu.com/s/1hsc41Ek 密码: 5hdg 显示效果如下: 代码附有详细注释(代码如下) 1 /*** 2 * 先新建QMainWindow, 项目名称: DrawWidget 基类选择: QMainWindow, 3 * 类名默认...

豆子 408

《哥谭神话-工程篇》01.Palantir 平台架构解析-混乱数据如何转化唯一真相源?

Palantir 平台的架构哲学可以概括为将洞察落地为行动,其核心是将“获取唯一真相”能力深度嵌入现有的、复杂的工作流程中,成为提升运营效率和决策质量的倍增器。

897

uniapp 如何封装实现任意页面都能使用的全局弹窗

项目内容场景全局监听消息提示难点uniapp 无法全局挂载组件解决方案动态创建 DOM + 动态 Vue 实例优势跨页面 / 不依赖页面组件树 / 灵活调用如果你使用的是小程序平台,DOM 操作可能受限,需要用或方式兼容处理。想支持多个弹窗堆叠?你可以扩展,加个弹窗队列管理器。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 944

Qt实现简易计算器

  创建基于QWidget的cacul项目,包含.ui文件,其余设置不变   cacul.pro #------------------------------------------------- # # Project created by QtCreator 2019-04-24T19:16:05 # #--------------------------------------------...

The_perfect_world的博客 1167

扣子(Coze)搭建智能体完整实战指南 —— 从零基础入门到写小说及其他需求扩展开发

随着大语言模型进入应用爆发期,我们正在经历从“寻找提示词”向“构建智能体”的范式转移。扣子(Coze)作为字节跳动推出的一站式AI智能体开发与运营平台,极大地降低了AI应用开发的门槛,让非技术人员也能快速搭建具备感知、决策、行动能力的智能体。 本文将手把手带你从零开始,在扣子平台上搭建一个功能完备的**小说创作智能体**,并基于此展示如何将同一套架构扩展到其他需求场景。无论你是写作爱好者、内容创作者,还是希望用AI赋能日常工作的职场人士,这套完整的技术方案都将帮助你快速上手。

huanghm88的专栏 637

PyQt(Python+Qt)入门:Designer组件属性编辑界面中QWidget类相关属性详解

一、引言 本文适用人员:本文比较长,适合不理解Qt Designer部件属性的人员阅读或资料查找。 声明:如果有人认为本文是复制粘贴+翻译而成的,敬请读本文最后的后记。 在Qt Designer中,提供了八大类可视化组件(也称为组件或控件,下同),分别为布局组件(Layouts)、分隔组件(Spacers)、按钮组件(Buttons)、表项视图(item views)、表项组件(item widg...

老猿Python 1万+

【用unity实现100个游戏之1】制作类元气骑士、挺进地牢——俯视角射击游戏多种射击效果(一)(附源码)

俯视角射击游戏)是一类以俯视视角进行游戏展示的射击游戏。在这种游戏中,玩家控制着一个角色或载具,从俯视的角度上方观察游戏世界,并与敌人进行战斗。这种视角使玩家能够有更好的全局观察和策略性,同时也强调快速反应和精确射击。视角:俯视角度可以是固定的,也可以随着玩家角色的移动而变化,但都允许玩家以全局视角观察整个战场,有利于制定战略和规划行动。射击:玩家通常需要使用各种武器来与敌人进行战斗,包括枪械、爆炸物等。射击动作依赖于玩家的反应速度和准确性。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 7831

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Qt中的常用组件:QWidget篇

QPixmap用于展示图像,QCursor可以设置光标效果,比如我们可以先用图像文件构建QPixmap对象,需要的话可以使用scaled调整大小,再通过这个QPixmap构造QCursor,将其设置进我们所需要的小组件,比如QPushButton,同时如果需要的话,可以构建一个热点(即实际点击的位置),就能够实现将光标放在某个组件上时将光标替换为我们所需要的光标图像的效果。提供给用户一个日历(精确到年月日),能够让用户选择日期,并通过selectionChanged信号来获取用户选择的日期。

wangjialelele的博客 1063

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

【Qt】QWidget类详解(属性篇)

00. 目录 文章目录00. 目录01. 概述02. 顶层widget和子widget03. 复合型Widget04. 自定义控件和绘制方式05. Size Hints和Size Policies06. 事件(Events)07. 函数和属性组08. Widget样式表09. 透明和双缓冲10. 创建半透明窗口11. Native Widgets和 Alien Widgets12. 成员类型文档13. 属性文档13.1 acceptDrops: bool13.2 accessibleDescription

C/C++软件工程师、嵌入式软件工程师、物联网研发工程师、C/C++讲师、物联网讲师、嵌入式讲师、鸿蒙讲师---欢迎大家一起交流(私信添加博主微信) 1万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

VS2017+QT实现折叠/展开布局功能

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Ma...

weixin_45572800的博客 1万+

「Qt Widget中文示例指南」如何实现一个旋转框(一)

本文将为大家介绍如何使用Qt Widget小部件如何实现一个旋转框示例,欢迎下载最新版组件体验~

需要界面开发、IDE工具研发中文教程资料的小伙伴,记得私信我~ 914

修改Qt源码支持DPI粒度到QWidget

什么???居然支持高DPI 自定义QWidget适应

Mingyueruya的专栏 1251
上一篇: Qt学习之路(30): Graphics View Framework
下一篇: Qt学习之路(32): 一个简易画板的实现(Graphics View)
flowingFire2012
博客等级 码龄14年 6粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值