tag:C++、接口编程、设计方法 、工具条
/* Create by zyzx
* Created 2008-05-18
* Modified 2008-05-25
*/
呵呵,原本想取题为Tools模式的,但想想只是一个惯用法还谈不上一种设计模式。。
好了,言归正传,做用户界面的时候通常会碰到这个问题:比如,我们为界面做了一系列的工具栏按钮,当用户点选按钮后会设置程序进入某个状态,在这种状态下,软件做出相应反馈。 如果只做一个或几个工具,按过程式的方法,还勉强可以接受,但不利于扩展。如果做成软件,一般可不只几个工具供用户选择了哦。。。
Tools模式,有前人发表过的思想,但偶楞是没找着,还是楞楞看开源代码才明白啥回事的。。。
举个简单的例子:就拿我们常用的Windows自带的画图工具来说,选中左边的工具栏框选项,在绘图区域按下左键拖动鼠标,是在屏幕上绘制虚线框,执行选框操作;选中直线,在绘图区域按下左键拖动鼠标,是绘制直线,执行绘直线操作;选中橡皮,在绘图区域按下左键拖动鼠标,执行擦除操作………
这里由于跟窗口(GDI对象)有关,从简来说:无非是左键按下啊,拖动啊,再到释放左键执行操作,或是右键的啥啊啥的。。他们的共通之处:(由于与DC相关,参数可酌情考虑)
Class CUIToolsBase : public XXX(?)
{
public:
virtual void OnMouseDown( UINT nFlags, CPoint point ) = 0; //鼠标点下,参数按MFC格式
virtual void OnMouseUp( UINT nFlags, CPoint point ) = 0; //鼠标弹起
virtual void OnMouseMove( UINT nFlags, CPoint point ) = 0; //鼠标移动
virtual void OnMouseDraging( UINT nFlags, CPoint point ) = 0; //鼠标拖动
…………
public:
CUIToolsBase ();
virtual ~CUIToolsBase();
protected:
virtual void Execute() = 0; //执行本Tool的操作
};
而其他的Tool都从本类继承而来。
比如选择框的Tool
CUIToolsSelect : public CUIToolsBase
{
public:
virtual void OnMouseDown( UINT nFlags, CPoint point ) //实现代码最好写在cpp文件中,懒下
{
if( 左键 == nFlags /*&& 要判断键盘(Ctrl,Shift,Alt )状态吗 */){
m_StartPt = point ;
m_EndPt = point;
}
}
virtual void OnMouseDraging( UINT nFlags, CPoint point )
{
if( 左键 == nFlags /*&& 要判断键盘(Ctrl,Shift,Alt )状态吗 */){
if( !m_DrawRect ){
XXX( m_StartPt, point ); //异或方式在CDC上绘制矩形框,第一次绘制
}else{
XXX( m_StartPt, m_EndPt ); //异或方式在CDC上清除上一次绘制的矩形框
XXX( m_StartPt, point ); //异或方式在CDC上绘制当前矩形框
}
m_EndPt = point;
}
}
virtual void OnMouseUp( UINT nFlags, CPoint point )
{
if( 左键 == nFlags /*&& 要判断键盘(Ctrl,Shift,Alt )状态吗 */){
if ( m_DrawRect ){
XXX( m_StartPt, m_EndPt ); //异或方式在CDC上清除上一次绘制的矩形框
m_EndPt = point
m_DrawRect = false;
Execute();
}
}
}
public:
CUIToolsSelect () { Init(); }
virtual ~CUIToolsSelect (){ }
protected:
void Init() { m_StarPt = ??; m_EndPt = ??; m_DrawRect = false; }
virtual void Execute()
{
XXXX( m_StartPt, m_EndPt ); //执行选择操作
//这里也可以按Command模式只发出命令
}
private:
CPoint m_StartPt; //启始点
CPoint m_EndPt; //结束点
bool m_DrawRect; //是否已经绘制矩形框标志,初始化为false!
};
如下图:
在要设置Tools的窗口内作如下处理:
CWorkWnd : public XXXX
{
public:
构造,析构......
enum{
UITOOLS_UNKNOW = 0,
UITOOLS_SELECT,
UITOOLS_ERASE,
UITOOLS_LINE,
......
UITOOLS_COUNT = ?
}
public:
void SetCurrentTool( int tool ){ // 外部调用此方法设置Tool
XXXXX // 相关前处理
switch( tool ) {
case UITOOLS_SELECT:
DoSetCurrentTool( new CUIToolsSelect() );
break;
case UITOOLS_ERASE:
DoSetCurrentTool( new CUIToolsErase() );
break;
case UITOOLS_LINE:
DoSetCurrentTool( new CUIToolsLine() );
break;
default:
break;
}
}
protected:
void OnMouseDown( UINT nFlags, CPoint point ){
if ( m_CurrentTool ) {
m_CurrentTool->OnMouseDown( nFlags, point );
}
}
void OnMouseUp( UINT nFlags, CPoint point ) {
if ( m_CurrentTool ) {
m_CurrentTool->OnMouseUp( nFlags, point );
}
}
void OnMouseMove( UINT nFlags, CPoint point ) {
if ( m_CurrentTool ) {
m_CurrentTool->OnMouseMove( nFlags, point );
}
}
void OnMouseDraging( UINT nFlags, CPoint point ){
if( m_CurrentTool ) {
m_CurrentTool->OnMouseDraging( nFlags, point );
}
}
protected:
void DoSetCurrentTool( CUIToolsBase* tool ){
if ( m_CurrentTool ) delete m_CurrentTool;
m_CurrentTool = tool;
}
......
private:
CUIToolsBase* m_CurrentTool; // 只关联到接口,运行时指定对象
}
总结:
此方法思路比较简单:无非是先定义一系列接口,在某个模块( 小到类,函数)中使用接口,执行动作由运行时的实际对象决定。关于这种方式在实际中会碰到很多类似的问题。
扩展:
为软件建立统一的Tools管理类,支持多个工具条。。。