Romi-知行合一

轻轻的风轻轻的梦,轻轻的晨晨昏昏, 淡淡的云淡淡的泪,淡淡的年年岁岁。
  博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

图像拖拽

Posted on 2012-11-22 15:28  romi  阅读(2509)  评论(5编辑  收藏  举报

在QGraphicsView框架中实现图像拖拽,固然可以使用滑动条拖动,但是如果可以使用鼠标在图像上面进行拖动,岂不是更方便,但遥感处理软件都有这种功能嘛。

要实现拖拽,首先就要获得鼠标事件,通常是按下鼠标左键,然后拖动图像,鼠标释放时拖动结束。核心的问题就是如何实现图像的移动。这里有两个思考的出发点:

一个就是根据图像项在场景中的坐标;

另一个就是通过改变滑动条的值。

前者没有研究清楚,未实现,采用后者实现了,后者实现也简单。因为GraphicsView自身带有滑动条,所以可以设置滑动条的值来移动图像。

本文使用改变滑动条的值实现,要点有两个:一是重写QGraphicsView类中的鼠标事件,二是捕捉鼠标移动的长度,然后使滑动条改变相应的值,从而实现图像移动。

1.重写鼠标事件

这里在Qt设计师中将QGraphicsView类进行提升,也即自定义一个类,该类继承自QGraphicsView,将该类作为显示图像的部件,假设类的名称为ImgGraphicsView,则在类ImgGraphicsView中重写鼠标按下、鼠标移动、鼠标释放的事件

鼠标事件的逻辑为:先按下鼠标,然后鼠标移动,鼠标移动时图像跟着移动,鼠标释放,图像停止移动。

所以处理的是鼠标左键,鼠标右键不管。而且鼠标移动是在鼠标按下后捕捉的,因此要进行鼠标跟踪的设置

setMouseTracking(false);

详见帮助文档:

还需设置一个标识符,用于判断鼠标左键是否按下。移动图像时需要知道的信息有移动前鼠标所在坐标和移动后鼠标所在坐标,两坐标之差就是图像要移动的距离(分X轴和Y轴),然后在滑动条当前值加上增加的移动距离即可得到新的滑动条值,然后图像就移动了。这里最关键的就是如何将鼠标坐标值传给主界面中的ImgGraphicsView部件,实现图像移动。

鼠标左键点下时坐标:x1,y1

鼠标移动时的坐标:x2,y2

鼠标移动时的坐标值是在ImgGraphicsView类中实现的,而图像操作是在主窗口类中实现的,我的方法是在主窗口类中使用定时器,定时间隔假设为200ms,定时时间到时获取ImgGraphicsView部件对象的成员变量值(将鼠标左键按下是坐标和鼠标移动时的坐标均定义为ImgGraphicsView类成员,其值随着鼠标事件而变化)。就可以只带鼠标此时的坐标点与鼠标按下时的坐标点,分别对X和Y轴做差,求出鼠标在X和Y轴上的移动距离,该距离就是图像该移动的距离,然后改变当前ImgGraphicsView对象中的滑动条的值即可实现图像的滑动。

要注意的是,鼠标左键按下时,x2=x1,y2=y1,保持x2和y2的更新,防止鼠标不移动定时时间到了图像还是滑动了(因为x2,y2还是原值)。此外,鼠标释放时标识符还原,x1=x2,y1=y2。

代码就不贴了,理解上上述原理之后,就很容以写出源代码了,关键是实现的方法原理。下面是设置滑动条的值的方法:

1 int x=ui.graphicsView->horizontalScrollBar()->value();
2 int y=ui.graphicsView->verticalScrollBar()->value();
3 int dx=ui.graphicsView->x1-ui.graphicsView->x2;
4 int dy=ui.graphicsView->y1-ui.graphicsView->y2;
5 ui.graphicsView->horizontalScrollBar()->setValue(x+dx);
6 ui.graphicsView->verticalScrollBar()->setValue(y+dy);