返回   cpper编程论坛 > 技术杂烩
注册账号 论坛帮助 会员列表 日历事件 搜索 今日新帖 标记版面已读

技术杂烩 找不到地方的技术问题?这里!

回复
 
LinkBack 主题工具 显示模式
  #1 (permalink)  
旧 2005-05-24
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认 捕捉鼠标输入的方法

有些画图工具,比如windows自带的那个,在画某些图形时,比如一个长方形,是先按下左键,然后拖动,再松开左键,这样会以按下和松开的两点为顶点,画出一个矩形。
现在若要在纯API的环境下实现这个功能,那么就要捕捉鼠标的输入,根据不同的鼠标动作,收集不同的数据,再生成相应的图形。
我现在的方法是在图形和WndProc见加一个中间类,MouseCapture,定义一个捕捉鼠标消息的Method:virtual void PostMouseMsg(...),再派生出CreateCapture类处理建立图形时的鼠标输入,再由其派生出RectCrtCpature,重新实现具体的处理鼠标输入。然后Create出(或者从个factory中生成)Rect,塞入全局容器中。
不过感觉上要处理各种输入状态(比如有时要移动该图形,有时要旋转该图形),要么在某个MouseCapture派生类中设立各种状态的flag,然后不同处理;要么再派生出特定的类处理特定图形,会比较庞杂。
一般处理这些输入信息,大家是怎么做的呢?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #2 (permalink)  
旧 2005-05-24
普通会员
 
注册日期: 2004-08-19
帖子: 87
wwwttt579 正向着好的方向发展
默认

我也比较迷惑。上次一个简单的图形处理程序,偶定义了一个base tool,定义了虚函数 mousedown, mousemove, mousemove,然后由派生类实现各操作。但是在判断使用哪一个操作方面可能会不方便:如果不是每次选定了工具后操作,而是根据鼠标的位置或其他判断可能是什么操作。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #3 (permalink)  
旧 2005-05-24
lxcLinuxer 的头像
初级会员
 
注册日期: 2005-01-03
帖子: 24
lxcLinuxer 正向着好的方向发展
默认

只要记录最基本的信息就行,比如长方形的2个点啊。
至于操作吗,在OnDraw中调用相关的函数就行了。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #4 (permalink)  
旧 2005-05-24
Elminster 的头像
超级版主
 
注册日期: 2002-09-09
帖子: 1,764
Elminster 正向着好的方向发展
默认 Re: 捕捉鼠标输入的方法

引用:
作者: Bankrock
有些画图工具,比如windows自带的那个,在画某些图形时,比如一个长方形,是先按下左键,然后拖动,再松开左键,这样会以按下和松开的两点为顶点,画出一个矩形。
现在若要在纯API的环境下实现这个功能,那么就要捕捉鼠标的输入,根据不同的鼠标动作,收集不同的数据,再生成相应的图形。
我现在的方法是在图形和WndProc见加一个中间类,MouseCapture,定义一个捕捉鼠标消息的Method:virtual void PostMouseMsg(...),再派生出CreateCapture类处理建立图形时的鼠标输入,再由其派生出RectCrtCpature,重新实现具体的处理鼠标输入。然后Create出(或者从个factory中生成)Rect,塞入全局容器中。
不过感觉上要处理各种输入状态(比如有时要移动该图形,有时要旋转该图形),要么在某个MouseCapture派生类中设立各种状态的flag,然后不同处理;要么再派生出特定的类处理特定图形,会比较庞杂。
一般处理这些输入信息,大家是怎么做的呢?
??
为什么要这样做?鼠标左键点下去的时候,已经可以确定要做什么操作了,那个时候建立一个能够 handle 那种 operation 的类的对象,然后交给它不就完了?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #5 (permalink)  
旧 2005-05-24
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认

在某些时候确实是知道要处理的事情,但有些时候便不是这样。比如你按住矩形的一边拖动鼠标时可以缩放大小,按住矩形内部拖动鼠标时可以移动。这样这个“能够 handle 那种 operation 的类的对象”(也就是我说的那个MouseCapture类体系)便要根据这些不同的情况判断来装载一个相应的处理类(这个可以由一个函数完成),然后把所有的鼠标消息都发送到这个类去。
现在就是这种方法处理消息算不算好呢?还有什么更简练优雅的办法?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #6 (permalink)  
旧 2005-05-24
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认

刚才说错了一点:在根据不同鼠标动作给出不同的鼠标信息处理对象时,需要某个特定的图形类知道与之相应的处理对象是什么。我现在是这么想的:
1。每个图形类里设立一个虚拟函数来生成不同的能处理该图形信息的类。
代码:
class Rect : public Shape //Shape是虚拟基类 { virtual MouseCapture * GetHandle() { return new RectHandle(this); }; virtual bool Selected(LPARAM lParam); ........ }
然后便可以由一个全局函数处理鼠标信息:
[code]
void SetMouseCapture(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
for (std::vector<Shape*>::iterator it = vecShapes.begin();
it != vecShapes.end(); ++it)
{
if ((*it)->Selected(lParam))
{
cur_handle = (*it)->GetHandle();
cur_handle->PostMouseMsg(hwnd, message, wParam, lParam);
}
}
}
代码:
如上代码所示,这样会在具体图形类中判断是否选中了该图形和给出handle。但感觉给Rect加上了多余的责任。 2。或者用模板特化:
template <class TShape>
MouseCapture * GetHandle(TShape * ps)
{
return NULL;
}

template <>
MouseCapture * GetHandle<Rect>(Rect * prect)
{
return new RectHandle(prect);
}
[code]
说了半天,其实就是想听听大家有什么解决类似问题的好办法
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #7 (permalink)  
旧 2005-05-25
Elminster 的头像
超级版主
 
注册日期: 2002-09-09
帖子: 1,764
Elminster 正向着好的方向发展
默认

引用:
作者: Bankrock
刚才说错了一点:在根据不同鼠标动作给出不同的鼠标信息处理对象时,需要某个特定的图形类知道与之相应的处理对象是什么。我现在是这么想的:
1。每个图形类里设立一个虚拟函数来生成不同的能处理该图形信息的类。
代码:
class Rect : public Shape //Shape是虚拟基类 { virtual MouseCapture * GetHandle() { return new RectHandle(this); }; virtual bool Selected(LPARAM lParam); ........ }
然后便可以由一个全局函数处理鼠标信息:
[code]
void SetMouseCapture(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
for (std::vector<Shape*>::iterator it = vecShapes.begin();
it != vecShapes.end(); ++it)
{
if ((*it)->Selected(lParam))
{
cur_handle = (*it)->GetHandle();
cur_handle->PostMouseMsg(hwnd, message, wParam, lParam);
}
}
}
代码:
如上代码所示,这样会在具体图形类中判断是否选中了该图形和给出handle。但感觉给Rect加上了多余的责任。 2。或者用模板特化:
template <class TShape>
MouseCapture * GetHandle(TShape * ps)
{
return NULL;
}

template <>
MouseCapture * GetHandle<Rect>(Rect * prect)
{
return new RectHandle(prect);
}
[code]
说了半天,其实就是想听听大家有什么解决类似问题的好办法
你的方案二看起来有点奇怪,不明白你是什么意思。判断究竟是那个图形相关的处理类来接管控制,还是要通过鼠标的位置来,你这几个函数有什么用?而且从你给出的例子来看,完全用不着函数模板,直接重载就行了。

方案一比较好些。如果你觉得这样给 Rect 增加了过多的职责,可以考虑把这部分显示、处理鼠标捕捉的功能剥离出来,另外构造一个类层次。UI 部分的代码只和新的类层次打交道,Rect 则仅仅包含纯粹的逻辑上和矩形有关的操作。

另外,关于分派(就是指定那个处理器处理鼠标消息),你现在的做法恐怕不是太好。其实你可以这样设计:全局的获得鼠标消息的函数直接把消息转发给一个“处理器”,最初的时候,就是整个“画布”的处理器。然后让每个图形对象声明一下自己的“关心区域”,当鼠标左键按下的时候,整个“画布”的处理器判断这个位置在哪个图形对象的“关心区域”内,然后直接把控制权交给它,也就是以后全局的获得鼠标消息的函数就把消息直接转发给它了。等到它处理完之后,再恢复成整个“画布”的处理器。

这样做的好处是分层处理,每一层都比较简单。比方说你点击在某个矩形内,你可以直接把处理消息的责任交给那个矩形的处理器,上面一层就不用管。然后那个矩形的处理器也可以再分派责任,比如在它自己内部再定义若干子处理器,各自定义关心区域,比如说四条边各定义一个,四个角各定义一个,内部定义一个。这样最后每个处理器都很简单,但是组合起来就能实现非常复杂的处理。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #8 (permalink)  
旧 2005-05-25
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认

多谢elm,现在的大体类构架是这样:
1。一个图形对象的类体系和一个与之相应的根据鼠标动作获取handle的类体系,ShapeMap负责交流处理鼠标Mapping信息,是个中间层:
代码:
//------------------------图形类体系----------------------------// class Shape { public: virtual ~Shape(){} virtual void DrawSelf(HDC hdc) const = 0; virtual void Move(POINT ptDirect) = 0; virtual void Rotate(POINT ptCenter, double dArg) = 0; private: //static std::list<Shape*> }; class SRect : public Shape { public: SRect(POINT _ptLT, POINT _ptRB) : ptLT(_ptLT), ptRB(_ptRB) {} virtual ~SRect() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetRect(POINT _ptLT, POINT _ptRB); void GetRect(POINT& _ptLT, POINT& _ptRB) const; private: POINT ptLT; //lefttop point POINT ptRB; //rightbottom point }; class SEllipse : public Shape { public: SEllipse(POINT _ptLT, POINT _ptRB) : ptLT(_ptLT), ptRB(_ptRB) {} virtual ~SEllipse() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetEllipse(POINT _ptLT, POINT _ptRB); void GetEllipse(POINT& _ptLT, POINT& _ptRB) const; private: POINT ptLT; //lefttop point POINT ptRB; //rightbottom point }; class SPolygon : public Shape { public: SPolygon(std::vector<POINT> const vecVtx) : vecVertex(vecVtx) {} virtual ~SPolygon() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetPolygon(std::vector<POINT> const& vecIn); void GetPolygon(std::vector<POINT>& vecOut) const; private: std::vector<POINT> vecVertex; }; //---------------handle类体系-------------------------// class ShapeMap { public: virtual ~ShapeMap() {} virtual MouseCapture * MappingHandle(int x, int y) = 0; //更据鼠标指到的不同位置获取不同的handle类 }; class SRectMap : public ShapeMap { public: SRectMap(SRect * pSR) : pSRect(pSR) {} virtual ~SRectMap() {} virtual MouseCapture * MappingHandle(int x, int y); private: SRect * pSRect; }; ......................
2。一个管理全部图形的类对象ShapeManager。(可以用singleton)
代码:
class ShapeManager { public: void Add(ShapeMap*); void Delete(ShapeMap *); ............ private: std::vector<ShapeMap*> vecShapeMaps; //用ShapeMap是为了根据鼠标信息确立不同的处理方式 MouseCapture * cur_handle; };
3。处理对应不同图形的各种方式的鼠标动作,比如矩形的拖动,多边形的旋转等
代码:
class MouseCapture { public: virtual bool PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam) = 0; virtual ~MouseCapture() {} }; class ShapeCapture : public MouseCapture { public: virtual bool PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam) = 0; virtual ~ShapeCapture() {} }; class SRectCapture : public ShapeCapture { public: SRctCapture(SRect * pSR) : pSRect(pSR) {} virtual ~SRectController() {} virtual bool PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam); private: enum SRectState {LTRESIZE, RTRESIZE, LBRESIZE, RBRESIZE, LRESIZE, RRESIZE, TRESIZE, BRESIZE, ROTATING, MOVING, FREE} cur_state; private: SRectState ConfirmState(int iX, int iY) const; };
初步计划是这样。

这里ShapMap的MappingHandle根据“关心区域”确定处理器。当鼠标信息来到时先看看cur_handle是否为NULL,是的话就在ShapeManager里对每个 ShapeMap对象调用GetHandle,找到了就将其放入cur_handle里,然后所有的鼠标信息都可以往cur_handle发。看起来还是很不错的
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #9 (permalink)  
旧 2005-05-25
wy 的头像
wy wy 当前离线
高级会员
 
注册日期: 2004-03-17
帖子: 518
wy 正向着好的方向发展
默认

Msdn的例子里MFC类Ole小类有一个DrawCli(好象是这个),和你设计的差不多,一个Shape类体系,一个tool类体系,tool类封装了各种鼠标操作,实际就是一个State模式,不过它使用了一个全局函数在不同的状态下切换到合适的tool,而设计模式那本书里是把状态的切换弄成tool的一个虚函数,以定制切换到后续的tool上
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #10 (permalink)  
旧 2005-05-25
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,563
文章: 6
cat 正向着好的方向发展
默认

等完善了贴上来吧,说不定有用 :P
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #11 (permalink)  
旧 2005-05-28
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认

yeah,大体结构完成了。就剩下具体的添加各种处理类和完善Shape类体系各成员的功能了。贴出来看看:
shapeclass.cpp
代码:
#include "shapeclass.h" //---------------- SRect Methods------------------------// void SRect::DrawSelf(HDC hdc) const { Rectangle(hdc, ptLT.x, ptLT.y, ptRB.x, ptRB.y); } void SRect::Move(POINT ptDirect) { ptLT.x += ptDirect.x; ptLT.y += ptDirect.y; ptRB.x += ptDirect.x; ptRB.y += ptDirect.y; } void SRect::Rotate(POINT ptCenter, double dArg) { } void SRect::SetRect(POINT _ptLT, POINT _ptRB) { ptLT.x = _ptLT.x; ptLT.y = _ptLT.y; ptRB.x = _ptRB.x; ptRB.y = _ptRB.y; } void SRect::GetRect(POINT& _ptLT, POINT& _ptRB) const { _ptLT.x = ptLT.x; _ptLT.y = ptLT.y; _ptRB.x = ptRB.x; _ptRB.y = ptRB.y; } //---------------------------SEllipse Method--------------------------------// void SEllipse::DrawSelf(HDC hdc) const { Ellipse(hdc, ptLT.x, ptLT.y, ptRB.x, ptRB.y); } void SEllipse::Move(POINT ptDirect) { ptLT.x += ptDirect.x; ptLT.y += ptDirect.y; ptRB.x += ptDirect.x; ptRB.y += ptDirect.y; } void SEllipse::Rotate(POINT ptCenter, double dArg) { } void SEllipse::SetEllipse(POINT _ptLT, POINT _ptRB) { ptLT.x = _ptLT.x; ptLT.y = _ptLT.y; ptRB.x = _ptRB.x; ptRB.y = _ptRB.y; } void SEllipse::GetEllipse(POINT& _ptLT, POINT& _ptRB) const { _ptLT.x = ptLT.x; _ptLT.y = ptLT.y; _ptRB.x = ptRB.x; _ptRB.y = ptRB.y; } //--------------------------SPolygon Method---------------------------// void SPolygon::DrawSelf(HDC hdc) const { POINT * pt = new POINT[vecVertex.size()]; for (int i = 0; i < vecVertex.size(); ++i) pt[i] = vecVertex[i]; Polygon(hdc, pt, vecVertex.size()); } void SPolygon::Move(POINT ptDirect) { for (int i = 0; i < vecVertex.size(); ++i) { vecVertex[i].x += ptDirect.x; vecVertex[i].y += ptDirect.y; } } void SPolygon::Rotate(POINT ptCenter, double dArg) { } void SPolygon::SetPolygon(std::vector<POINT> const& vecIn) { vecVertex = vecIn; } void SPolygon::GetPolygon(std::vector<POINT>& vecOut) const { vecOut = vecVertex; }
shapeclass.h
代码:
#include <windows.h> #include <vector> #ifndef __SHAPECLASS_H__ #define __SHAPECLASS_H__ class Shape { public: virtual ~Shape(){} virtual void DrawSelf(HDC hdc) const = 0; virtual void Move(POINT ptDirect) = 0; virtual void Rotate(POINT ptCenter, double dArg) = 0; private: //static std::list<Shape*> }; class SRect : public Shape { public: SRect(POINT _ptLT, POINT _ptRB) : ptLT(_ptLT), ptRB(_ptRB) {} virtual ~SRect() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetRect(POINT _ptLT, POINT _ptRB); void GetRect(POINT& _ptLT, POINT& _ptRB) const; private: POINT ptLT; //lefttop point POINT ptRB; //rightbottom point }; class SEllipse : public Shape { public: SEllipse(POINT _ptLT, POINT _ptRB) : ptLT(_ptLT), ptRB(_ptRB) {} virtual ~SEllipse() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetEllipse(POINT _ptLT, POINT _ptRB); void GetEllipse(POINT& _ptLT, POINT& _ptRB) const; private: POINT ptLT; //lefttop point POINT ptRB; //rightbottom point }; class SPolygon : public Shape { public: SPolygon(std::vector<POINT> const vecVtx) : vecVertex(vecVtx) {} virtual ~SPolygon() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetPolygon(std::vector<POINT> const& vecIn); void GetPolygon(std::vector<POINT>& vecOut) const; private: std::vector<POINT> vecVertex; }; #endif
shapemap.h
代码:
#include <windows.h> #include "shapeclass.h" #include "mousecapture.h" #include <algorithm> #ifndef __SHAPERMAP_H__ #define __SHAPERMAP_H__ class ShapeMap; //-----------------manage all the shapes--------------------// class ShapeManager { public: ShapeManager() : cur_handle(NULL) {} ~ShapeManager(); void MappingHandle(int x, int y); bool ExistHandle() { return cur_handle == NULL ? false : true; } void Add(ShapeMap *); void PostMouseMsg(HWND, UINT, WPARAM, LPARAM); void Draw(HDC) const; private: std::vector<ShapeMap*> vecShapes; ShapeCapture * cur_handle; }; //------------------manage message for creating------------------// class FactoryManager { public: FactoryManager() : cur_handle(NULL) {} ~FactoryManager(); void SetHandle(FactoryCapture * new_handle); bool ExistHandle() const { return cur_handle == NULL ? false : true; } void PostMouseMsg(HWND, UINT, WPARAM, LPARAM); void Draw(HDC hdc) const; private: FactoryCapture * cur_handle; }; class ShapeMap { public: virtual ~ShapeMap() {} virtual void Draw(HDC) const = 0; virtual ShapeCapture * MappingHandle(int x, int y) = 0; }; class SRectMap : public ShapeMap { public: SRectMap(SRect const& src) : rc(src) {} virtual ~SRectMap() {} virtual void Draw(HDC) const; virtual ShapeCapture * MappingHandle(int x, int y); private: SRect rc; }; class SElliMap : public ShapeMap { public: SElliMap(SEllipse const& selli) : el(selli) {} virtual ~SElliMap() {} virtual void Draw(HDC) const; virtual ShapeCapture * MappingHandle(int x, int y); private: SEllipse el; }; class SPolyMap : public ShapeMap { public: SPolyMap(SPolygon const& spoly) : pl(spoly) {} virtual ~SPolyMap() {} virtual void Draw(HDC) const; virtual ShapeCapture * MappingHandle(int x, int y); private: SPolygon pl; }; #endif
shapemap.cpp
代码:
#include "shapermap.h" #include <cmath> //----------------------SRectMap methods------------------------// ShapeCapture * SRectMap::MappingHandle(int x, int y) { POINT ptLT, ptRB; rc.GetRect(ptLT, ptRB); int xMin = std::min(ptLT.x, ptRB.x), xMax = std::max(ptLT.x, ptRB.x), yMin = std::min(ptLT.y, ptRB.y), yMax = std::max(ptLT.y, ptRB.y); if ((x > xMin && x < xMax) && (y > yMin && y < yMax)) return new MoveCapture(&rc); return NULL; } void SRectMap::Draw(HDC hdc) const { rc.DrawSelf(hdc); } //----------------------SElliMap methods-----------------------// ShapeCapture * SElliMap::MappingHandle(int x, int y) { POINT ptLT, ptRB; el.GetEllipse(ptLT, ptRB); int a = abs(ptLT.x - ptRB.x) / 2, b = abs(ptLT.y - ptRB.y) / 2, x0 = (ptLT.x + ptRB.x) / 2, y0 = (ptLT.y + ptRB.y) / 2; if (std::pow((double)(b * (x - x0)), 2) + std::pow((double)(a * (y - y0)), 2) < std::pow((double)(a * b), 2)) return new MoveCapture(&el); return NULL; } void SElliMap::Draw(HDC hdc) const { el.DrawSelf(hdc); } //--------------------------SPolyMap methods------------------------// ShapeCapture * SPolyMap::MappingHandle(int x, int y) { return NULL; } void SPolyMap::Draw(HDC hdc) const { pl.DrawSelf(hdc); } //----------------------ShapeManager methods-------------------------// ShapeManager::~ShapeManager() { delete cur_handle; for (std::vector<ShapeMap *>::iterator it = vecShapes.begin(); it != vecShapes.end(); ++it) delete (*it); } void ShapeManager::MappingHandle(int x, int y) //insert correct handle { if (ExistHandle()) return; ShapeCapture * pmc; for (std::vector<ShapeMap *>::reverse_iterator it = vecShapes.rbegin(); it != vecShapes.rend(); ++it) { if ((pmc = (*it)->MappingHandle(x, y)) != NULL) { cur_handle = pmc; break; } } } void ShapeManager::Add(ShapeMap * psm) { vecShapes.push_back(psm); } void ShapeManager::PostMouseMsg(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (cur_handle == NULL) //if a handle exists then return return; //delete the existing handle when the process is finished if (!cur_handle->PostMouseMsg(hwnd, message, wParam, lParam)) { delete cur_handle; cur_handle = NULL; } } void ShapeManager::Draw(HDC hdc) const { for (std::vector<ShapeMap*>::const_iterator it = vecShapes.begin(); it != vecShapes.end(); ++it) (*it)->Draw(hdc); } //-----------------------------FactoryManager methods-------------------------// FactoryManager::~FactoryManager() { delete cur_handle; } void FactoryManager::SetHandle(FactoryCapture * new_handle) { if (cur_handle != NULL) return; cur_handle = new_handle; } void FactoryManager::PostMouseMsg(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (cur_handle == NULL)//if a handle exists then return return; //delete the existing handle when the process is finished if (!cur_handle->PostMouseMsg(hwnd, message, wParam, lParam)) { delete cur_handle; cur_handle = NULL; } } void FactoryManager::Draw(HDC hdc) const { if (cur_handle == NULL) return; cur_handle->Draw(hdc); }
mousecapture.h
代码:
#include <windows.h> #include <vector> #include "shapeclass.h" #ifndef __MOUSECAPTURE_H__ #define __MOUSECAPTURE_H__ //----------------------------Mouse message handles------------------// class MouseCapture { public: virtual ~MouseCapture() {} virtual bool PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam) = 0; }; class ShapeCapture : public MouseCapture { public: virtual ~ShapeCapture() {} virtual bool PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam) = 0; }; class MoveCapture : public ShapeCapture //moving handle { public: MoveCapture(Shape * pS) : pShape(pS) , cur_state(END) {} virtual ~MoveCapture() {} virtual bool PostMouseMsg(HWND, UINT, WPARAM, LPARAM); private: enum MOVE_STATE { MOVING, END } cur_state; POINT ptStart; Shape * pShape; }; //------------------------Factory captures---------------------------// class FactoryCapture : public MouseCapture { public: virtual ~FactoryCapture() {} virtual bool PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam) = 0; virtual void Draw(HDC) const = 0; }; class SRectFacCapture : public FactoryCapture //gather info for creating SRect { public: SRectFacCapture() : cur_state(RB_INPUTED) {} virtual ~SRectFacCapture() {}; virtual bool PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam); virtual void Draw(HDC) const; private: enum CREATE_STATE { LT_INPUTED, RB_INPUTED } cur_state; POINT ptLT, ptRB; }; class SElliFacCapture : public FactoryCapture //gather info for creating SEllipse { public: SElliFacCapture() : cur_state(RB_INPUTED) {} virtual ~SElliFacCapture() {}; virtual bool PostMouseMsg(HWND, UINT, WPARAM, LPARAM); virtual void Draw(HDC) const; private: enum CREATE_STATE { LT_INPUTED, RB_INPUTED } cur_state; POINT ptLT, ptRB; }; class SPolyFacCapture : public FactoryCapture //gather info for creating SPolygon { public: SPolyFacCapture() : cur_state(INPUT_END) {} virtual ~SPolyFacCapture() {} virtual bool PostMouseMsg(HWND, UINT, WPARAM, LPARAM); virtual void Draw(HDC) const; private: enum CREATE_STATE { INPUT_POINT, INPUT_END } cur_state; std::vector<POINT> vecPt; }; #endif
mousecapture.cpp
代码:
#include "mousecapture.h" #include "shapermap.h" extern ShapeManager sm; //-------------------------SRectFacCapture methods---------------------------// void SRectFacCapture::Draw(HDC hdc) const { Rectangle(hdc, ptLT.x, ptLT.y, ptRB.x, ptRB.y); } bool SRectFacCapture::PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam) { switch (msgMouse) { case WM_LBUTTONDOWN: if (cur_state != RB_INPUTED) break; ptLT.x = (int)(LOWORD(lParam)); ptLT.y = (int)(HIWORD(lParam)); cur_state = LT_INPUTED; break; case WM_MOUSEMOVE: if (cur_state != LT_INPUTED) break; ptRB.x = (int)(LOWORD(lParam)); ptRB.y = (int)(HIWORD(lParam)); InvalidateRect(hwnd, NULL, TRUE); break; case WM_LBUTTONUP: if (cur_state != LT_INPUTED) break; ptRB.x = (int)(LOWORD(lParam)); ptRB.y = (int)(HIWORD(lParam)); sm.Add(new SRectMap(SRect(ptLT, ptRB))); cur_state = RB_INPUTED; return false; case WM_RBUTTONUP: cur_state = RB_INPUTED; return false; } return true; } //------------------------------SElliFacCapture methods--------------------------// void SElliFacCapture::Draw(HDC hdc) const { Ellipse(hdc, ptLT.x, ptLT.y, ptRB.x, ptRB.y); } bool SElliFacCapture::PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam) { switch (msgMouse) { case WM_LBUTTONDOWN: if (cur_state != RB_INPUTED) break; ptLT.x = (int)(LOWORD(lParam)); ptLT.y = (int)(HIWORD(lParam)); cur_state = LT_INPUTED; break; case WM_MOUSEMOVE: if (cur_state != LT_INPUTED) break; ptRB.x = (int)(LOWORD(lParam)); ptRB.y = (int)(HIWORD(lParam)); InvalidateRect(hwnd, NULL, TRUE); break; case WM_LBUTTONUP: if (cur_state != LT_INPUTED) break; ptRB.x = (int)(LOWORD(lParam)); ptRB.y = (int)(HIWORD(lParam)); sm.Add(new SElliMap(SEllipse(ptLT, ptRB))); cur_state = RB_INPUTED; return false; case WM_RBUTTONUP: cur_state = RB_INPUTED; return false; } return true; } //-----------------------------SPolyFacCapture methods------------------------// void SPolyFacCapture::Draw(HDC hdc) const { POINT * ppt = new POINT[vecPt.size()]; for (int i = 0; i < vecPt.size(); ++i) ppt[i] = vecPt[i]; Polyline(hdc, ppt, vecPt.size()); delete [] ppt; } bool SPolyFacCapture::PostMouseMsg(HWND hwnd, UINT msgMouse, WPARAM wParam, LPARAM lParam) { POINT ptMouse; POINT * ppt; switch (msgMouse) { case WM_LBUTTONUP: ptMouse.x = (int)(LOWORD(lParam)); ptMouse.y = (int)(HIWORD(lParam)); vecPt.push_back(ptMouse); InvalidateRect(hwnd, NULL, TRUE); return true; case WM_RBUTTONUP: sm.Add(new SPolyMap(SPolygon(vecPt))); vecPt.clear(); InvalidateRect(hwnd, NULL, TRUE); return false; } return true; } //---------------------------MoveCapture methods--------------------------// bool MoveCapture::PostMouseMsg(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int x, y; x = (int)(LOWORD(lParam)); y = (int)(HIWORD(lParam)); POINT ptOffset; switch (message) { case WM_LBUTTONDOWN: cur_state = MOVING; ptStart.x = x; ptStart.y = y; break; case WM_MOUSEMOVE: if (cur_state != MOVING) break; ptOffset.x = x - ptStart.x; ptOffset.y = y - ptStart.y; pShape->Move(ptOffset); InvalidateRect(hwnd, NULL, TRUE); ptStart.x = x; ptStart.y = y; break; case WM_LBUTTONUP: cur_state = END; ptOffset.x = x - ptStart.x; ptOffset.y = y - ptStart.y; pShape->Move(ptOffset); InvalidateRect(hwnd, NULL, TRUE); return false; } return true; }
shapemain.cpp
代码:
#include <windows.h> #include "mousecapture.h" #include "shapermap.h" ShapeManager sm; FactoryManager fm; /* Declare Windows procedure */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); /* Make the class name into a global variable */ char szClassName[ ] = "WindowsApp"; int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { HWND hwnd; /* This is the handle for our window */ MSG messages; /* Here messages to the application are saved */ WNDCLASSEX wincl; /* Data structure for the windowclass */ /* The Window structure */ wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ wincl.style = CS_DBLCLKS; /* Catch double-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = NULL; /* No menu */ wincl.cbClsExtra = 0; /* No extra bytes after the window class */ wincl.cbWndExtra = 0; /* structure or the window instance */ /* Use Windows's default color as the background of the window */ wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; /* Register the window class, and if it fails quit the program */ if (!RegisterClassEx (&wincl)) return 0; /* The class is registered, let's create the program*/ hwnd = CreateWindowEx ( 0, /* Extended possibilites for variation */ szClassName, /* Classname */ "Windows App", /* Title Text */ WS_OVERLAPPEDWINDOW, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ 544, /* The programs width */ 375, /* and height in pixels */ HWND_DESKTOP, /* The window is a child-window to desktop */ NULL, /* No menu */ hThisInstance, /* Program Instance handler */ NULL /* No Window Creation data */ ); /* Make the window visible on the screen */ ShowWindow (hwnd, nFunsterStil); /* Run the message loop. It will run until GetMessage() returns 0 */ while (GetMessage (&messages, NULL, 0, 0)) { /* Translate virtual-key messages into character messages */ TranslateMessage(&messages); /* Send message to WindowProcedure */ DispatchMessage(&messages); } /* The program return-value is 0 - The value that PostQuitMessage() gave */ return messages.wParam; } #define ID_CRT_RECT 100 #define ID_CRT_ELLI 101 #define ID_CRT_POLY 102 /* This function is called by the Windows function DispatchMessage() */ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hCrtRect, hCrtElli, hCrtPoly; static int cxChar, cyChar; static HINSTANCE hInstance; static RECT rcPaint; PAINTSTRUCT ps; HDC hdc; switch (message) /* handle the messages */ { case WM_CREATE: cxChar = LOWORD(GetDialogBaseUnits()); cyChar = HIWORD(GetDialogBaseUnits()); hInstance = ((LPCREATESTRUCT)lParam)->hInstance; hCrtRect = CreateWindow(TEXT("button"), TEXT("Rectangle"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 15, 20, 12 * cxChar, 7 * cyChar / 4, hwnd, (HMENU)ID_CRT_RECT, hInstance, NULL); hCrtElli = CreateWindow(TEXT("button"), TEXT("Ellipse"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 15, 70, 12 * cxChar, 7 * cyChar / 4, hwnd, (HMENU)ID_CRT_ELLI, hInstance, NULL); hCrtPoly = CreateWindow(TEXT("button"), TEXT("Polygon"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 15, 120, 12 * cxChar, 7 * cyChar / 4, hwnd, (HMENU)ID_CRT_POLY, hInstance, NULL); rcPaint.left = 40 + 12 * cxChar; rcPaint.top = 0; return 0; case WM_SIZE: rcPaint.right = LOWORD(lParam); rcPaint.bottom = HIWORD(lParam); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case ID_CRT_RECT: fm.SetHandle(new SRectFacCapture); break; case ID_CRT_ELLI: fm.SetHandle(new SElliFacCapture); break; case ID_CRT_POLY: fm.SetHandle(new SPolyFacCapture); break; } return 0; case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MOUSEMOVE: if (fm.ExistHandle()) fm.PostMouseMsg(hwnd, message, wParam, lParam); else { if (message == WM_LBUTTONDOWN) sm.MappingHandle((int)(LOWORD(lParam)), (int)(HIWORD(lParam))); if (sm.ExistHandle()) sm.PostMouseMsg(hwnd, message, wParam, lParam); } return 0; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); sm.Draw(hdc); fm.Draw(hdc); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; } /* for messages that we don't deal with */ return DefWindowProc (hwnd, message, wParam, lParam); }
DEVC++下通过编译。提供了鼠标创建图形,移动图形的基本功能,其他有待完善。现在碰到一个算法上的问题,就是怎么判断一个点是在任意的多边形内部呢?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #12 (permalink)  
旧 2005-06-01
Elminster 的头像
超级版主
 
注册日期: 2002-09-09
帖子: 1,764
Elminster 正向着好的方向发展
默认

引用:
作者: Bankrock
现在碰到一个算法上的问题,就是怎么判断一个点是在任意的多边形内部呢?
不要给自己找这个麻烦,为这个任意多边形加个外接的矩形框或是在中心放个“把手”,那样要方便的多。任意多边形(非凸的)在计算几何里面处理起来比较麻烦,你这个问题我刚才想了一下,只想到一个 O(n) 的算法。回头有功夫我查查,看看这个问题最好结果是什么。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #13 (permalink)  
旧 2005-06-01
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,563
文章: 6
cat 正向着好的方向发展
默认

还有一种简单的方法(不去考虑O级别了 :P )
对于需要填充的polygon, rasterize的时候不绘制颜色,而是绘制一些特别的object identifier到buffer里面,然后读这个buffer里mouse cursor所在的pixel就可以知道在哪里了。这在OpenGL里面很容易做到,而且rasterize还可能有硬件加速,那就很快了(不过奇怪的polygon可能没什么加速,不过它的实现总是比较高效的吧)。不知道windows的api有没有这样的函数。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #14 (permalink)  
旧 2005-06-01
cat cat 当前离线
高级会员
 
注册日期: 2003-11-06
帖子: 1,563
文章: 6
cat 正向着好的方向发展
默认

windows应该也可以,画到一个memoryDC里面,然后把它的bitmap掉出来看就是了。在需要选择物体的时候 && 场景已经变化的时候 refresh这个DC里的内容。
绘制的时候用object index填充最后的color参数。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #15 (permalink)  
旧 2005-06-11
bankrock 的头像
高级会员
 
注册日期: 2003-12-11
帖子: 847
文章: 7
bankrock 正向着好的方向发展
默认

差不多完善了,放出最新版本
整个程序由四大块组成:
1。处理逻辑工作的底层Shape类。除了画图外完全和图形处理无关,提供移动,缩放等功能。(ShapeClass.h, ShapeClass.cpp)
2。在Shape类基础上建立起来的响应图形界面操作的ShapeMap类。能根据不同的鼠标动作加载上不同的处理鼠标操作的MouseCapture类(由MappingHandle函数完成),并包含了Shape类的各种动作。(ShapeMap.h, ShapeMap.cpp)
3。处理鼠标操作的MouseCapture类。接受鼠标消息,根据不同的消息对其操作作的图形做出不同的改变,并随时更新屏幕显示。 (MouseCapture.h,MouseCapture.cpp)
4。管理全部已生成图形类的ShapeManager和负责生成图形的FactoryManager类。所有鼠标消息都从他们传送到各个具体图形。(这两个类用Singleton Pattern,只有一个实例,在ShapeMap.h,ShapeMap.cpp下定义)

下面是完整代码,用得着的人不妨看一下。在Window XP SP1 + devc++下通过编译测试:
[ShapeClass.h]
代码:
#ifndef __SHAPECLASS_H__ #define __SHAPECLASS_H__ #include <windows.h> #include <vector> class Shape { public: virtual ~Shape(){} virtual void DrawSelf(HDC hdc) const = 0; virtual void Move(POINT ptDirect) = 0; virtual void Rotate(POINT ptCenter, double dArg) = 0; }; class SRect : public Shape { public: SRect(RECT rc) : rect(rc) {} virtual ~SRect() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetRect(RECT rc) { rect = rc; } RECT GetRect() const { return rect; } private: RECT rect; }; class SEllipse : public Shape { public: SEllipse(RECT el) : elli(el) {} virtual ~SEllipse() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetEllipse(RECT el) { elli = el; } RECT GetEllipse() const { return elli; } private: RECT elli; }; class SPolygon : public Shape { public: SPolygon(std::vector<POINT> const vecVtx) : vecVertex(vecVtx) {} virtual ~SPolygon() {} virtual void DrawSelf(HDC hdc) const; virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetPolygon(std::vector<POINT> const& vecIn); void GetPolygon(std::vector<POINT>& vecOut) const; void SetByID(int i, POINT pt); int GetVertexNum() const { return vecVertex.size(); } POINT GetByID(int i) const; private: std::vector<POINT> vecVertex; }; #endif
[ShapeClass.cpp]
代码:
#include "shapeclass.h" #include <stdexcept> #include <iostream> #include <cmath> //---------------Rotate a point--------------// inline POINT RotatePoint(POINT ptIn, POINT ptCenter, double arg) { POINT ptOut; int dx = ptIn.x - ptCenter.x, dy = ptIn.y - ptCenter.y; ptOut.x = dx * cos((float)arg) - dy * sin((float)arg) + ptCenter.x; ptOut.y = dy * cos((float)arg) + dx * sin((float)arg) + ptCenter.y; return ptOut; } //---------------- SRect Methods------------------------// void SRect::DrawSelf(HDC hdc) const { Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom); } void SRect::Move(POINT ptDirect) { rect.left += ptDirect.x; rect.top += ptDirect.y; rect.right += ptDirect.x; rect.bottom += ptDirect.y; } void SRect::Rotate(POINT ptCenter, double dArg) { } //---------------------------SEllipse Method--------------------------------// void SEllipse::DrawSelf(HDC hdc) const { Ellipse(hdc, elli.left, elli.top, elli.right, elli.bottom); } void SEllipse::Move(POINT ptDirect) { elli.left += ptDirect.x; elli.top += ptDirect.y; elli.right += ptDirect.x; elli.bottom += ptDirect.y; } void SEllipse::Rotate(POINT ptCenter, double dArg) { } //--------------------------SPolygon Method---------------------------// void SPolygon::DrawSelf(HDC hdc) const { POINT * pt = new POINT[vecVertex.size()]; for (int i = 0; i < vecVertex.size(); ++i) pt[i] = vecVertex[i]; Polygon(hdc, pt, vecVertex.size()); delete [] pt; } void SPolygon::Move(POINT ptDirect) { for (int i = 0; i < vecVertex.size(); ++i) { vecVertex[i].x += ptDirect.x; vecVertex[i].y += ptDirect.y; } } void SPolygon::Rotate(POINT ptCenter, double dArg) { typedef std::vector<POINT>::iterator PT_ITERATOR; for (PT_ITERATOR it = vecVertex.begin(); it != vecVertex.end(); ++it) *it = RotatePoint(*it, ptCenter, dArg); } void SPolygon::SetPolygon(std::vector<POINT> const& vecIn) { vecVertex = vecIn; } void SPolygon::GetPolygon(std::vector<POINT>& vecOut) const { vecOut = vecVertex; } void SPolygon::SetByID(int i, POINT pt) try { if (i < 0 || i > vecVertex.size()) throw std::out_of_range("No such point exists"); vecVertex[i] = pt; } catch (std::exception& e) { std::cout << e.what() << std::endl; system("pause"); } POINT SPolygon::GetByID(int i) const try { if (i < 0 || i > vecVertex.size()) throw std::out_of_range("No such point exists"); return vecVertex[i]; } catch (std::exception& e) { std::cout << e.what() << std::endl; system("pause"); }
[ShapeMap.h]
代码:
#ifndef __SHAPERMAP_H__ #define __SHAPERMAP_H__ //#include <windows.h> #include "shapeclass.h" #include <algorithm> class ShapeCapture; class FactoryCapture; class ShapeMap; //-----------------manage all the shapes--------------------// class ShapeManager { public: ~ShapeManager(); static ShapeManager * Instance(); void MappingHandle(POINT pt); bool ExistHandle() { return cur_handle == NULL ? false : true; } void Add(ShapeMap *); void PostMouseMsg(HWND, UINT, POINT); void Draw(HDC) const; private: ShapeManager() : cur_handle(NULL) {} static ShapeManager * instance; std::vector<ShapeMap*> vecShapes; ShapeCapture * cur_handle; }; //------------------manage message for creating------------------// class FactoryManager { public: ~FactoryManager(); static FactoryManager * Instance(); void SetHandle(FactoryCapture * new_handle); bool ExistHandle() const { return cur_handle == NULL ? false : true; } void PostMouseMsg(HWND, UINT, POINT); void Draw(HDC hdc) const; private: FactoryManager() : cur_handle(NULL) {} static FactoryManager * instance; FactoryCapture * cur_handle; }; //--------------------------Graphic Shape class-----------------// class ShapeMap { public: virtual ~ShapeMap() {} virtual void Draw(HDC) const = 0; virtual ShapeCapture * MappingHandle(POINT pt) = 0; virtual void Move(POINT ptDirect) = 0; virtual void Rotate(POINT ptCenter, double dArg) = 0; }; class SRectMap : public ShapeMap { public: SRectMap(SRect const& src) : rc(src) {} virtual ~SRectMap() {} virtual void Draw(HDC) const; virtual ShapeCapture * MappingHandle(POINT pt); virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetRect(RECT new_rc); RECT GetRect() const; private: SRect rc; }; class SElliMap : public ShapeMap { public: SElliMap(SEllipse const& selli) : el(selli) {} virtual ~SElliMap() {} virtual void Draw(HDC) const; virtual ShapeCapture * MappingHandle(POINT pt); virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetEllipse(RECT new_el); RECT GetEllipse() const; private: SEllipse el; }; class SPolyMap : public ShapeMap { public: SPolyMap(SPolygon const& spoly) : pl(spoly) { POINT pt = pl.GetByID(0); rcKnob.left = pt.x + 5; rcKnob.top = pt.y + 5; rcKnob.right = rcKnob.left + 9; rcKnob.bottom = rcKnob.top + 9; SetAxis(); } virtual ~SPolyMap() {} virtual void Draw(HDC) const; virtual ShapeCapture * MappingHandle(POINT pt); virtual void Move(POINT ptDirect); virtual void Rotate(POINT ptCenter, double dArg); void SetPolygon(std::vector<POINT> const& vecIn); void GetPolygon(std::vector<POINT>& vecOut) const; void SetByID(int i, POINT pt); POINT GetByID(int i) const; private: void SetAxis(); private: RECT rcKnob, rcAxis; SPolygon pl; }; #endif
[ShapeMap.cpp]
代码:
#include "shapermap.h" #include "mousecapture.h" #include <cmath> const double PI = 3.1415926; //----------------------SRectMap methods------------------------// ShapeCapture * SRectMap::MappingHandle(POINT pt) { RECT rect = rc.GetRect(); if (abs(pt.x - rect.left) < 4) { if (abs(pt.y - rect.top) < 4) return new RectResizeCapture(this, RectResizeCapture::LT); else if (abs(pt.y - rect.bottom) < 4) return new RectResizeCapture(this, RectResizeCapture::LB); else if ((pt.y - rect.top) * (pt.y - rect.bottom) < 0) return new RectResizeCapture(this, RectResizeCapture::L); } else if (abs(pt.x - rect.right) < 4) { if (abs(pt.y - rect.top) < 4) return new RectResizeCapture(this, RectResizeCapture::RT); else if (abs(pt.y - rect.bottom) < 4) return new RectResizeCapture(this, RectResizeCapture::RB); else if ((pt.y - rect.top) * (pt.y - rect.bottom) < 0) return new RectResizeCapture(this, RectResizeCapture::R); } if (abs(pt.y - rect.top) < 4 && (pt.x - rect.left) * (pt.x - rect.right) < 0) return new RectResizeCapture(this, RectResizeCapture::T); if (abs(pt.y - rect.bottom) < 4 && (pt.x - rect.left) * (pt.x - rect.right) < 0) return new RectResizeCapture(this, RectResizeCapture::B); if ( (pt.x - rect.left) * (pt.x - rect.right) < 0 && (pt.y - rect.top) * (pt.y - rect.bottom) < 0 ) return new MoveCapture(this); return NULL; } void SRectMap::Draw(HDC hdc) const { rc.DrawSelf(hdc); } void SRectMap::Move(POINT ptDirect) { rc.Move(ptDirect); } void SRectMap::Rotate(POINT ptCenter, double dArg) { rc.Rotate(ptCenter, dArg); } RECT SRectMap::GetRect() const { return rc.GetRect(); } void SRectMap::SetRect(RECT new_rc) { rc.SetRect(new_rc); } //----------------------SElliMap methods-----------------------// ShapeCapture * SElliMap::MappingHandle(POINT pt) { RECT elli; elli = el.GetEllipse(); int a = abs(elli.left - elli.right) / 2, b = abs(elli.bottom - elli.top) / 2, a1 = a - 3, b1 = b - 3, a2 = a + 3, b2 = b + 3, x0 = (elli.left + elli.right) / 2, y0 = (elli.bottom + elli.top) / 2, dx = pt.x - x0, dy = pt.y - y0; if (std::pow((double)(b1 * dx), 2) + std::pow((double)(a1 * dy), 2) > std::pow((double)(a1 * b1), 2) && std::pow((double)(b2 * dx), 2) + std::pow((double)(a2 * dy), 2) < std::pow((double)(a2 * b2), 2)) { double arg = std::atan2((double)dy, (double)dx) * 180 / PI; if (arg > -10 && arg < 10) return new ElliResizeCapture(this, ElliResizeCapture::R); else if (arg > 10 && arg < 80) return new ElliResizeCapture(this, ElliResizeCapture::RT); else if (arg > 80 && arg < 100) return new ElliResizeCapture(this, ElliResizeCapture::T); else if (arg > 100 && arg < 170) return new ElliResizeCapture(this, ElliResizeCapture::LT); else if (arg > 170 || arg < -170) return new ElliResizeCapture(this, ElliResizeCapture::L); else if (arg > -170 && arg < -100) return new ElliResizeCapture(this, ElliResizeCapture::LB); else if (arg > -100 && arg < -10) return new ElliResizeCapture(this, ElliResizeCapture::RB); } if (std::pow((double)(b * (pt.x - x0)), 2) + std::pow((double)(a * (pt.y - y0)), 2) < std::pow((double)(a * b), 2)) return new MoveCapture(this); return NULL; } void SElliMap::Draw(HDC hdc) const { el.DrawSelf(hdc); } void SElliMap::Move(POINT ptDirect) { el.Move(ptDirect); } void SElliMap::Rotate(POINT ptCenter, double dArg) { el.Rotate(ptCenter, dArg); } void SElliMap::SetEllipse(RECT new_el) { el.SetEllipse(new_el); } RECT SElliMap::GetEllipse() const { return el.GetEllipse(); } //--------------------------SPolyMap methods------------------------// ShapeCapture * SPolyMap::MappingHandle(POINT pt) { if ( (pt.x < rcAxis.right && pt.x > rcAxis.left) && (pt.y < rcAxis.bottom && pt.y > rcAxis.top) ) { POINT ptC = pl.GetByID(0); return new RotateCapture(this, ptC); } std::vector<POINT> vecVtx; pl.GetPolygon(vecVtx); for (int i = 0; i < vecVtx.size(); ++i) if (abs(pt.x - vecVtx[i].x) < 5 && abs(pt.y - vecVtx[i].y) < 5) return new PolyAlterCapture(this, i); if ( (pt.x > rcKnob.left && pt.x < rcKnob.right) && (pt.y > rcKnob.top && pt.y < rcKnob.bottom) ) return new MoveCapture(this); return NULL; } void SPolyMap::Draw(HDC hdc) const { pl.DrawSelf(hdc); HBRUSH hBrush = (HBRUSH)SelectObject(hdc, CreateSolidBrush(RGB(0, 255, 0))); Rectangle(hdc, rcKnob.left, rcKnob.top, rcKnob.right, rcKnob.bottom); DeleteObject(SelectObject(hdc, hBrush)); hBrush = (HBRUSH)SelectObject(hdc, CreateSolidBrush(RGB(255, 255, 0))); Ellipse(hdc, rcAxis.left, rcAxis.top, rcAxis.right, rcAxis.bottom); DeleteObject(SelectObject(hdc, hBrush)); } void SPolyMap::Move(POINT ptDirect) { rcKnob.left += ptDirect.x; rcKnob.right += ptDirect.x; rcKnob.top += ptDirect.y; rcKnob.bottom += ptDirect.y; pl.Move(ptDirect); SetAxis(); } void SPolyMap::Rotate(POINT ptCenter, double dArg) { pl.Rotate(ptCenter, dArg); SetAxis(); POINT pt = pl.GetByID(0); rcKnob.left = pt.x + 5; rcKnob.top = pt.y + 5; rcKnob.right = rcKnob.left + 9; rcKnob.bottom = rcKnob.top + 9; } void SPolyMap::SetPolygon(std::vector<POINT> const& vecIn) { rcKnob.left = vecIn[0].x + 5; rcKnob.top = vecIn[0].y + 5; rcKnob.right = rcKnob.left + 9; rcKnob.bottom = rcKnob.top + 9; pl.SetPolygon(vecIn); SetAxis(); } void SPolyMap::GetPolygon(std::vector<POINT>& vecOut) const { pl.GetPolygon(vecOut); } void SPolyMap::SetByID(int i, POINT pt) { if (i == 0) { rcKnob.left = pt.x + 5; rcKnob.top = pt.y + 5; rcKnob.right = rcKnob.left + 9; rcKnob.bottom = rcKnob.top + 9; } pl.SetByID(i, pt); SetAxis(); } POINT SPolyMap::GetByID(int i) const { return pl.GetByID(i); } inline void SPolyMap::SetAxis() { POINT pt = pl.GetByID(pl.GetVertexNum() - 1); rcAxis.left = pt.x + 5; rcAxis.top = pt.y + 5; rcAxis.right = rcAxis.left + 10; rcAxis.bottom = rcAxis.top + 10; } //----------------------ShapeManager methods-------------------------// ShapeManager::~ShapeManager() { delete cur_handle; for (std::vector<ShapeMap *>::iterator it = vecShapes.begin(); it != vecShapes.end(); ++it) delete (*it); } void ShapeManager::MappingHandle(POINT pt) //insert correct handle { if (ExistHandle()) return; ShapeCapture * pmc; for (std::vector<ShapeMap *>::reverse_iterator it = vecShapes.rbegin(); it != vecShapes.rend(); ++it) { if ((pmc = (*it)->MappingHandle(pt)) != NULL) { cur_handle = pmc; break; } } } void ShapeManager::Add(ShapeMap * psm) { vecShapes.push_back(psm); } void ShapeManager::PostMouseMsg(HWND hwnd, UINT message, POINT pt) { if (cur_handle == NULL) //if a handle exists then return return; //delete the existing handle when the process is finished if (!cur_handle->TreatMouseMsg(hwnd, message, pt)) { delete cur_handle; cur_handle = NULL; } } void ShapeManager::Draw(HDC hdc) const { for (std::vector<ShapeMap*>::const_iterator it = vecShapes.begin(); it != vecShapes.end(); ++it) (*it)->Draw(hdc); } ShapeManager * ShapeManager::instance = 0; ShapeManager * ShapeManager::Instance() { if (instance == 0) instance = new ShapeManager; return instance; } //-----------------------------FactoryManager methods-------------------------// FactoryManager::~FactoryManager() { delete cur_handle; } void FactoryManager::SetHandle(FactoryCapture * new_handle) { if (cur_handle != NULL) return; cur_handle = new_handle; } void FactoryManager::PostMouseMsg(HWND hwnd, UINT message, POINT pt) { if (cur_handle == NULL)//if a handle exists then return return; //delete the existing handle when the process is finished if (!cur_handle->TreatMouseMsg(hwnd, message, pt)) { delete cur_handle; cur_handle = NULL; } } void FactoryManager::Draw(HDC hdc) const { if (cur_handle == NULL) return; cur_handle->Draw(hdc); } FactoryManager * FactoryManager::instance = 0; FactoryManager * FactoryManager::Instance() { if (instance == 0) instance = new FactoryManager; return instance; }
[MouseCapture.h]
代码:
#ifndef __MOUSECAPTURE_H__ #define __MOUSECAPTURE_H__ #include "shapermap.h" #include <windows.h> #include <vector> //----------------------------Mouse message handles------------------// //-------------------abstract class--------------------// class MouseCapture { public: virtual ~MouseCapture() {} virtual bool TreatMouseMsg(HWND hwnd, UINT msgMouse, POINT pt) = 0; }; //--------------------ShapeCapture-----------------------// class ShapeCapture : public MouseCapture { public: virtual ~ShapeCapture() {} virtual bool TreatMouseMsg(HWND hwnd, UINT msgMouse, POINT pt) = 0; }; class MoveCapture : public ShapeCapture //moving handle { public: MoveCapture(ShapeMap * p) : pSM(p) , cur_state(END) {} virtual ~MoveCapture() {} virtual bool TreatMouseMsg(HWND, UINT, POINT); private: enum MOVE_STATE { MOVING, END } cur_state; POINT ptStart; ShapeMap * pSM; }; class RotateCapture : public ShapeCapture //rotating handle { public: RotateCapture(ShapeMap * p, POINT ptCenter) : pSM(p), ptCenter(ptCenter), cur_state(END) {} virtual ~RotateCapture() {} virtual bool TreatMouseMsg(HWND, UINT , POINT); private: enum ROTATE_STATE { ROTATING, END } cur_state; POINT const ptCenter; double last_arg; ShapeMap * pSM; }; class RectResizeCapture : public ShapeCapture // resize handle { public: enum RESIZE_TYPE { LT, RB, LB, RT, L, R, T, B } const rt; RectResizeCapture(SRectMap * p, RESIZE_TYPE r) : pRCM(p) , rt(r), cur_state(END) {} virtual ~RectResizeCapture() {} virtual bool TreatMouseMsg(HWND, UINT, POINT); private: enum RESIZE_STATE { RESIZING, END } cur_state; POINT ptStart; SRectMap * pRCM; }; class ElliResizeCapture : public ShapeCapture // resizing ellipse { public: enum RESIZE_TYPE { LT, RB, LB, RT, L, R, T, B } const rt; ElliResizeCapture(SElliMap * p, RESIZE_TYPE r) : pELM(p) , rt(r), cur_state(END) {} virtual ~ElliResizeCapture() {} virtual bool TreatMouseMsg(HWND, UINT, POINT); private: enum RESIZE_STATE { RESIZING, END } cur_state; POINT ptStart; SElliMap * pELM; }; class PolyAlterCapture : public ShapeCapture // change poly vertexes { public: PolyAlterCapture(SPolyMap * p, int iVtx) : pPM(p), index(iVtx), cur_state(END) {} virtual ~PolyAlterCapture() {} virtual bool TreatMouseMsg(HWND, UINT, POINT); private: enum ALTER_STATE { ALTERING, END } cur_state; int const index; POINT ptStart; SPolyMap * pPM; }; //------------------------Factory captures---------------------------// class FactoryCapture : public MouseCapture { public: virtual ~FactoryCapture() {} virtual bool TreatMouseMsg(HWND hwnd, UINT msgMouse, POINT pt) = 0; virtual void Draw(HDC) const = 0; }; class SRectFacCapture : public FactoryCapture //gather info for creating SRect { public: SRectFacCapture() : cur_state(RB_INPUTED) {} virtual ~SRectFacCapture() {}; virtual bool TreatMouseMsg(HWND hwnd, UINT msgMouse, POINT pt); virtual void Draw(HDC) const; private: enum CREATE_STATE { LT_INPUTED, RB_INPUTED } cur_state; RECT rect; }; class SElliFacCapture : public FactoryCapture //gather info for creating SEllipse { public: SElliFacCapture() : cur_state(RB_INPUTED) {} virtual ~SElliFacCapture() {}; virtual bool TreatMouseMsg(HWND, UINT, POINT); virtual void Draw(HDC) const; private: enum CREATE_STATE { LT_INPUTED, RB_INPUTED } cur_state; RECT elli; }; class SPolyFacCapture : public FactoryCapture //gather info for creating SPolygon { public: SPolyFacCapture() : cur_state(INPUT_END) {} virtual ~SPolyFacCapture() {} virtual bool TreatMouseMsg(HWND, UINT, POINT); virtual void Draw(HDC) const; private: enum CREATE_STATE { INPUT_POINT, INPUT_END } cur_state; std::vector<POINT> vecPt; }; #endif
[MouseCapture.cpp]
代码:
#include "mousecapture.h" #include <cmath> double const PI = 3.1415926; class ShapeManager; extern RECT rcPaint; //-------------------------SRectFacCapture methods---------------------------// void SRectFacCapture::Draw(HDC hdc) const { Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom); } bool SRectFacCapture::TreatMouseMsg(HWND hwnd, UINT msgMouse, POINT pt) { switch (msgMouse) { case WM_LBUTTONDOWN: if (cur_state != RB_INPUTED) break; SetCapture(hwnd); rect.left = pt.x; rect.top = pt.y; cur_state = LT_INPUTED; break; case WM_MOUSEMOVE: case WM_LBUTTONUP: if (cur_state != LT_INPUTED) break; rect.right = pt.x; rect.bottom = pt.y; InvalidateRect(hwnd, &rcPaint, TRUE); if (msgMouse == WM_LBUTTONUP) { ShapeManager::Instance()->Add(new SRectMap(SRect(rect))); cur_state = RB_INPUTED; ReleaseCapture(); return false; } break; case WM_RBUTTONUP: cur_state = RB_INPUTED; return false; } return true; } //------------------------------SElliFacCapture methods--------------------------// void SElliFacCapture::Draw(HDC hdc) const { Ellipse(hdc, elli.left, elli.top, elli.r