Chinaunix首页 | 论坛 | 博客
  • 博客访问: 80551
  • 博文数量: 27
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 300
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-21 11:32
文章分类

全部博文(27)

文章存档

2010年(3)

2009年(13)

2008年(11)

我的朋友

分类: C/C++

2009-06-28 13:07:01

对于我们使用ArcEngine开发,最常用的控件就是地图控件了。这个是一个ActiveX控件。但是,如果问如何创建MapControl控件?这个问题看起来不值得问。因为太简单了啊,凡是写过几行代码的人都会,不就是在窗体上拖一个控件摆上

 

其实啊,我不这样想。我觉得,对于拖一个控件到窗体上的方法,有一个弊端。那就是万一当我们的程序放到忘记安装ArcEngine运行时的用户电脑上,运行程序时候,效果是直接出来一个醒目的感叹号,死的非常难看。

 

当然,这样的情况应该不会经常遇到的。不过,从程序的健壮,稳定性,用户感受的角度来说,还是避免那个难看的错误为好。如果我们的程序一打开,判断出了差错,马上友好告诉用户,哈嘿,您的电脑还要安装ArcEngine运行时才行呢。你看,这多好

 

有没有办法避免?能避免。因为我们程序员是聪明的,办法总是能找到啊

办法一,是在运行时候提前检查系统能否运行你的程序,根据情况做相应的处理。这个怎么检查呢?我觉得,办法是查看注册表。这个方法有点难度,因为你现在知道ArcEngine9.0注册表是这样,万一到9.4版本时候,ArcEngine在注册表存储的方式变化了呢? 没有办法,打开注册表看看ArcEngine信息具体是怎么存储的,更改程序。

 

办法二,运行时候创建MapControl控件。我个人觉得该方法很好。好处是,不用理会注册表内容。由于控件是在运行时候才创建的,如果创建不成功,基本上肯定当前系统没有安装ArcEngine运行时了。这个时候提示用户,然后结束运行。

 

我们要怎么办,才能在运行时候创建这个控件呢?目前我知道方法有两个:

 

· VC的向导事先生成一个控件类CMapControl

class CMapControl : public CWnd

{

protected:

DECLARE_DYNCREATE(CMapControl)

public:

CLSID constGetClsid()

{

static CLSID const clsid

= { 0xC552EA94, 0x6FBB, 0x11D5, { 0xA9, 0xC1, 0x0, 0x10, 0x4B, 0xB6, 0xFC, 0x1C } };

return clsid;

}

virtual BOOL Create(LPCTSTR lpszClassNameLPCTSTR lpszWindowNameDWORD dwStyle,

const RECTrectCWndpParentWndUINT nID

CCreateContextpContext = NULL)

return CreateControl(GetClsid(), lpszWindowNamedwStylerectpParentWndnID); 

}

    BOOL Create(LPCTSTR lpszWindowNameDWORD dwStyleconst RECTrectCWndpParentWnd

UINT nIDCFilepPersist = NULLBOOL bStorage = FALSE,

BSTR bstrLicKey = NULL)

return CreateControl(GetClsid(), lpszWindowNamedwStylerectpParentWndnID,

pPersistbStoragebstrLicKey); 

}

// 属性

public:

  省略

};

 

  有了上述的类定义,那么创建的方法很简单了:

    if (!m_wndMapCtrl9.Create(NULLWS_CHILD|WS_VISIBLECRect(0,0,30,30), pParentMapControlID))

{

AfxMessageBox(strErrorMB_OK | MB_ICONSTOP);

return FALSE;

}

 

· 方法二。方法一看起来很好,也没有什么问题,也确实没有什么问题。不过,ArcEngine9.0ArcEngine9.2生成的类函数不一样了,也就是说,不同版本的函数定义有差异,没有办法通用了。这个就是采用高度封装带来便利的同时,也带来了弊端。我们有办法解决这个问题吗?答案是有的。我的办法是不用上述的类了。我先定义一个窗体对象(这里采用WTL的实现,其实用MFC也是一样的)和一个地图控件接口:

     IMapControl2Ptr m_ipMapControl2;

    CAxWindow m_wndMapControl;

然后,接下来需要做工作的是创建一个容纳地图控件的窗体:

CRect rcClient;

GetClientRect(&rcClient);

HWND hWnd = m_wndMapControl.Create(*thisrcClient_T(""), WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, 0, IDC_MAPCONTROL1);

if (NULL == hWnd)

{

::MessageBox(::GetActiveWindow(), _T("未知错误,无法创建MapControl控件容器。"), _T("严重错误"), MB_OK | MB_ICONSTOP);

return FALSE;

}

窗体有了,那么接着的工作就是得到地图控件的接口:

CComPtr<IUnknownpunkCtrl = NULL;

HRESULT hr = m_wndMapControl.CreateControlEx(L"{C552EA94-6FBB-11D5-A9C1-00104BB6FC1C}"NULLNULL, &punkCtrl );

if (FAILED(hr) || NULL == punkCtrl)

{

::MessageBox(::GetActiveWindow(), _T("当前系统没有安装ArcEngine环境,无法创建MapControl控件。"), _T("严重错误"), MB_OK | MB_ICONSTOP);

return FALSE;

}

hr = m_wndMapControl.QueryControl(IID_IMapControl2, (void**)&m_ipMapControl2);

看,到了这里,动态创建的步骤结束了,一个ActiveX控件就出来了。每个步骤都是可以控制的,随时知道问题出在那里。程序运行过程不会出现难看的感叹号了。

上述方式解决了动态创建的问题,紧接着的问题是,我们怎么监听到地图控件的事件呢?比如鼠标按下、移动等等? 这个问题其实很简单的,去这里参见我的文章 http://blog.chinaunix.net/u2/79895/showart_1954500.html

阅读(5537) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~