Qt 简易画板

用Qt框架搭建一个简易画板

  • 需求

    • 绘制线、椭圆、矩形框、任意凹/凸多边形、曲线
    • 删除最近的图形实例
  • 思路

    • 用list保存绘制的图形实例,便于删除
    • 对于line、rectangle、ellipse 只要保存初始位置和结束位置
    • 对于任意凸/凹多边形可以用一个list保存点集
    • 利用Graphics View 管理图形对象
    • Graphics View 是M-V框架,model指的是各种图形对象,view指的是视角
    • 使用过程是:创建一个scene,创建line和rectangle等图形实例,再使用scene的add函数将line、rectangle实例等添加到scene中,最后通过视口view就可以看到了;同一个model可以从不同的view进行观察
    • 创建图形对象继承于父类Shape,绘制完毕后将图形对象存储在List中,点击删除按钮时,从List中出栈一个图形对象,重绘
    • 界面样式

    • 按钮描述(从左至右)

      直线按钮:点击进入绘制直线模式:按下左键设置起始点,拖动鼠标至结束点,释放左键绘制完毕

      矩形按钮:点击进入绘制矩形模式:按下左键设置左上角,拖动鼠标至结束点,释放左键绘制完毕

      椭圆按钮:点击进入绘制椭圆模式:同矩形按钮

      多边形按钮:点击进入绘制多边形模式:单击左键设置起始点,拖动鼠标至下一个转折点,继续单击鼠标添加转折点,直到单击右键结束绘制

      曲线按钮:点击进入绘制曲线模式:左键按下并拖动鼠标绘制

      删除按钮:点击进入删除模式:逆序删除绘制的图形对象

  • 问题解决Q&A

    1.问题: 在Qt中,添加类之后经常出现“无法解析的外部命令的问题”

    解决方法:http://blog.csdn.net/yz960611/article/details/50735406

    http://blog.csdn.net/zhoxier/article/details/8619688

  • Tuitor

    1.创建主界面

    这一步主要是mainWindow.cpp、mainWindow.h、mainWindow.ui三个文件

    • 新建Qt Widegts Application,项目名是miniDraw,基类是QMainWindow,类名是MainWindow,头文件mainWindow.h,源文件mainWindow.cpp,勾选创建界面。

    • 在mainWindow.h中添加头文件

      #include<vector>

      #include<shape.h>//后面会讲到

    • 添加成员变量

      ```cpp

      private:

      Shape::drawMode mode;//保存目前的绘图模式,分为七中,在shape.h中定义

      Shape *shape;//五种不同的图形对象

      bool isDone=false;//是否绘制完毕

      QList shapeList;//保存图形对象

      QVector polygon_point_array;//保存正在绘制的多边形的点

      QVector freehand_point_array;//保存正在绘制的曲线的点

      QPoint freePoint;//鼠标当前位置

  1. * 添加成员函数
  2. ```cpp
  3. protected:
  4. void paintEvent(QPaintEvent *event);//绘图事件,用update()调用
  5. void mousePressEvent(QMouseEvent *event);//鼠标按下
  6. void mouseMoveEvent(QMouseEvent *event);//鼠标移动
  7. void mouseReleaseEvent(QMouseEvent *event);//鼠标释放
  • 编写界面

    仿照主界面示意图添加组件,具体使用方法查看Qt Designer,使用设计模式创建界面

    (基本步骤:1、创建actionLine;2、编辑图标;3、添加statusTip;4、转到槽函数;)

    2、创建各种图形对象的父类——Shape类

    (1、右键单击工程;2、添加新文件;2、C++ Class;3、Define Class)

    ```cpp

    //shape.h

ifndef SHAPE_H

define SHAPE_H

include

include

class Shape

{

public:

enum drawMode//绘图模式

{

LINE,

RECT,

ELLIPSE,

POLYGON,

FREEHAND,

DELETE,

DEFAULT

};

Shape();

virtual ~Shape();//虚函数,防止内存泄漏,具体见后面

void setStart(QPoint start)

{

this->start=start;

}

void setEnd(QPoint end)

{

this->end=end;

}

QPoint getStart()

{

return start;

}

QPoint getEnd()

{

return end;

}

void virtual paint(QPainter &painter)=0;//需要在子类中重写的函数设置为虚函数

protected:

QPoint start,end;

};

endif // SHAPE_H

  1. ```cpp
  2. //shape.cpp
  3. #include "shape.h"
  4. Shape::Shape()
  5. {
  6. }

2.1创建子类line、Rectangle、Ellipse、Polygon、FreeHand——主要是重写paint函数

  • line

    ```cpp

    void line::paint(QPainter &painter)

    {

    painter.drawLine(start,end);

    }

  1. * **rectangle**
  2. ```cpp
  3. void Rectangle::paint(QPainter &painter)
  4. {
  5. painter.drawRect(start.x(),start.y(),end.x()-start.x(),end.y()-start.y());
  6. }
  • ellipse
  1. void Ellipse::paint(QPainter &painter)
  2. {
  3. painter.drawEllipse(start.x(),start.y(),end.x()-start.x(),end.y()-start.y());
  4. }

以上这些都很简单

  • freehand

    ```cpp

    //freehand.h

ifndef FREEHAND_H

define FREEHAND_H

include"shape.h"

include

class FreeHand:public Shape

{

public:

FreeHand();

FreeHand(const QVector &point_array);//利用Vector构造

void paint(QPainter &painter);

protected:

QVector free_point_array;//保存曲线上的一系列点

};

endif // FREEHAND_H

  1. ```cpp
  2. //构造函数和绘制函数的实现
  3. FreeHand::FreeHand(const QVector<QPoint> &point_array)
  4. {
  5. for(size_t i=0;i<point_array.size();i++)
  6. {
  7. //free_point_array[i]=point_array[i];
  8. free_point_array.push_back(point_array[i]);
  9. }
  10. }
  11. void FreeHand::paint(QPainter &painter)
  12. {
  13. for(size_t i=0;i<free_point_array.size()-1;i++)
  14. {
  15. painter.drawLine(free_point_array[i],free_point_array[i+1]);
  16. }
  17. }
  • polygon

    ```cpp

    //构造函数和绘图函数的实现

    Polygon::Polygon(const QVector &points)

    {

    for(size_t i=0;i<points.size();i++)

    {

    pointList.push_back(points[i]);

    }

    }

    void Polygon::paint(QPainter &painter)

    {

    for(size_t i=0;i<pointList.size()-1;i++)

    {

    painter.drawLine(pointList[i],pointList[i+1]);

    }

    painter.drawLine(pointList.back(),pointList.front());

    }

  1. **以上两个是比较难的,需要考虑一下**
  2. **3整体逻辑——对成员函数的实现**
  3. **3.1给按钮添加槽函数**
  4. (这里我是采用Qt Creator 添加的,这不是我们讲的重点)
  5. ```cpp
  6. void MainWindow::on_actionLine_triggered()
  7. {
  8. mode=Shape::drawMode::LINE;
  9. }
  10. void MainWindow::on_actionRectangle_triggered()
  11. {
  12. mode=Shape::drawMode::RECT;
  13. }
  14. void MainWindow::on_actionEllipse_triggered()
  15. {
  16. mode=Shape::drawMode::ELLIPSE;
  17. }
  18. void MainWindow::on_actionPolygon_triggered()
  19. {
  20. mode=Shape::drawMode::POLYGON;
  21. }
  22. void MainWindow::on_actionFreehand_triggered()
  23. {
  24. mode=Shape::drawMode::FREEHAND;
  25. }
  26. void MainWindow::on_actionDelete_triggered()
  27. {
  28. mode=Shape::drawMode::DELETE;
  29. if(!shapeList.isEmpty())
  30. {
  31. shapeList.pop_back();//最后一个图形对象出栈
  32. mode=Shape::DEFAULT;//设置模式为默认模式
  33. update();
  34. }
  35. }
  • 逻辑就是点击不同的按钮进入不同的绘制模式

    3.2给鼠标按键添加监听

    • 绘制直线:按下鼠标左键拖动鼠标,直到目的位置释放鼠标;
    • 绘制矩形:同绘制直线;
    • 绘制椭圆:同绘制矩形
    • 绘制多边形:点击鼠标左键设置第一个锚点,再次单击设置第二个锚点,以此类推,设置完最后一个锚点后点击鼠标右键结束绘制;
    • 绘制曲线:按住左键不放绘制曲线,释放左键结束绘制
    • 从功能需求我们可以看出,绘制直线、矩形、椭圆实际上只需要两个点就可以确定,那么就可以按按下鼠标的位置作为起始位置,释放鼠标的位置作为结束位置
    • 绘制多边形和绘制曲线很相似,就是往vector里面添加一系列点
    • 因此,在绘制直线、椭圆、矩形的时候,可以在按下左键的时候就将图形对象保存进shapeList
    • 在绘制曲线、多边形时可以在主函数里面暂存这一系列点,等绘制完毕再把图形对象保存进shapeList,这样可以提高绘制的效率

    ```cpp

    //鼠标按下

    void MainWindow::mousePressEvent(QMouseEvent *event)

    {

    switch (event->button()) {

    case Qt::LeftButton ://在绘制直线、矩形、多边形、椭圆、曲线时有效,开始绘制

    switch (mode) {

    case Shape::DEFAULT:

    break;

    case Shape::DELETE:

    //do nothing

    break;

    case Shape::LINE:

    shape=new line;

    break;

    case Shape::RECT:

    shape=new Rectangle;

    break;

    case Shape::ELLIPSE:

    shape=new Ellipse;

    break;

    case Shape::FREEHAND:

    shape=new FreeHand;

    break;

    case Shape::POLYGON:

    shape=new Polygon;

    break;

    default:

    break;

    }

    break;

    case Qt::RightButton: //仅在绘制多边形时有效,结束绘制

    if(mode==Shape::POLYGON)

    {

    isDone=true;

    if(polygon_point_array.size()>0)

    {

    shape=new Polygon(polygon_point_array);

    shapeList.push_back(shape);

    polygon_point_array.clear();

    update();

    shape=NULL;

    }

    }

    break;

    default:

    break;

    }

    if(shape!=NULL){//刚开始绘制

    if(mode==Shape::POLYGON)//设置转折点

    {

    isDone=false;

    polygon_point_array.push_back(event->pos());//添加进锚点

    freePoint=event->pos();

    update();

    }else if(mode==Shape::FREEHAND)

    {

    isDone=false;

    freehand_point_array.push_back(event->pos());//添加进锚点

    }

    else {

    isDone=false;

    shape->setStart(event->pos());

    shape->setEnd(event->pos());

    shapeList.push_back(shape);//将图形对象入栈

    }

    }

    }

  1. ```cpp
  2. //鼠标移动
  3. void MainWindow::mouseMoveEvent(QMouseEvent *event)
  4. {
  5. if(shape&&!isDone)
  6. {
  7. if(mode==Shape::FREEHAND)
  8. {
  9. freehand_point_array.push_back(event->pos());//添加曲线点序列
  10. update();
  11. }else
  12. {
  13. shape->setEnd(event->pos());
  14. freePoint=event->pos();
  15. update();
  16. }
  17. }
  18. }
  1. //鼠标释放
  2. void MainWindow::mouseReleaseEvent(QMouseEvent *event)
  3. {
  4. if(event->button()==Qt::LeftButton)//仅在左键释放时有效,结束绘制直线、矩形、椭圆、曲线
  5. {
  6. switch (mode) {
  7. case Shape::POLYGON:
  8. break;
  9. case Shape::FREEHAND:
  10. isDone=true;
  11. shape=new FreeHand(freehand_point_array);
  12. freehand_point_array.clear();
  13. shapeList.push_back(shape);
  14. update();
  15. shape=NULL;
  16. break;
  17. default:
  18. isDone=true;
  19. update();
  20. shape=NULL;
  21. break;
  22. }
  23. }
  24. }


以上

来自为知笔记(Wiz)

时间: 2024-08-02 06:50:11

Qt 简易画板的相关文章

canvas简易画板。

在学canvas的时候,想到可以做一个自己用来画画的简易画板,加上canvas的基础都已经学完,便尝试做了一个画板.如图 1.获取标签. var c=document.getElementById('myCanvas'); var ctx= c.getContext('2d');var b=document.getElementById('b'); var b1=document.getElementById('b1'); var bbb=document.getElementById('bbb

JavaScript 简易画板

html 5 canvas只是一个容器,想要画出东西全部依赖于JavaScript.感觉什么都离不开这个JavaScript脚本. 简易画板核心代码: <script> var start = false;//绘制开关是否开始? window.onload = function(){ var cvs = document.getElementById("cvs"); var cxt = cvs.getContext("2d"); //鼠标在画板上按下 c

Kivy 中文教程 实例入门 简易画板 (Simple Paint App):0. 项目简介 &amp; 成果展示

本教程咪博士将带领大家学习创建自己的窗口部件 (widget).最终,我们完成的作品是一个简易的画板程序. 当用 kivy 创建应用时,我们需要仔细思考以下 3 个问题: 我们创建的应用需要处理什么数据? 如何可视化地展示这些数据? 用户如何与这些数据交互? 以本教程的简易画板为例,我们希望用户可以用手指在触摸屏上画画,这便是用户与数据交互的方式.为了实现这样的交互,我们需要记录下用户手指的位置,这便是应用需要处理的数据.而在不同位置点之间绘制线条就是数据展示的方式. Kivy 应用中,用户界面

Kivy 中文教程 实例入门 简易画板 (Simple Paint App):1. 自定义窗口部件 (widget)

1. 框架代码 用 PyCharm 新建一个名为 SimplePaintApp 的项目,然后新建一个名为 simple_paint_app.py 的 Python 源文件, 在代码编辑器中,输入以下框架代码 1 from kivy.app import App 2 from kivy.uix.widget import Widget 3 4 5 class MyPaintWidget(Widget): 6 pass 7 8 9 class MyPaintApp(App): 10 def buil

Kivy 中文教程 实例入门 简易画板 (Simple Paint App):2. 实现绘图功能

1. 理解 kivy 坐标系统 上一节中,咪博士带大家实现了画板程序的基础框架,以及一个基本的自定义窗口部件(widget).在上一节的末尾,咪博士留了一道关于 kivy 坐标系统的思考题给大家.通过点击窗口的 4 个角落,观察相应的控制台输出,我们可以推断出 kivy 的坐标原点位于窗口的左下角,x 轴正方向为水平向右,y 轴正方向为竖直向上.这和我们中学数学中常见的平面直角坐标系是一模一样的. 2. 绘制圆点 了解了 kivy 的坐标系统,本节咪博士将教大家实现简易画板的核心功能:绘图. 重

qt 5 小练习 简易画板

如何在窗口上画线?用一根根线来拼凑图案呢? 想必大家都知道点的集合是线,而线的集合就是很多线啦,用线的集合我们能拼凑出许许多多的图案.于是我就要记录自己跟着老师的学习之路啦: 既然有集合的话,势必要用到QVector,这是一个QT提供给我们的容器,而QVector<QPoint> line; 则表示的就是一条线,那我们怎么表示线的集合呢? QVector< QVector<QPoint> > lines; 首先,我们从简单做起,在画板上画一条线,我们都知道画线的话,有起

用Java语言编写一个简易画板

讲了三篇概博客的概念,今天,我们来一点实际的东西.我们来探讨一下如何用Java语言,编写一块简易的画图板. 一.需求分析 无论我们使用什么语言,去编写一个什么样的项目,我们的第一步,总是去分析这个项目需要满足怎样的需求. 那么,画板需要满足怎样的需要呢?换句话说,在画板上,我们应该赋予它什么功能呢?从我们熟悉的画板来看,我们需要实现诸如铅笔.橡皮.喷枪.刷子的功能,我们可以画出一些规则的图形,比如直线.矩形.圆.最好我们还能调整画笔的颜色和粗细.以上,我们希望的是,当我们点击一个按钮的时候,我们

Qt5_简易画板_详细注释

代码下载链接:  http://pan.baidu.com/s/1hsc41Ek 密码: 5hdg 显示效果如下: 代码附有详细注释(代码如下) 1 /*** 2 * 先新建QMainWindow, 项目名称: DrawWidget 基类选择: QMainWindow, 3 * 类名默认, 然后在DrawWidget项目名上新建c++class文件, 选择基类: QWidget 4 */ 5 //先完成绘图区的实现 6 //如下为: drawwidget.h 7 #ifndef DRAWWIDG

Qt 简易设置透明按钮

QPushButton *bt =new QPushButton(this); bt->setText("ok"); bt->move(200,100); bt->setFlat(true);//就是这句能够实现透明,真是意外的发现,希望对一些学习的朋友有点帮助