程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> VC增強Edit控件為日期輸入控件

VC增強Edit控件為日期輸入控件

編輯:關於VC++

MFC所提供的組件已經可以完成很多功能了,但有時候我們還需要這些控件按我們自己的意圖去處理。比如EDIT控件,雖然我們可以設置EDIT控件為只能接受數字屬性,但如果我們還需要它可以接收數字意外的字符,比如需要控件只能接收"2004-02-20"這樣的格式的日期字符呢?我們需要自己在WM_CHAR消息裡面來處理輸入的字符。可是,當輸入字符後,Windows會向Edit控件發送WM_CHAR消息,應用程序會調用Windows默認的Edit控件窗口處理函數WndProc來處理該控件。這時我們需要通過子類化將該窗口對象與自己的Edit類連接起來,這樣,該類的的消息處理函數會替代原來的消息處理函數,窗口消息才能通過自己的類進行消息映射,並首先調用自己的類的消息處理函數,采用自己的Edit類來處理WM_CHAR消息。子類化可以通過宏DDX_Control宏進行靜態關聯,以可以通過函數SubclassWindow()或SubclassDlgItem()完成。

現在講一下該日期輸入框控件實現部分,程序運行如圖一:

圖一 程序運行界面

一、要想自己定義該控件的WM_CHAR消息處理函數,必須先先從CEdit類派生出自己的新類CMyEdit,這一步可以通過ClassWizard來完成。這個類主要完成對編輯框類的WM_CHAR和WN_KEYDOWN消息的處理,以達到對輸入格式的控制。編輯框初始時顯示" - - "的時間輸入格式,要求按"year-month-day"的格式輸入日期。所以初始化時設置控件格式,代碼如下:

void CMyEdit::Initial()
{
   SetLimitText(10);
   SetWindowText("  - - ");
}

二、然後是關鍵的消息處理函數,因為我們需要過濾字符類(包括數字和Backspace鍵)和控制類兩種擊鍵消息(主要包括對Delete的處理)。當用戶輸入或者刪除字符並更新窗口後,要保證"-"在字符串的第5和第8個位置,主要思路是在字符顯示前通過添加" "來修整編輯框中的字符串,使顯示時的字符串達到需要的要求。主要處理的函數如下:

字符消息處理:

void CMyEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
   // TODO: Add your message handler code here and/or call
   int oldpos=LOWORD(GetSel());
   CString str;
   GetWindowText(str);
  
   if ( nChar>=''0'' && nChar<=''9'' )
   {  
     if ( oldpos<4 || ( oldpos>4 && oldpos<7) || oldpos>7)
     {
       str.Delete(oldpos,1);
       SetWindowText(str);
       SetSel(FormatPos(oldpos,oldpos));
       CEdit::OnChar(nChar, nRepCnt, nFlags);
       if ( LOWORD(GetSel())==4 || LOWORD(GetSel())==7)
       {
         oldpos=LOWORD(GetSel());
         SetSel(FormatPos(oldpos+1,oldpos+1));
       }
     }
     else
       if ( oldpos==4 || oldpos==7 )
       {
         oldpos+=1;
         SetSel(FormatPos(oldpos,oldpos));
         str.Delete(oldpos,1);
         SetWindowText(str);
         SetSel(FormatPos(oldpos,oldpos));
         CEdit::OnChar(nChar, nRepCnt, nFlags);
       }
   }
   else
     if ( nChar==VK_BACK )
     {
       if ( (oldpos>0 && oldpos<5) || ( oldpos>5 && oldpos<8) || oldpos>8)
       {
         str.Insert(oldpos,'' '');
         SetWindowText(str);
         SetSel(FormatPos(oldpos,oldpos));
         CEdit::OnChar(nChar, nRepCnt, nFlags);
       }
       else
         if ( oldpos==5 || oldpos==8 )
         {  
           SetSel(FormatPos(oldpos-1,oldpos-1));
         }
     }
    
}

擊鍵消息處理:

void CMyEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
   // TODO: Add your message handler code here and/or call
   CString str;
   int oldpos=LOWORD(GetSel());
   GetWindowText(str);
   if ( nChar==VK_DELETE )
   {
     if ( oldpos<4 || ( oldpos>4 && oldpos<7) || oldpos>7)
     {
       CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
       GetWindowText(str);
       if ( oldpos<7 )
         str.Insert(str.Find(''-'',oldpos),'' '');
       SetWindowText(str);
       SetSel(FormatPos(oldpos,oldpos));
     }
     else
       if ( oldpos==4 || oldpos==7 )
         return ;
   }
   else
     CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
}

三、在對話框類中添加變量 CMyEdit,m_MyEdit,在初始化函數中添加動態子類化函數 :

m_MyEdit.SubclassDlgItem(IDC_EDIT,this);

為了演示一些其他問題,我添加了兩個按鈕子類化和反子類化。相關代碼如下::

子類化:

void CAdEditDlg::OnBtnsub()
{
   m_MyEdit.SubclassWindow(GetDlgItem(IDC_EDIT)->m_hWnd);
   GetDlgItem(IDC_BTNUNSUB)->EnableWindow(true);
   GetDlgItem(IDC_BTNSUB)->EnableWindow(false);
   m_MyEdit.SetFocus();
}

反子類化:

void CAdEditDlg::OnBtnunsub()
{
   m_MyEdit.UnsubclassWindow();
   GetDlgItem(IDC_BTNUNSUB)->EnableWindow(false);
   GetDlgItem(IDC_BTNSUB)->EnableWindow(true);
   GetDlgItem(IDC_EDIT)->SetFocus();
}

附加說明:

1、子類化函數的參數說明:

BOOL SubclassDlgItem( UINT nID, CWnd* pParent);

將一個 Windows 控件與 CWnd 或 CWnd 派生類的對象連接,然後使它通過 CWnd 或 CWnd 派生類的消息映射轉發消息。其中nID為該控件的ID,pParent為控件的父窗口。

BOOL SubclassWindow( HWND hWnd );

作用同SubclassDlgItem,只是該函數通過創後的句柄來完成子類化操作。hWnd為需要子類化的窗口句柄 HWND

UnsubclassWindow();

反子類化,該函數使窗口與子類化所連接的類脫離,使用該控件窗口默認的消息處理函數WndProc來處理。函數返回取消子類化的窗口句柄。

2、如果使采用ClassWizard將編輯框與CMyEdit變量映射後,ClassWizard已經通過DDX_Control宏完成了子類化的過程,如果此時再在對話框的初始化函數中進行子類化的時候,將會發生錯誤。

3、反子類化後,m_MyEdit對象已經與窗口分離,此時不能通過m_MyEdit來處理該窗口需要消息類完成的操作,比如SetFocus(),否則,也會發生錯誤。

注:部分地方參考了《MS VC++ 6.0 MFC類庫參考手冊》

結束語

本文簡單的講了一下如何動態的使控件子類化,從而使控件完成自己需要的功能。這是我前段時間做一套管理軟件時所碰到的問題,雖然比較簡單,但我想對於初級讀者來說,還使又一定幫助的。很希望和大家探討一些更深層次的問題。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved