1. 程式人生 > >[MFC]在程式中訪問對話方塊中的控制元件——GetDlgItem函式

[MFC]在程式中訪問對話方塊中的控制元件——GetDlgItem函式

1. 使用GetDlgItem函式來訪問對話方塊中的控制元件:

    1) 函式原型:CWnd* CWnd::GetDlgItem(int nID) const;

    2) 只要引數指定為要訪問的控制元件的ID,即可返回該控制元件的指標,但要注意的是返回的是CWnd*型別的指標,是所有視窗型別的父類;

2. 安全地利用GetDlgItem返回的指標來訪問控制元件:

    1) 如果想訪問的是CWnd就有的功能則可以不做任何處理直接訪問,例如:

CWnd* pWnd = GetDlgItem(IDC_CHECK);
pWnd->EnableWindow(TRUE);
!由於使控制元件(或視窗)有效的函式EnableWindow直接繼承自CWnd,因此可以不做任何處理放心地使用;

    2) 拙劣而危險的用法——強型別轉換:

         i. 如果想訪問控制元件特有的功能,則可以嘗試將GetDlgItem的返回值強制轉換為控制元件所對應的型別,例如:

CListBox* pListBox = (CListBox*)GetDlgItem(IDC_LIST);
pListBox->AddString(_T("One"));
         ii. 上面的程式碼之所以可以執行那是因為MFC對CListBox這種控制元件有特殊的支援,換做其它的,例如CComboBox就會失效!!

         iii. 絕對不推薦用這種方法來訪問控制元件的特有功能,因為MFC對這樣的用法不太支援,有些情況下會產生嚴重錯誤,而有些情況下則不起任何作用;

    3) 區域性範圍內臨時訪問對話方塊中的控制元件——利用控制元件型別的Attach函式來繫結對話方塊中的控制元件:

         i. 設想:在對話方塊中類中定義空的控制元件型別的物件作為資料成員,然後利用這些物件的Attach函式將空的物件和對話方塊中的控制元件資源繫結起來,這樣就可以利用這些物件正常訪問控制元件的功能了;

         ii. 例如:

CListBox m_wndListBox;
m_wndListBox.Attach(GetDlgItem(IDC_LIST)->m_hWnd);
m_wndListBox.AddString(_T("One"));
m_wndListBox.Detach();
!!注意:如果這樣的物件是在區域性函式中定義的,則一定要在使用完後解除繫結,否則控制元件資源會隨著物件一併釋放掉,這就會導致對話方塊中的控制元件莫名地突然消失!!

!!Attach和Detach均是從CWnd繼承而來,注意Attach的引數是HWND型別的,所以要用控制元件的m_hWnd作為引數傳入;

!!!該方法仍然不是最優先推薦使用的,因為該方法使用的最多的情況是在區域性函式中臨時要訪問控制元件,因此一旦Attach就必定跟著一個Detach,如果將繫結的物件主體作為視窗的資料成員的話,則Attach需要放在對話方塊的建構函式中使用,而Detach則要放對話方塊的解構函式中使用,這就會產生一個問題,如果這開發的僅僅是一個庫供別人使用,而別人在不知情的情形下又在某個區域性函式中再次Attach,即重複繫結,這會造成執行時錯誤(不能重複繫結和解除繫結),因此這種方法只推薦在區域性函式中訪問控制元件時使用的一種臨時訪問法;

!!因此上面的設想並不好!!!!

    4) 將控制元件程式設計對話方塊的資料成員的完美解決方案——DDX_Control:

         i. 要實現上面的設想MFC提供了完美的解決方案,上面設想中定義的空的空間類成員m_wndXXX,可以在DoDataExchange中用DDX_Control和相應的對話方塊控制元件資源完美而安全地聯絡起來,然後就利用該資料成員肆無忌憚地訪問控制元件的功能,並不用在對話方塊的構造寒素和解構函式中使用Attach和Detach進行繫結和解綁!!

         ii. 函式原型:void AFXAPI DDX_Control(CDataExchange* pDX, int nID, CWnd& rControl);

         iii. 使用示例:

// 在對話方塊派生類中定義相應的控制元件類物件
class CMyDialog: public CDialog
{
...

CListBox m_wndListBox;
...
};

// 然後在DoDataExchange函式中用DDX_Control將該物件和控制元件資源聯絡起來
void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
...
DDX_Control(pDX, IDC_LISTBOX, m_wndListBox);
...
}

// 最後就可以隨意訪問對話方塊控制元件的功能
m_wndListBox.AddString(_T("One"));
    5) DDX_Control的附加功能:

         i. 有時你希望在對話方塊中使用自定義的控制元件,比如利用CListBox派生出一個你自定義的具有特異功能的列表框,並且你想在對話方塊中新增它,那麼現在有一個重要的問題需要解決,那就是這種自定義的控制元件無法在資源指令碼.rc檔案中定義,.rc中只能定義MFC預定義的控制元件;

         ii. 現在DDX_Control又能完美解決這個問題,在.rc中還是照樣定義普通型別的基本控制元件,然後在對話方塊中照樣定義自定義的控制元件型別的物件(比如CMyListBox m_wndMyListBox),最後還是用DDX_Control將.rc中定義的普通控制元件和物件聯絡起來即可,比如DDX_Control(pDX, IDC_LISTBOX, m_wndMyListBox);

         iii. 這就是DDX_Control的附加功能,即可以對資源指令碼中定義的普通控制元件作向下擴充套件,將其擴充套件為自定義型別的派生類物件,這種不僅僅是型別上的向下擴充套件,也是功能上徹徹底底地向下擴充套件;