前言:EDIT控件提供的“Number”属性往往无法满足要求,它只能接受数字输入,而经常要需求只接受16进制输入。可以用多种方法(子类化技术,钩子函数,开辟新线程),这里选择子类化技术。
一 认识子类化技术
把一个窗体子类化其实就是使用SetWindowLong为该窗体设计一个新的窗体过程,然后可以在该窗体函数中处理特定的消息,而那些不关心的消息可以通过CallWindowProc传递给系统默认的处理。(有关这方面的介绍网上很多,不过多介绍)
从功能上来说,子类化技术有点类似于钩子函数(SetWindowHookEx),都可以对一些特定的消息自由处理。但在两者有着本质的区别,钩子函数是针对系统的消息传递机制,而子类化技术则是针对特定的窗体。利用钩子函数可以处理某一类或几类的消息,而利用子类化技术则能处理特定窗体的绝大部分消息。因而在使用时应区分被处理对象的范围,然后再选择采用哪种技术。
二 体验子类化技术
资源模板:一个对话框(IDD_TEST_SAMPLE)和一个EDIT控件(IDC_TEST).
测试程序 (程序简单,不作介绍):
#include “resource.h”
#include <TChar.h>
#include <windows.h>
/**********************************
* Global variable
***********************************/
LONG DefWndProc = NULL ;
/**********************************
* Sub function pre-definition
***********************************/
LRESULT CALLBACK EditNewProc ( HWND hEdit, UINT uMsg, WPARAM wParam, LPARAM lParam ) ;
BOOL CALLBACK TestSampleProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) ;
/**********************************
* main function
***********************************/
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
DialogBox ( hInstance, MAKEINTRESOURCE(IDD_TEST_SAMPLE), 0, TestSampleProc ) ;
return 0;
}
/**********************************
* Detail of sub function
***********************************/
LRESULT CALLBACK EditNewProc ( HWND hEdit, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
return CallWindowProc ( (WNDPROC)DefWndProc, hEdit, uMsg, wParam, lParam ) ;
}
BOOL CALLBACK TestSampleProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
LONG DlgWndProc, EditWndProc ;
TCHAR buf[128] ;
switch ( message )
{
case WM_INITDIALOG:
DlgWndProc = GetWindowLong ( hDlg, GWL_WNDPROC ) ;
EditWndProc = GetWindowLong ( GetDlgItem(hDlg,IDC_TEST), GWL_WNDPROC ) ;
wsprintf ( buf, _TEXT(“DlgWndProc : %08XnEditWndProc : %08XnDefWndProc:%08Xn”),
DlgWndProc, EditWndProc, DefWndProc ) ;
MessageBox ( hDlg, buf, _TEXT(“子类化之前”), 0 ) ;
DefWndProc = SetWindowLong (
GetDlgItem(hDlg,IDC_TEST), GWL_WNDPROC, (long)EditNewProc ) ;
return true ;
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDCANCEL:
EndDialog ( hDlg, 0 ) ;
return true ;
}
break ;
case WM_LBUTTONDOWN:
DlgWndProc = GetWindowLong ( hDlg, GWL_WNDPROC ) ;
EditWndProc = GetWindowLong ( GetDlgItem(hDlg,IDC_TEST), GWL_WNDPROC ) ;
wsprintf ( buf, _TEXT(“DlgWndProc : %08XnEditWndProc : %08XnDefWndProc:%08Xn”),
DlgWndProc, EditWndProc, DefWndProc ) ;
MessageBox ( hDlg, buf, _TEXT(“子类化之后”), 0 ) ;
return false ;
}
return false ;
}
测试结果 :
测试说明 :左图==》DlgWndProc和EditWndProc实际上就是系统默认的对话框处理函数体和
编辑框处理函数体。DefWndProc是用来保存编辑框的默认处理函数的入口,
程序中把它初始化为0。
右图==》DefWndProc保存了系统默认的编辑框处理函数体;
EditWndProc即为新添加的函数的入口地址。
三。进入主题–EDIT功能拓展
功能需求 :1)。输入字符个数不大于8
2)。可输入的合法字符(0–9,A–F,a–f)
设计概要 :
1)。由于EDIT功能拓展需要处理是字符,所以选择处理的对象为
WM_CHAR : TCHAR chCharCode = (TCHAR) wParam ; // character code
2)。确保用户输入的字符的合法性
if ( ( chCharCode >= 0X30 && chCharCode <= 0X39 ) || ( chCharCode >= 0X41 && chCharCode <= 0X46 ) || ( chCharCode >= 0X61 && chCharCode <= 0X66 ) ){ //合法 }
3)。保证EDIT中的字符个数不大于8
TCHAR tEditText[9] ;
int iCharacterNum = GetWindowText ( hEdit, tEditText, sizeof(tEditText)/sizeof(TCHAR) ) ;
if ( iCharacterNum < 8 )
{
//符合要求,继续接受字符
}
else
{
//不符合要求,忽略键盘消息(不处理)}
4)。必须保证退格键能够正常运行
if ( chCharCode == _TEXT(8) )
return CallWindowProc ( (WNDPROC)DefWndProc, hEdit, uMsg, wParam, lParam ) ;
注:退格键的ASCII值为8
详细设计(源代码–VC):
#include “resource.h”
#include <TChar.h>
#include <windows.h>
/**********************************
* Global variable
***********************************/
LONG DefWndProc = NULL ;
/**********************************
* Sub function pre-definition
***********************************/
LRESULT CALLBACK EditNewProc ( HWND hEdit, UINT uMsg, WPARAM wParam, LPARAM lParam ) ;
BOOL CALLBACK TestSampleProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) ;
/**********************************
* main function
***********************************/
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
DialogBox ( hInstance, MAKEINTRESOURCE(IDD_TEST_SAMPLE), 0, TestSampleProc ) ;
return 0;
}
/**********************************
* Detail of sub function
***********************************/
注:如果使用EDIT控件时不需要“窗体过程切换”,可以把下面这段EditNewProc直接使用,不然可以使用下一部分的DLL 。
LRESULT CALLBACK EditNewProc ( HWND hEdit, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if ( uMsg == WM_CHAR )
{
TCHAR chCharCode = (TCHAR) wParam ;
if ( ( chCharCode >= 0X30 && chCharCode <= 0X39 ) ||
( chCharCode >= 0X41 && chCharCode <= 0X46 ) ||
( chCharCode >= 0X61 && chCharCode <= 0X66 ) )
{
TCHAR tEditText[9] ;
int iCharacterNum = GetWindowText ( hEdit, tEditText, sizeof(tEditText)/sizeof(TCHAR) ) ;
if ( iCharacterNum < 8 )
{
MessageBeep ( MB_OK ) ;
}
else
return NULL ;
}
else if ( chCharCode == _TEXT(8) )
return CallWindowProc ( (WNDPROC)DefWndProc, hEdit, uMsg, wParam, lParam ) ;
else
return NULL ;
}
return CallWindowProc ( (WNDPROC)DefWndProc, hEdit, uMsg, wParam, lParam ) ;
}
BOOL CALLBACK TestSampleProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_INITDIALOG:
DefWndProc = SetWindowLong (
GetDlgItem(hDlg,IDC_TEST), GWL_WNDPROC, (long)EditNewProc ) ;
return true ;
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDCANCEL:
EndDialog ( hDlg, 0 ) ;
return true ;
}
break ;
}
return false ;
}
说明:当用户按键有效时会产生系统提示音。
四。DLL–功能封装
接口函数 :
BOOL WINAPI SetExternEditFunction (
BOOL isSet, //是否处于拓展状态(切换窗体过程)
HWND hParent, //父窗口句柄
UINT dwEditId //EDIT控件ID
) ;
最重要的功能实现 EditNewProc 与 EditDefWndProc 这两个EDIT窗体过程之间的切换。
附:DLL源码( WINXPSP2,VC6.0,WIN32 DLL )
五:功能更新
7.26更新:支持WM_COPY, WM_CUT, WM_PASTE .
说明:前两个功能比较简单,重点是WM_PASTE.
WM_PASTE功能实现的简略介绍:
1)。取得粘贴板中可复制的合法字串,
2)。检测该字串的长度,若过长则截去多余部分
3)。检测剩余字符串的合法性
4)。模拟键盘消息实现:在鼠标所指向的位置增添字符。
例:EDIT中已有字符串“123Iabc”(‘I’表示鼠标位置)
需要拷贝的字符串“defghijk”
===》 “123deabc”
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国