MFC สรุปการควบคุมที่ใช้กันทั่วไปจำนวนมากและสรุปชื่อคลาสโดยไม่ต้องมีอินเทอร์เฟซที่ชัดเจน ในการเขียนโปรแกรมหน้าต่างโดยใช้ win api ขั้นตอนแรกคือการลงทะเบียนคลาสหน้าต่าง
ในขณะนี้ ชื่อคลาสและชื่อชื่อเรื่องถูกลงทะเบียนไว้ด้วยกัน ดังนั้นชื่อคลาสจึงควรเป็นเรื่องง่ายมาก น่าเสียดาย ที่ MFC ไม่ทำเช่นนี้ สาเหตุอาจเป็นเพราะชื่อหน้าต่าง สามารถเปลี่ยนได้เรื่อยๆ แต่ชื่อคลาสทำไม่ได้ ชื่อคลาสของหน้าต่างถูกกำหนดโดย Create ก่อนที่จะสร้าง คุณต้องเลือกชื่อคลาสของหน้าต่างที่ลงทะเบียนไว้สำหรับหน้าต่าง ในที่สุด CreateEx ก็จะปรากฏขึ้น ที่ CreateEx ชัดเจนยิ่งขึ้น
บูล CWnd::CreateEx (DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& แก้ไข, CWnd* pParentWnd, UINT nID, LPVOID lpParam /* = NULL */){ return CreateEx (dwExStyle, lpszClassName, lpszWindowName, , rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, pParentWnd->GetSafeHwnd(), (HMENU)(UINT_PTR)nID, lpParam);}BOOL CWnd::CreateEx (DWORD dwExStyle, LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) { ยืนยัน (lpszClassName == NULL || AfxIsValidString (lpszClassName) ||. Afx IsValidAtom( lpszClassName )); ENSURE_ARG(lpszWindowName == NULL || AfxIsValidString(lpszWindowName)); // อนุญาตให้แก้ไขพารามิเตอร์การสร้างทั่วไปหลายอย่าง CREATESTRUCT cs; cs.dwExStyle; cs.lpszClass = cs.lpszName = cs สไตล์ = dwStyle; cs.x = x; cs.y = y; cs.cy = nHeight; cs.hwndParent; ) { PostNcDestroy(); return FALSE; } AfxHookWindowCreate(สิ่งนี้); cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);#ifdef _DEBUG if (hWnd == NULL) { TRACE(traceAppMsg, 0, "คำเตือน : การสร้างหน้าต่างล้มเหลว: GetLastError ส่งกลับ 0x%8.8 Xn", GetLastError()); }#endif if (!AfxUnhookWindowCreate()) PostNcDestroy(); // การล้างข้อมูลหาก CreateWindowEx ล้มเหลวเร็วเกินไปถ้า (hWnd == NULL) ส่งคืน FALSE; ASSERT(hWnd == m_hWnd); // ควรตั้งค่าให้ send msg hook return TRUE;}
คุณจะเห็นว่าในที่สุดก็มาถึง::AfxCtxCreateWindowEx คุณสามารถรู้ได้อย่างง่ายดายว่า CreateWindowEx ถูกเรียกที่นี่เพื่อสร้างหน้าต่าง
มี PreCreateWindow(cs) อยู่ด้านหน้า และหลังจากที่ cs ได้รับการประมวลผลโดย PreCreateWindow แล้ว มันจะถูกส่งไปที่ ::AfxCtxCreateWindowEx เพื่อประมวลผล
::AfxCtxCreateWindowEx ถูกโอนไปยัง CreateWindowEx cs.lpszClass เป็นชื่อคลาส ซึ่งทำให้ชัดเจนว่า AfxCtxCreateWindowEx มีเจตนาดี
เราสามารถโอเวอร์โหลด PreCreateWindow เพื่อแก้ไขชื่อคลาสได้ดังนี้:
// สิ่งที่ต้องทำ: เพิ่มโค้ดพิเศษที่นี่และ/หรือเรียกคลาสพื้นฐาน //VERIFY(AfxDeferRegisterClass(AFX_WND_REG)); //AfxEndDeferRegisterClass(AFX_WND_REG); //cs.lpszClass = AfxRegisterWndClass(NULL); 0, sizeof(WNDCLASS)); // เริ่มต้นด้วย NULL // defaults wndcls.style = CS_HREDRAW |. CS_VREDRAW; // คุณสามารถระบุขั้นตอนหน้าต่างของคุณเองได้ wndcls.lpfnWndProc = ::DefWindowProc; ; wndcls.hIcon = NULL; // หรือโหลดไอคอนอื่น wndcls.hCursor = NULL; wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndcls.lpszClassName = _T("MyNewClass"); // ลงทะเบียนคลาสใหม่และออกหากล้มเหลว if(!AfxRegisterClass(&wndcls)) { TRACE("การลงทะเบียนคลาสล้มเหลวn"); return FALSE; wndcls.lpszClassName; กลับ TRUE; // กลับ CWnd::PreCreateWindow(cs);
ในความเป็นจริง มันคือการส่งสตริงชื่อคลาสที่ลงทะเบียนไปที่ CreateWindowEx เมื่อพิจารณาจากความคิดเห็นในโค้ดข้างต้น ฉันยังใช้ AfxRegisterWndClass ซึ่งเป็นวิธีการที่ช่วยให้ระบบสร้าง className CWnd::PreCreateWindow ไม่ตรงกับความปรารถนาของฉัน ดังนั้นฉันจึงแสดงความคิดเห็น จริงๆ แล้วไม่มีอะไรอยู่ในนั้น มันเป็นเพียงการตัดสิน ใน MFC คลาสที่ได้รับอื่น ๆ ของ CWnd นั้นไม่ง่ายนัก อย่างไรก็ตาม เพียงแค่แก้ไขชื่อคลาสและการโอเวอร์โหลดวิธีนี้ส่วนใหญ่จะใช้ได้
ใช่ ส่วนใหญ่สามารถทำได้ น่าเสียดาย วิธีนี้ใช้ไม่ได้กับ Dialog เนื่องจากไม่ได้ใช้ CWnd::Create ดังนั้นจึงไม่สามารถหลีกเลี่ยงได้
PreCreateWindow กำลังมาถึง คุณสามารถโอเวอร์โหลดวิธีการนี้ของกล่องโต้ตอบได้ เนื่องจากการสร้าง CDialog สามารถทำได้โดยตรงโดยใช้ API ของระบบ และไม่จำเป็นต้องรบกวน CWnd เพื่อถ่ายโอนไปยัง CReateWindowEx ดังนั้นคุณจึงไม่สามารถใช้วิธีการข้างต้นเพื่อเปลี่ยนชื่อคลาสของกล่องโต้ตอบได้
ดูรหัสการสร้าง:
bool cdialog :: create (lpctstr lpsztemplatename, cwnd* pparentwnd) {assert (is_intresource (lpsztemplatename) || afxisvalidstring (lpsztemplatename); templatename) && m_nid help == 0) m_nIDHelp = LOWORD((DWORD_PTR)m_lpszTemplateName);#ifdef _DEBUG if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE)) { ASSERT(FALSE); // ชื่อเทมเพลตกล่องโต้ตอบไม่ถูกต้อง PostNcDestroy(); // การล้างข้อมูลหากการสร้างล้มเหลวเร็วเกินไป ให้คืนค่า FALSE; } #endif //_DEBUG HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG); HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG); ) ; FreeResource(hTemplate);
จะเห็นได้ว่า CDialog ถูกสร้างขึ้นโดยทรัพยากร สามารถทำได้ในลักษณะนี้ กำหนดคลาส "ชื่อคลาสกล่องโต้ตอบ" ในสคริปต์ทรัพยากร ลงทะเบียนชื่อคลาสนี้ก่อน domodal หรือสร้างในกล่องโต้ตอบ จากนั้นรอ modal และ สร้าง แค่นั้นแหละ.
ในช่วงเวลานี้ ฉันยุ่งอยู่กับด้านอื่นๆ และฉันลืมไปมากเกี่ยวกับกลไกการบรรจุ MFC ฉันจะติดตามโค้ดเพื่อทบทวนความจำ