最近使用Qt开发了一个绘图软件,实现了拖动和放缩的功能。这里大体描述一下思路:
1、自定义类继承图形项:
class MyItem : public QGraphicsItem
重写以下方法
QRectF boundingRect()const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QPainterPath shape()const;
重写以下鼠标事件
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
2、自定义类继承视图:
class MyView : public QGraphicsView
重写以下事件
//void paintEvent(QPaintEvent *pEvent);
void mousePressEvent(QMouseEvent *mEvent);
void mouseMoveEvent(QMouseEvent *mEvent);
void mouseReleaseEvent(QMouseEvent *mEvent);
3、值得注意的地方:
(1)绘制放缩时候出现的皮筋效果:其实就是用虚线画出图形的外接矩形,为了区分图形是画好了,还是正在绘制中,可以加一个bool标记
(2)拖动和放缩:判断鼠标位置,在外接矩形边界上可以放缩,在矩形内部可以拖动,可以改变鼠标形状表现出来,也需要一个bool标记
(3)事件传递机制:由于视图和图形项都重写了鼠标事件,就会有一个问题,鼠标拖动等事件先从视图获得,然后传递到图形项,使用一个全局变量标记,这样
就不会出现图形项拖动带动视图中绘出内容
(4)坐标系的变换:在视图中绘制的图形坐标要变换到场景中去,由场景去负责图形项的管理,否则拖动的时候绘图会显示错位
(5)随笔画:继承item,写鼠标事件的时候,要注意判断点的位置,不能保证第一个点就在第二个点的左上方
目前界面大致如下:比较简单,菜单栏懒的写,工具栏只加了删除Action
目前实现的功能如下:
可以通过选择图形,然后在画布上拖动鼠标绘制简单几何图形,比如:直线,椭圆,矩形,一般四边形,五边形,六边形;
可以选中图形,进行移动;
可以通过图形四边进行放缩;
可以删除选中的图形,可以清空整个画布;
可以随笔涂鸦,画任何曲线,写字;
可以更换画笔的类型和大小;
可以更改画笔和填充颜色。
目前存在的问题如下:
程序结构不合理,把scene放在view里面,作为成员变量,明显不科学;view里面控制item的加减不符合实际。
更好的思路是自定义一个类继承QWidget,作为QMainWindow的中央控件,然后把scene和view都放进去。
继承view,重写view的事件不合理,最后重写widget的鼠标事件。
继承item,本身合理,但是应该把图形的属性分开单独设计图形类,然后把图形对象作为成员,沟通view和item的思路不合理,要用信号和槽。
删除有一个bug,那就是删除所有的item以后,再次添加会不显示,没有调试,虽然现在使用hack的方式解决了,但是习惯不好,不合理。
所犯过的低级错误:
以为写view的paint事件就能在view上显示,太天真,view显示的东西还是item绘制的,view只是一个媒介。
有人把scene比喻成黑板,item比如在黑板上画的图形或者写的字,而view呢,只相当于一个照相机,把黑板上的字照下来,给你看罢了。
另外,一个c++的傻逼错误,居然用指针共享对象,然后指针被后面的操作改变了,都没有发现,调试半天。