自定义控件编程

 


摘要 本文分析了Visaul C++中自定义控件DLL的编程方法,以交通灯为例编
制一个自定义控件DLL,并介绍了客户应用程序中使用自定义控件的方法。
关健字 自定义控件,DLL,窗口消息

有一个吸引人的界面是商业软件成功的关键,微软的VisualC++集成开发环境为我们提供了许多标准的控件,如按钮控件,编辑控件,组合框控件等,但是,要设计一个美观的界面这些控件是远远不够的,经常还需要定制自己的特定控件,例如仪器面板、微调按钮等。在Windows的早期程序员开发一个自定义控件DLL非常复杂,现在,开发自己的专用控件,使用MFC库的特性来编制自定义控件DLL就容易多了,如果使用正规的DLL,还可用于任何可接受自定义控件的开发系统。使用自定义控件具有一次编程重复使用,代码小,装入快等优点,因此高级程序员经常使用自定义控件。下面以一个交通灯控件来讨论自定义控件编程,它包括如下过程。
一、 创建自定义控件的窗口类
利用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通知码。
通过以上步骤我们就可以掌握自定义控件编程,由于Ryg.dll是 一个正规的DLL,所以可在Borland C++等可接受自定义控件的开发系统中应用。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值