zoukankan      html  css  js  c++  java
  • MFC窗口子类化

    我写东西很少婆婆妈妈,可能是比较懒散,如果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
    }
    
  • 相关阅读:
    从Java小白到收获BAT等offer,分享我这两年的经验和感悟
    我的Java秋招面经大合集
    从零基础到拿到网易Java实习offer,我做对了哪些事
    设计模式常见面试知识点总结(Java版)
    如何才能够系统地学习Java并发技术?
    这些喜闻乐见的Java面试知识点,你都掌握了吗?
    Java集合类常见面试知识点总结
    用大白话告诉你 :Java 后端到底是在做什么?
    16-使用Selenium模拟浏览器抓取淘宝商品美食信息
    15-分析Ajax请求并抓取今日头条街拍美图
  • 原文地址:https://www.cnblogs.com/zuiyirenjian/p/3102564.html
Copyright © 2011-2022 走看看