一、 创建自定义控件的窗口类

    利用Visual C++6.0集成开发环境创建一个名为Ryg的正规的动态连接库。在Ryg.cpp中,加入

extern"C" __declspec(dllexport)void RygEntry(){}

    此虚构的导出RygEntry 函数只是为了DLL能被隐式连接。客户必须包括对该函数的调用,而且调用必须在程序的执行路径里,否则编 译器会忽略该调用。作为选择,客户程序也可以在其InitInstance 函数中调用Win32的LoadLibrary函数,这样可显示连接该 DLL。 在Ryg.cpp 中加入

CRygWnd::RegisterWndClass(AfxGetInstanceHandle());

此函数注册一个窗口。

    现在编制CRygWnd类,在Insert菜单下选择New Class...子菜单,然后创建一个CWnd的派生类CRygWnd类,打开RygWnd.h文件,增加如下内容:

class CRygWnd : public CWnd

{

.........

public:

static BOOL RegisterWndClass(HINSTANCE hInstance);

.........

};

在RygWnd.h中声明了RegisterWndClass函数,现在打开RygWnd.cpp文件,在此文件中编写此函数如下:

BOOL CRygWnd::RegisterWndClass(HINSTANCE hInstance)

{ WNDCLASS wc; wc.lpszClassName = "RYG"; wc.hInstance = hInstance; wc.lpfnWndProc = RygWndProc; wc.hCursor = ::LoadCursor(NULL,IDC_ARROW); wc.hIcon = 0; wc.lpszMenuName = NULL; wc.hbrBackground = (HBRUSH) ::GetStockObject(LTGRAY_BRUSH); wc.style = CS_GLOBALCLASS; wc.cbClsExtra = 0; wc.cbWndExtra = 0; return (::RegisterClass(&wc) != 0);

}

    在函数RegisterWndClass中,首先是构造一个窗口类结构WNDCLASS ,然后,用窗口注册函数 RegisterClass对此窗口注册。对话框资源板利用符号化的窗口类名来指定自定义控件RYG(如图一所示)。在此函数中,最重要的是类名 lpszClassName和指向WNDPROC函数的指针 lpfnWndProc 。在构造好WNDCLASS类结构后,函数 RegisterClass把该结构拷贝到进程内存,进程中的任何函数都可以用该类创建窗口。当对话框被初始化时,Windows根据保存在模板里的窗口 类名,创建自定义控件子窗口。

图 一

    二、 编制Windows过程处理函数WndProc

    在掌握了注册一个窗口类名后,下面要做的是如何编制一个Windows过程WndProc。过程WndProc主要是处理自定义控件窗口 消息,它是自定义窗口与类CRygWnd建立连接的桥梁。为了完成这个工作,首先,我们必须用new构造一个C++类目标,然后,告诉Windows把自 定义控件窗口中的所有消息送到C++类目标,当第一个消息WM_NCCREATE到达时,句柄hWnd为空,因此必须先用new构造一个C++类。下面是 WndProc函数的具体内容。

LRESULT CALLBACK AFX_EXPORT RygWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)

{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); CWnd* pWnd; pWnd = CWnd::FromHandlePermanent(hWnd); if(pWnd == NULL){ pWnd = new CRygWnd(); pWnd->Attach(hWnd); } ASSERT(pWnd->m_hWnd == hWnd); ASSERT(pWnd == CWnd::FromHandlePermanent(hWnd)); LRESULT lResult = AfxCallWndProc(pWnd,hWnd,message,wParam,lParam); return lResult;

}

    当对话框管理者构造一个对话框时,它为对话框里的每一个控件依据其类名调用:CreateWindow,因为我们已经为交通灯注册了类名 RYG,并且告诉Windows送所有的消息到RygWndProc,所以,当对话框管理者创建交通灯控件时,RygWndProc将接收到消息 WM_NCCREATE并构造一个C++类RygWnd。以后所有其他消息将送到AfxCallWndProc。

    三、 自定义控件的窗口消息

    控件窗口与C++类CRygWnd建立起连接后,下面要做的是如何响应窗口消息。控件通过给父窗口发送特定的WM_COMMAND窗口消息与父窗口进行通讯。控件以下面的方式发送窗口消息:

GetParent()->SendMessage(WM_COMMAND,GetDlgCtrlID() | ID_NOTIFYCODE, (LONG)GetSafeHwnd());

在客户方,可以用MFC的ON_CONTROL宏映射消息,如下所示:

ON_CONTROL(ID_NOTIFYCODE,ID_MYCONTROL,OnClickedMyControl)

在此应充分理解SendMessage函数,SendMessage函数原型是:

LRESULT SendMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )

其中,message是指需要发送的消息,可以是WM_COMMAND,WM_HVSCROLL等消息,wParam和lParam参数是一个32位的附加依赖信息,wParam的高16位为通知码,wParam的低16位为子窗口ID,lParam为子窗口句柄。

    下面创建一个左鼠标按下事件:

void CRygWnd::OnLButtonDown(UINT nFlags, CPoint point)

{GetParent()->SendMessage(WM_COMMAND,GetDlgCtrlID() | 0, (LONG)GetSafeHwnd()); CWnd::OnLButtonDown(nFlags, point);

}

通过以上步骤就建立了一个自定义控件RYG的框架,然后,我们可以写设置背景色、三个交通灯等函数,这样一个自定义控件就圆满完成了。

    四、 在程序中使用自定义控件DLL

    以上是自定义控件DLL编程,下面是客户程序如何应用此自定义控件DLL的例子。首先,用对话框编辑器创建一个IDD_RYGTEMP模板,在控件窗口里,选择自定义控件,然后,在模板里画一个自定义窗口ID_RYG,如图二所示:


图 二

    指定自定义窗口类名为RYG(如图一),然后用ClassWizard生产CDialog派生的类CRygDialog。其次,在 RygDialog.cpp文件中编辑构造函数,加入RygEntry()函数,初始化数据成员。最后,映射控件的左按键窗口消息,在 RygDialog.cpp文件里加入消息映射入口和控制函数:

ON_CONTROL(0,IDR_RYG,OnClickRyg)

在上面的OnLButtonDown 函数中的SendMessage定义了通知码0,因此,在ON_CONTROL函数中相应的用0通知码。
Posted on 2011-08-31 10:48  我不是牛人  阅读(1120)  评论(0编辑  收藏  举报