MFC窗口子类化

简介: 我写东西很少婆婆妈妈,可能是比较懒散,如果2个字能说完,绝对不会说三个字以上,有朋友开玩笑说“言语珍贵”,因为简单,很多人不理解,所以也有“跳跃性思维”的说法。 对一个问题,我喜欢”自悟“,一定要知道所以然,即使有一些细节不知,但是整个过程是不应该出现错误,对于问题,我喜欢“心神领会”,只有领会了...

我写东西很少婆婆妈妈,可能是比较懒散,如果2个字能说完,绝对不会说三个字以上,有朋友开玩笑说“言语珍贵”,因为简单,很多人不理解,所以也有“跳跃性思维”的说法。

对一个问题,我喜欢”自悟“,一定要知道所以然,即使有一些细节不知,但是整个过程是不应该出现错误,对于问题,我喜欢“心神领会”,只有领会了,才可以游刃有余,

在使用的时候方可如鱼得水,其次领会一个问题,可以让大脑轻松,而不被宿主在大脑中的问题所困扰,这也是所谓的快乐学习,但是弄懂一个问题,是要以时间为代价的,生命如此短暂,我又能弄懂几个问题?

蹉跎的岁月让人一天天变老,让人一天天憔悴,让人的脑细胞在生与死的斗争中,终于死的越来越多,这就是所谓的规律。哀叹时光的流逝,自己却无能无力,只能反省,反省……。

时间在让我们老去的同时,让我们越来越聪明,越来越有智慧,人就因为有太多的不明白,所以才活着,如果都明白了,估计也就是在死亡的那一刻吧!

过于追去完美,过于追求,为什么,让自己在和时间的赛跑中成了一个失败者,无心留恋逝去的光阴,无心幻想剩下的岁月,只有无力的哀叹!

 08年的时候,机缘巧合看了《深入浅出MFC》,也许是因为有一门课程就是VC++开发的,但是当时看那本书,很是晦涩难懂,而因为一些原因,VC++开发的课程也夭折了,一晃,

已经5年过去了,凭借自己的坚持,终于将《深入浅出MFC》看完了,也了解了很多以前觉得晦涩难懂的东西,可能真是自己当时的知识不够而已,也许是自己天资愚笨。用时间去战胜问题是我最大的总结。

言归正传,MFC窗口对象和窗口句柄是两个完全不同的东西,前者是一个C++对象,而后者是一个window对象或者window控件或者windows的一种资源,后者其实就类似一个身份证的东西,唯一标识了它的身份,而这个身份又是前者的一个成员变量,这可能是我们最初的认识吧。

但是当遇到子类化这个概念的时候,懵了,一头雾水,丈二的和尚摸不着头脑?子类化,简单地说就是替换了window窗口句柄的处理过程,书上都这么说,我也就这么说,其实这个还是要从前面的一句话说起,这个所谓的C++对象是如何和window句柄关联起来的?

create函数,这个不应该陌生,在create函数中调用了createx函数等一系列相关的函数,而这些函数做了大概以下事情,注册一个窗口,创建一个窗口返回一个句柄,这个时候这个句柄就放在了m_hWnd成员变量中,在《深入浅出MFC》中,在主窗体创建的时候还有一个偷天换日的动作,那就是将默认的处理函数替换成了我afxwndproc,而这个就对应了所在类的消息映射函数,其实这个就是一个子类化过程,暂且就这么理解吧。所以create函数已经帮我们子类化了,如果细细跟踪下去,会遇到setwindowlong等函数,这些可以自己动手去跟踪下,我点到为止。create函数因为将句柄和C++对象关联起来了,我们当然就可以用C++对象对窗口进行操作了,其实里面调用的还是win32 api,只是这些都被封装在了这个C++对象中,现在应该有豁然开朗和柳暗花明又一村的感觉了吧,当然句柄和C++也就是这个MFC对象关联不仅仅是create函数这一种方式,subclasswindow和DDX也是可以的,跟踪下去这些包含create都是调用了attach和setwindowlong这个函数,源码面前无秘密,大家可以去源码中看看。

 

 

这里我只是写了一个字符串而已:
void CMFCTestDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); //DDX_Control(pDX, IDC_EDIT1, m_edit); m_edit.SubclassWindow(GetDlgItem(IDC_Test)->m_hWnd); m_edit.SetWindowTextW(L"liuyu"); } CWnd* CWnd::GetDlgItem(int nID) const { ASSERT(::IsWindow(m_hWnd)); if (m_pCtrlCont == NULL) return CWnd::FromHandle(::GetDlgItem(m_hWnd, nID)); else return m_pCtrlCont->GetDlgItem(nID); }

 

 

如果向我上面的这种写法,是实现不了子类化的,为什么?因为我这个操作只是将控件和类关联起来了?这可以从头文件中看出来:

 

CEdit m_edit;

通俗来讲子类化就是用自己的窗口处理函数来处理特定消息,并将自己其他消息还给标准(默认)窗口处理函数,而CEdit是微软定义的基类,里面定义了对EDIT控件默认的消息处理函数.

 

看到这个CEdit,我们似乎应该知道原因,这个是一个基类,或者说是从CWnd派生的一个窗口对象。在子类化介绍的时候,往往会用一个对输入的字符做判断这个例子,如果我们没有在CEdit这个类做特殊处理,我们就无法实现对输入字符的判断?那我们可以不可以在CEdit中添加,其实理论上是可行的,但是不这么做,你想下,这样将基类都破坏了,微软的人看了,还不会被气死,所以我们可以这么做,从CEdit派生一个类,回想主窗体创建的那个过程?这两个就类似,当然可以在这个派生类中添加消息处理函数了。

 

一般在使用子类化的时候,从基类中派生一个子类,这样我们就会自己去定制想要的功能!一旦有了子类,我们就可以在子类中添加要处理的函数,并且采用自己熟悉的方式进行句柄关联……,这算是我对子类化的一点个人看法,如果有什么想法,可以跟我探讨!下面附上我的一些操作代码:

 

 

 

头文件
CEdit m_edit;
CmyEdit m_edit1;

 

 

所谓的子类化
void CMFCTestDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	//DDX_Control(pDX, IDC_EDIT1, m_edit);
	m_edit1.SubclassWindow(GetDlgItem(IDC_Test)->m_hWnd);
	//m_edit.SetWindowTextW(L"ss");
}

 

 

 

派生类中对OnChar的处理,这里我将第一个输入的字母A改成了B,不要注释掉CEdit::OnChar(nChar, nRepCnt, nFlags),但是可以注释下看看效果。

void CmyEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) {  // TODO: 在此添加消息处理程序代码和/或调用默认值

 CString ch;

 GetWindowText(ch);  // 获得已输入的字符序列

 if(strlen(ch)==0&&nChar == 'A')  {         SetWindowTextW(this->m_hWnd,L"B");

  return ;  }

  

   CEdit::OnChar(nChar, nRepCnt, nFlags);

}

 前面我们说到过create这函数,这个函数其实就是创建一个window的句柄对象或者说window对象(区别C++对象)

那么如果我们有了一个子类,不是通过拖放控件的方式,我们可以自己用create函数去做这个子类化,代码如下:

 

BOOL CMFCTestDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码


	CRect r(20,10,300,500); 
	//GetClientRect(&r);


	m_edit1.Create(WS_VISIBLE|WS_CHILD,r,this,10003);

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

 

 

 

相关文章
|
3月前
Qt3个窗口类的区别
一个普通的窗口,不包含菜单栏、状态栏,除了登录界面,新建项目时建议使用QWidget,因为大部分的窗口可能都要做成无边框窗口,需要自定义标题栏,实现拉伸等;QMainWindow使用的场景不多。:对话框,常用来做登录窗口、弹出窗口(例如设置界面):包含菜单栏、工具栏、状态栏。
38 0
|
4月前
|
消息中间件 SQL 安全
[MFC] CWnd类总结
[MFC] CWnd类总结
35 0
MFC CFileFind类用法总结
MFC CFileFind类用法总结
329 0