GetDlgItem用法


基本用法(得到當前對話框中的控件):
CButton* btn = (CButton*)GetDlgItem(IDC_BUTTON_SEND);
btn->SetWindowTextW(_T( " hello "));
如果想得到其他對話框中的控件,用GetDlgItem(hwnd,IDD);

CWnd::GetDlgItem(int   nID) 

這個是一個類成員函數,可使用CWnd*   pWnd   =   GetDlgItem(ID_XXX); 
而HWND   GetDlgItem( 
    HWND   hDlg,               //   handle   of   dialog   box 
    int   nIDDlgItem       //   identifier   of   control 
); 
是一個sdk的函數

兩個的主要區別是用的地方不一樣 
一個參數的是在窗口中調用的函數,兩個參數的是在平台SDK中調用的 

你在對話框類里面調用GetDlgItem(IDC_BOARD_SIZE),就是調用的類成員函數CWnd::GetDlgItem

獲得某個控件的句柄GetDlgItem(IDC_BOARD_SIZE)->m_hWnd就可以了


如果要用到第二種用法,要這樣 
::GetDlgItem(this-> m_hWnd,IDC_BOARD_SIZE); 
效果一樣的 

那個IDC_BOARD_SIZE是你某個控件的id, 

如果HWND   GetDlgItem( 
    HWND   hDlg,               //   handle   of   dialog   box 
    int   nIDDlgItem       //   identifier   of   control 
);的話, 
第一個參數是窗體的句柄,第二個參數是某個控件的ID,和IDC_BOARD_SIZE是一個意思

GetDlgItem(IDC_..),GetDlgItem(HWND hWnd, IDC_..)該如何使用,我在使用前者時老報錯,提示應使用后者,但后者的hWnd不知如何獲取。

 GetDlgItem(IDC_..)是一個非靜態方法,意思是你對話框內獲取該控件指針,所以這里不需要獲取對話框句柄,也就是說你如果在非對話框窗口里面調用這個方法就肯定會出錯
GetDlgItem(HWND hWnd, IDC_..)是一個靜態方法,它是一個讓你指定從哪個對話框里獲取控件指針
舉個例子:你調用了上廁所這個函數,如果你在家里的話肯定是在自己家里上廁所,所以不需要知道在哪里上廁所(hwnd)
如果你在室外那么上廁所就一定要選一個地方(hwnd)。
如果說你上廁所的地方都不是一個房間,那么肯定會報錯嘛,因為你在隨地大小便,哈哈
所以你先搞清楚這兩個函數的使用環境區別
再者,你問這個問題說明了你還沒有搞清楚對話框是一個什么東西,建議學習一下深入淺出MFC

------------------------------------------------------------------------------------------

BOOL EnableWindow(

HWND hWnd,      // handle to window  (i)

BOOL bEnable      // flag for enabling or disabling input  (i)

);

函數功能:

 該函數禁止/允許指定的窗口或控件,以便拒絕/接受鼠標和鍵盤的輸入。禁止時,窗口不響應鼠標和按鍵的輸入,允許時,窗口接受所有的輸入。

參數:

hWnd:被禁止/允許的窗口的句柄。

bEnable:定義窗口是被允許,還是被禁止。若該參數為TRUE,則窗口被允許。若該參數為FALSE,則窗口被禁止。

 返回值:

如果窗口原來是禁止態,返回值不為零;如果窗口原來是允許態,返回值為零。若想獲得更多的錯誤信息,可調用GetLastError函數。

備注:

  若窗口的允許/禁止狀會發生變化,則Enblewindow函數將發送WM_ENABLE消息。若窗口已被禁止,那么它所有的子窗口也被禁止,即使他們沒有被發送WM_ENABLE消息。

  窗口被激活前必須處於允許態。比如,一個應用程序正在顯示一個非模態對話框,並且其主窗口處於禁止狀態,則應用程序必須在撤消該對話框之前將其主窗口置於允許態。否則,其他窗口將接受鍵盤輸入焦點並被激活。若子窗口被禁止,則系統在確定由哪個窗口接受鼠標消息時將忽略該窗口。

 窗口被創建時默認為允許態。若創建一個初始化為禁止狀態的窗口,應用程序需要在CreateWindow或CreateWindowEX函數中指定WS_DISABLED風格。窗口在創建后,應用程序可用EnbleWindow函數來將窗口置於允許態或禁止態。

 應用程序可利用此函數允許/禁止對話框中的某個控件。被禁止的控制既不能接受鍵盤輸入,也不能被用戶訪問。

速查:

 

Windows NT:3.1及以上版本;

Windows:95及以上版本;

Windows CE:1.0及以上版本;

頭文件:Winuser.h;

庫文件:user32.lib。

 

用法:EnableWindow(GetDlgItem(hwndDlg,IDC_EDT1),TRUE);

      GetDlgItem(IDC_START)->EnableWindow(FALSE);

由GetDlgItem函數想到的

 

我們在調用CWnd::GetDlgItem()函數時,MSDN告訴我們:The returned pointer may be temporary and should not be stored for later use.

中文意思就是:返回的指針可能是臨時的並且最好不要保存起來放到以后用。

猜測:返回的指針既然可能是臨時的,那么可能是非臨時的(永久的),最好不要保存起來放到以后用(有時候可以保存起來)

源碼面前,了無秘密。讓我們深入MFC源代碼去看個究竟。

先隨便建立一個Dialog程序,然后在窗體上拉一個按鈕,添加按鈕事件,在按鈕事件里寫上如下代碼:GetDlgItem(IDC_BUTTON1); 然后給這行代碼加上斷點。好,我們開始進去看看,運行程序,按下按鈕,程序就停在剛才的斷點出,然后F11進去。

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);

}

再跟蹤到紅色代碼中去:

CWnd* PASCAL CWnd::FromHandle(HWND hWnd)

{

       CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist

       ASSERT(pMap != NULL);

       CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);

#ifndef _AFX_NO_OCC_SUPPORT

       pWnd->AttachControlSite(pMap);

#endif

       ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);

       return pWnd;

}

再一次跟蹤進入紅色函數里去:

CHandleMap* PASCAL afxMapHWND(BOOL bCreate)

{

       AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();

       if (pState->m_pmapHWND == NULL && bCreate)

       {

              BOOL bEnable = AfxEnableMemoryTracking(FALSE);

#ifndef _AFX_PORTABLE

              _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler);

#endif

              pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CTempWnd),

                     offsetof(CWnd, m_hWnd));


#ifndef _AFX_PORTABLE

              AfxSetNewHandler(pnhOldHandler);

#endif

              AfxEnableMemoryTracking(bEnable);

       }

       return pState->m_pmapHWND;

}


看一下AFX_MODULE_THREAD_STATE的定義:

// AFX_MODULE_THREAD_STATE (local to thread *and* module)

class AFX_MODULE_THREAD_STATE : public CNoTrackObject

{

public:

       AFX_MODULE_THREAD_STATE();

       virtual ~AFX_MODULE_THREAD_STATE();


       // current CWinThread pointer

       CWinThread* m_pCurrentWinThread;


       // list of CFrameWnd objects for thread

       CTypedSimpleList<CFrameWnd*> m_frameList;


       // temporary/permanent map state

       DWORD m_nTempMapLock;           // if not 0, temp maps locked

       CHandleMap* m_pmapHWND;

       CHandleMap* m_pmapHMENU;

       CHandleMap* m_pmapHDC;

       CHandleMap* m_pmapHGDIOBJ;

       CHandleMap* m_pmapHIMAGELIST;


       // thread-local MFC new handler (separate from C-runtime)

       _PNH m_pfnNewHandler;


#ifndef _AFX_NO_SOCKET_SUPPORT

       // WinSock specific thread state

       HWND m_hSocketWindow;

#ifdef _AFXDLL

       CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapSocketHandle;

       CEmbeddedButActsLikePtr<CMapPtrToPtr> m_pmapDeadSockets;

       CEmbeddedButActsLikePtr<CPtrList> m_plistSocketNotifications;

#else

       CMapPtrToPtr* m_pmapSocketHandle;

       CMapPtrToPtr* m_pmapDeadSockets;

       CPtrList* m_plistSocketNotifications;

#endif

#endif

};


看一下黃色的那一行代碼,很明顯,MFC說臨時的map可以被鎖定,先記住就可以。

看一下黃色下面的代碼:

       CHandleMap* m_pmapHWND;

       CHandleMap* m_pmapHMENU;

       CHandleMap* m_pmapHDC;

       CHandleMap* m_pmapHGDIOBJ;

       CHandleMap* m_pmapHIMAGELIST;

很明顯,這里放了一些臨時的映射,包括HWND到CWnd,HDC到CDC的,等等。

並且,MFC除了這些臨時的映射表之外,還有永久的映射表。

也就是說,GetDlgItem以及FromHandle等函數返回的CWnd以及CDC等指針是可以保存的,不管是臨時的map還是永久map中的,我們都可以安全的保存,前提是把臨時的map鎖定,那么不管怎么樣,返回的指針可以在任何時候都是安全的。默認的,MFC是在空閑時間里把臨時map里的東西清空掉的。


剛才說到在空閑時間MFC會把臨時的map刪除掉,我們在剛才那個按鈕事件里添上如下代碼:

AfxGetApp()->OnIdle(1);


然后運行並跟蹤到如下函數:

BOOL CWinApp::OnIdle(LONG lCount)

{

       if (lCount <= 0)

       {

              CWinThread::OnIdle(lCount);

              // call doc-template idle hook

              POSITION pos = NULL;

              if (m_pDocManager != NULL)

                     pos = m_pDocManager->GetFirstDocTemplatePosition();

              while (pos != NULL)

              {

                     CDocTemplate* pTemplate = m_pDocManager->GetNextDocTemplate(pos);

                     ASSERT_KINDOF(CDocTemplate, pTemplate);

                     pTemplate->OnIdle();

              }

       }

       else if (lCount == 1)

       {

              VERIFY(!CWinThread::OnIdle(lCount));

       }

       return lCount < 1;  // more to do if lCount < 1

}

再跟蹤進上面的紅色函數中,整個函數如下:

BOOL CWinThread::OnIdle(LONG lCount)

{

       ASSERT_VALID(this);

#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)

       // check MFC's allocator (before idle)

       if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)

              ASSERT(AfxCheckMemory());

#endif

       if (lCount <= 0)

       {

              // send WM_IDLEUPDATECMDUI to the main window

              CWnd* pMainWnd = m_pMainWnd;

              if (pMainWnd != NULL && pMainWnd->m_hWnd != NULL &&

                     pMainWnd->IsWindowVisible())

              {

                     AfxCallWndProc(pMainWnd, pMainWnd->m_hWnd,

                            WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);

                     pMainWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,

                            (WPARAM)TRUE, 0, TRUE, TRUE);

              }

              // send WM_IDLEUPDATECMDUI to all frame windows

              AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;

              CFrameWnd* pFrameWnd = pState->m_frameList;

              while (pFrameWnd != NULL)

              {

                     if (pFrameWnd->m_hWnd != NULL && pFrameWnd != pMainWnd)

                     {

                            if (pFrameWnd->m_nShowDelay == SW_HIDE)

                                   pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);

                            if (pFrameWnd->IsWindowVisible() ||

                                   pFrameWnd->m_nShowDelay >= 0)

                            {

                                   AfxCallWndProc(pFrameWnd, pFrameWnd->m_hWnd,

                                          WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);

                                   pFrameWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI,

                                          (WPARAM)TRUE, 0, TRUE, TRUE);

                            }

                            if (pFrameWnd->m_nShowDelay > SW_HIDE)

                                   pFrameWnd->ShowWindow(pFrameWnd->m_nShowDelay);

                            pFrameWnd->m_nShowDelay = -1;

                     }

                     pFrameWnd = pFrameWnd->m_pNextFrameWnd;

              }

       }

       else if (lCount >= 0)

       {

              AFX_MODULE_THREAD_STATE* pState = _AFX_CMDTARGET_GETSTATE()->m_thread;

              if (pState->m_nTempMapLock == 0)

              {

                     // free temp maps, OLE DLLs, etc.

                     AfxLockTempMaps();

                     AfxUnlockTempMaps();

              }

       }

#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)

       // check MFC's allocator (after idle)

       if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_CHECK_ALWAYS_DF)

              ASSERT(AfxCheckMemory());

#endif

       return lCount < 0;  // nothing more to do if lCount >= 0

}


怎么樣,當了老半天的間諜了,總算能看出點門道了吧?上面3行紅色的代碼說的很清楚,這里會把臨時的map釋放掉。

兩個函數的代碼如下:

AfxLockTempMaps();

AfxUnlockTempMaps();

void AFXAPI AfxLockTempMaps()

{

       AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();

       ++pState->m_nTempMapLock;

}

BOOL AFXAPI AfxUnlockTempMaps(BOOL bDeleteTemps)

{

       AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();

       if (pState->m_nTempMapLock != 0 && --pState->m_nTempMapLock == 0)

       {

              if (bDeleteTemps)

              {

                     if (bDeleteTemps != -1)

                     {

                            // allow COM libraries to be freed

                            CWinThread* pThread = AfxGetThread();

                            if (pThread != NULL && pThread->m_lpfnOleTermOrFreeLib != NULL)

                                   (*pThread->m_lpfnOleTermOrFreeLib)(FALSE, FALSE);

                     }


                     // clean up temp objects

 

                     pState->m_pmapHGDIOBJ->DeleteTemp();

 

                     pState->m_pmapHDC->DeleteTemp();

 

                     pState->m_pmapHMENU->DeleteTemp();

 

                     pState->m_pmapHWND->DeleteTemp();

 

                     pState->m_pmapHIMAGELIST->DeleteTemp();

              }


#ifndef _AFX_PORTABLE

              CWinApp* pApp = AfxGetApp();

              _AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();

              // restore safety pool after temp objects destroyed

              if (pApp != NULL &&

                      (pThreadState->m_pSafetyPoolBuffer == NULL ||

                      _msize(pThreadState->m_pSafetyPoolBuffer) < pApp->m_nSafetyPoolSize) &&

                     pApp->m_nSafetyPoolSize != 0)

              {

                     // attempt to restore the safety pool to its max size

                     size_t nOldSize = 0;

                     if (pThreadState->m_pSafetyPoolBuffer != NULL)

                     {

                            nOldSize = _msize(pThreadState->m_pSafetyPoolBuffer);

                            free(pThreadState->m_pSafetyPoolBuffer);

                     }


 


                     // undo handler trap for the following allocation

                     BOOL bEnable = AfxEnableMemoryTracking(FALSE);

                     pThreadState->m_pSafetyPoolBuffer = malloc(pApp->m_nSafetyPoolSize);

                     if (pThreadState->m_pSafetyPoolBuffer == NULL)

                     {

                            TRACE1("Warning: failed to reclaim %d bytes for memory safety pool.\n",

                                   pApp->m_nSafetyPoolSize);

                            // at least get the old buffer back

                            if (nOldSize != 0)

                            {

                                   //get it back

                                   pThreadState->m_pSafetyPoolBuffer = malloc(nOldSize);

                                   ASSERT(pThreadState->m_pSafetyPoolBuffer != NULL);

                            }

                     }

                     AfxEnableMemoryTracking(bEnable);

              }

#endif  // !_AFX_PORTABLE

       }


       // return TRUE if temp maps still locked

       return pState->m_nTempMapLock != 0;

}


看到上面黃色的代碼了吧,這時候你還敢保存GetDlgItem或者FromHandle返回的指針嗎?

剛才你不是說可以鎖定臨時map的嗎?是的,可以用AfxLockTempMaps鎖定,但是必須與AfxUnlockTempMaps配對使用,其內部有一個計數變量。MSDN上沒這個函數,最好不要用它,否則除了什么問題我可不保證哦 J


永久的map存放的應該就是我們顯示創建的例如CWnd此類的對象了。

其實很多函數如FromHandle、FindWindow等函數都是用到了這種技術,所以MSDN必定有這樣類似這樣的一句話:The returned pointer may be temporary and should not be stored for later use.


有興趣大家自己跟蹤代碼,源碼面前了無秘密


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM