Download presentation
Presentation is loading. Please wait.
Published byRolf Lloyd Modified over 9 years ago
1
Chap. 6 Dialog and Control Classes
2
Contents CDialog class Common Dialogs Property Sheets Control classes
3
CDialog Class Dialog 의 종류 Modal dialog Close 될 때 까지 다른 부분을 사용할 수 없음 Close 될 때 까지 다른 부분을 사용할 수 없음 DoModal() 함수를 이용 DoModal() 함수를 이용 예 : common dialog box 예 : common dialog box Modeless dialog Close 되기 전에 다른 부분을 사용할 수 있음 Close 되기 전에 다른 부분을 사용할 수 있음 Create() 함수를 이용 Create() 함수를 이용 DestroyWindow() 함수를 이용하여 명시적으로 종료함 DestroyWindow() 함수를 이용하여 명시적으로 종료함 예 : find and replace dialog box 예 : find and replace dialog box
4
CDialog Class (cont’d) History MFC 1.0 Modal dialog : CModalDialog Modal dialog : CModalDialog Modeless dialog : CDialog Modeless dialog : CDialog Current version Modal dialog : CDialog Modal dialog : CDialog Modeless dialog : Cdialog Modeless dialog : Cdialog AFXWIN.H // all CModalDialog functionality is now in CDialog #define CModalDialog CDialog
5
CDialog Class (cont’d) void CMyView::DisplayOrderDialog() { CMyDialog myDialog(ID_DLG_MYDIALOG); if ( myDialog.DoModal() == IDOK ) { // Do OK processing } else { // Do Calnel processing } m_pDlgMyDlgPtr = new CMyDialog; m_pDlgMyDlgPtr->Create(ID_DLG_MYDIALOG); // Do something m_pDlgMyDlgPtr->DestroyWindow(); m_pDlgMyDlgPtr = NULL;
6
Win32 APIs Dialog 생성을 위한 Win32 APIs CreateDialog() Modeless dialog 생성, template resource 이용 Modeless dialog 생성, template resource 이용 CreateDialogIndirect() Modeless dialog 생성, template pointer 이용 Modeless dialog 생성, template pointer 이용 DialogBox() Modal dialog 생성, template resource 이용 Modal dialog 생성, template resource 이용 DialogBoxIndirect() Modal dialog 생성, template pointer 이용 Modal dialog 생성, template pointer 이용
7
Win32 APIs (cont’d) CDialog Class 오직 CreateDialogIndirect() API 을 이용 Modality 를 내부적으로 구현 AFXWIN.H DLGCORE.CPP, AFXWIN2.INL
8
CDialog class CDialog : public CWnd { DECLARE_DYNAMIC(CDialog) BOOL Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); BOOL Create(UINT nIDTemplate, CWnd* pParentWnd = NULL); BOOL CreateIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd = NULL, void* lpDialogInit = NULL); BOOL CreateIndirect(HGLOBAL hDialogTemplate, CWnd* pParentWnd = NULL); // Modal construct public: CDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); CDialog(UINT nIDTemplate, CWnd* pParentWnd = NULL); BOOL InitModalIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd = NULL, void* lpDialogInit = NULL); BOOL InitModalIndirect(HGLOBAL hDialogTemplate, CWnd* pParentWnd = NULL); // Operations public: // modal processing virtual int DoModal();
9
CDialog (cont’d) void NextDlgCtrl() const; void PrevDlgCtrl() const; void GotoDlgCtrl(CWnd* pWndCtrl); // termination void EndDialog(int nResult); // Overridables (special message map entries) virtual BOOL OnInitDialog(); virtual void OnSetFont(CFont* pFont); protected: virtual void OnOK(); virtual void OnCancel(); // Implementation public: virtual ~CDialog(); virtual BOOL PreTranslateMessage(MSG* pMsg); virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo); virtual BOOL CheckAutoCenter();
10
protected: // parameters for 'DoModal' LPCTSTR m_lpszTemplateName; // name or MAKEINTRESOURCE HGLOBAL m_hDialogTemplate; // indirect (m_lpDialogTemplate == NULL) LPCDLGTEMPLATE m_lpDialogTemplate; void* m_lpDialogInit; // DLGINIT resource data CWnd* m_pParentWnd; // parent/owner window HWND m_hWndTop; // top level parent window (may be disabled) virtual void PreInitDialog(); // implementation helpers HWND PreModal(); void PostModal(); BOOL CreateIndirect(LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd, void* lpDialogInit, HINSTANCE hInst); BOOL CreateIndirect(HGLOBAL hDialogTemplate, CWnd* pParentWnd, HINSTANCE hInst); protected: DECLARE_MESSAGE_MAP() }; CDialog (cont’d)
11
Declaration(AFXWIN.H) 멤버 변수 m_nIDHelp m_nIDHelp Button 을 위한 help ID m_lpszTemplateName m_lpszTemplateName Resource template 의 이름 m_hDialogTemplate m_hDialogTemplate 일단 load 된 후의 resource template 의 handle m_lpDialogInit m_lpDialogInit 초기화에 관련된 data 에 대한 pointer CDialog (cont’d)
12
m_pParentWnd m_pParentWnd Parent window 에 대한 pointer m_hWndTop m_hWndTop Top-level parent window m_pOccDialogInfo m_pOccDialogInfo OLE controls 을 위한 stored information 멤버 함수 virtual PreTranslateMessage() virtual PreTranslateMessage() 특별한 message(tool tips, context-sensitive help) 에 대한 filtering CDialog (cont’d)
13
virtual OnCmdMsg() virtual OnCmdMsg() Command message 처리작업 virtual CheckAutoCenter() virtual CheckAutoCenter() Auto-center 옵션이 체크되었는지 확인 virtual SetOccDialogInfo() virtual SetOccDialogInfo() M_pOccDialogInfo 변수에 데이터를 setting virtual PreInitDialog() virtual PreInitDialog() WM_INITDIALOG message 이전에 불리워지는 함수 PreModal() PreModal() DoModal() 함수 실행을 위한 준비작업 PostModal() PostModal() DoModal() 함수가 끝난후의 뒤처리 CDialog (cont’d)
14
일반적으로 두가지의 과정을 거침 CDialog construction DoModal() 함수의 호출 CDialog construction DLGCORE.CPP 에 있음 두가지 버전이 있으며 CDialog class 의 필요한 변수에 값을 입력하는 역할을 함 Modal Dialog Creation
15
Modal Dialog Creation (cont’d) “ DlgCore.cpp ” CDialog::CDialog(LPCTSTR lpszTemplateName, CWnd* pParentWnd) { m_pParentWnd = pParentWnd; m_lpszTemplateName = lpszTemplateName; if (HIWORD(m_lpszTemplateName) == 0) m_nIDHelp = LOWORD((DWORD)m_lpszTemplateName); } CDialog::CDialog(UINT nIDTemplate, CWnd* pParentWnd) { m_pParentWnd = pParentWnd; m_lpszTemplateName = MAKEINTRESOURCE(nIDTemplate); m_nIDHelp = nIDTemplate; }
16
Modal Dialog Creation (cont’d) int CDialog::DoModal() { // STEP 1 : load resource as necessary LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate; HGLOBAL hDialogTemplate = m_hDialogTemplate; HINSTANCE hInst = AfxGetResourceHandle(); if (m_lpszTemplateName != NULL) { hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG); HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG); hDialogTemplate = LoadResource(hInst, hResource); } if (hDialogTemplate != NULL) lpDialogTemplate = (LPCDLGTEMPLATE)LockResource (hDialogTemplate); // return -1 in case of failure to load the dialog template resource if (lpDialogTemplate == NULL) return -1;
17
Modal Dialog Creation (cont’d) // STEP 2 : Preparing to create the dialog HWND hWndParent = PreModal(); AfxUnhookWindowCreate(); BOOL bEnableParent = FALSE; if (hWndParent != NULL && ::IsWindowEnabled(hWndParent)){ ::EnableWindow(hWndParent, FALSE); bEnableParent = TRUE; } // STEP 3 : create modeless dialog AfxHookWindowCreate(this); if (CreateDlgIndirect(lpDialogTemplate, CWnd::FromHandle(hWndParent), hInst)) { if (m_nFlags & WF_CONTINUEMODAL) { // enter modal loop DWORD dwFlags = MLF_SHOWONIDLE; if (GetStyle() & DS_NOIDLEMSG) dwFlags |= MLF_NOIDLEMSG; VERIFY(RunModalLoop(dwFlags) == m_nModalResult); }
18
Modal Dialog Creation (cont’d) // hide the window before enabling the parent, etc. if (m_hWnd != NULL) SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW| SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER); } if (bEnableParent) ::EnableWindow(hWndParent, TRUE); if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd) ::SetActiveWindow(hWndParent); // STEP 4 : destroy modal window DestroyWindow(); PostModal(); }
19
Modal Dialog Creation (cont’d) HWND CDialog::PreModal() { // cannot call DoModal on a dialog already constructed as modeless ASSERT(m_hWnd == NULL); // allow OLE servers to disable themselves CWinApp* pApp = AfxGetApp(); if (pApp != NULL) pApp->EnableModeless(FALSE); // find parent HWND HWND hWnd = CWnd::GetSafeOwner_ (m_pParentWnd->GetSafeHwnd(), &m_hWndTop); // hook for creation of dialog AfxHookWindowCreate(this); // return window to use as parent for dialog return hWnd; }
20
Modal Dialog Creation (cont’d) int CWnd::RunModalLoop(DWORD dwFlags) { BOOL bIdle = TRUE; LONG lIdleCount = 0; BOOL bShowIdle = (dwFlags & MLF_SHOWONIDLE) && !(GetStyle() & WS_VISIBLE); HWND hWndParent = ::GetParent(m_hWnd); // acquire and dispatch messages until the modal state is done for (;;) { // phase1: check to see if we can do idle work while(bIdle&&!::PeekMessage(pMsg,NULL,NULL,NULL,PM_NOREMOVE)) { } // phase2: pump messages while available do { // pump message, but quit on WM_QUIT !AfxGetThread()->PumpMessage(); } while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)); }
21
DoModal()(DLGCORE.CPP) Dialog resource 의 loading Dialog template name 을 가지고 dialog template 을 찾아서 load 함 Dialog template name 을 가지고 dialog template 을 찾아서 load 함 Dialog 를 생성하기 위한 준비 PreModal() 함수를 호출함 PreModal() 함수를 호출함 Safety checks Parent window handle 을 찾음 Parent window handle 을 찾음 m_hWndTop 에 저장 EnableWindow(FALSE) 를 호출 EnableWindow(FALSE) 를 호출 Parent window 를 disable 시킴 Modal Dialog Creation (cont’d)
22
Dialog 를 생성하고 보여줌 CWnd::CreateDlgIndirect() 함수 호출 CWnd::CreateDlgIndirect() 함수 호출 내부적으로 Win32API 인 CreateDialogIndirect() 를 호출 내부적으로 Win32API 인 CreateDialogIndirect() 를 호출 CWnd::RunModalLoop() 함수 호출 CWnd::RunModalLoop() 함수 호출 Dialog 가 끝날때 까지 일을 수행 Dialog 가 끝날때 까지 일을 수행 사용자가 ok 나 cancel 버튼을 누르면 CWnd::EndModalLoop() 함수가 호출됨 사용자가 ok 나 cancel 버튼을 누르면 CWnd::EndModalLoop() 함수가 호출됨 Dialog 를 화면에서 보이지 않게 함 Dialog 를 화면에서 보이지 않게 함 Dialog 가 종료하면 EnableWindow(TRUE) 를 호출 Dialog 가 종료하면 EnableWindow(TRUE) 를 호출 Parent window 를 enable 시킴 Parent window 를 enable 시킴 마지막 단계 DestroyWindow() 함수 호출 DestroyWindow() 함수 호출 PostModal() 함수 호출 PostModal() 함수 호출 Modal Dialog Creation (cont’d)
23
Modeless dialog creation 두가지 과정을 거침 New operator 를 사용하여 변수 생성 New operator 를 사용하여 변수 생성 CDialog::Create() 함수 호출 CDialog::Create() 함수 호출 Modeless Dialog Creation
24
Modeless Dialog Creation (cont’d) BOOL CDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd) { m_lpszTemplateName = lpszTemplateName; // used for help if (HIWORD(m_lpszTemplateName) == 0 && m_nIDHelp == 0) m_nIDHelp = LOWORD((DWORD)m_lpszTemplateName); if (!_AfxCheckDialogTemplate(lpszTemplateName, FALSE)) { PostNcDestroy(); // cleanup if Create fails too soon return FALSE; } HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG); HRSRC hResource = ::FindResource(hInst, lpszTemplateName, RT_DIALOG); HGLOBAL hTemplate = LoadResource(hInst, hResource); BOOL bResult = CreateIndirect(hTemplate, pParentWnd, hInst); FreeResource(hTemplate); return bResult; }
25
Modeless Dialog Creation (cont’d) BOOL CDialog::CreateIndirect (LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd, void* lpDialogInit, HINSTANCE hInst) { ASSERT(lpDialogTemplate != NULL); if (pParentWnd == NULL) pParentWnd = AfxGetMainWnd(); m_lpDialogInit = lpDialogInit; return CreateDlgIndirect(lpDialogTemplate, pParentWnd, hInst); }
26
CDialog::Create()(DLGCORE.CPP) Template name 과 help ID 를 내부 변수에 저장 Dialog resource 를 찾고 load 함 CDialog::CreateIndirect() 함수 호출 내부적으로 Win32 API 인 CreateDialogIndirect() 함수 호출 내부적으로 Win32 API 인 CreateDialogIndirect() 함수 호출 사용자가 ok 나 cancel 버튼을 누르면 EndDialog() 가 호출되어 dialog 가 사라짐 Modeless Dialog Creation (cont’d)
27
Dialog Terminator void CDialog::EndDialog(int nResult) { ASSERT(::IsWindow(m_hWnd)); if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL)) EndModalLoop(nResult); ::EndDialog(m_hWnd, nResult); }
28
CDialog Control Initialization Dialog 에 있는 control 의 초기화 작업 Resource 에 의한 초기화 Combo box 를 예로 살펴봄 Data 는 “one”, “two”, “three” 라 가정 Data 는 “one”, “two”, “three” 라 가정 다음과 같은 코드가 생성되지 않는다. m_pCombo->AddString( “ one ” ); m_pCombo->AddString( “ two ” ); m_pCombo->AddString( “ three ” );
29
WM_INITDIALOG Dialog 가 화면에 보이기 전에 발생하는 message Application 으로 하여금 dialog 에 있는 control 들을 초기화 할 수 있도록 함 CDialog::HandleInitDialog() 함수에 mapping 되어 있음 CDialog::HandleInitDialog() OLE control 관련 초기화 작업을 하고 CDialog::OnInitDialog() 를 호출 CDialog::OnInitDialog() CWnd::ExecuteDlgInit() 를 호출 CDialog Control Initialization (cont’d)
30
Resource file CDialog Control Initialization (cont’d) IDD_ABOUTBOX DLGINIT BEGIN IDC_COMBO1, 0x403, 4, 0 0x6e6f, 0x0065, IDC_COMBO1, 0x403, 4, 0 0x7774, 0x006f, IDC_COMBO1, 0x403, 6, 0 0x6874, 0x6572, 0x0065, 0 END
31
CWnd::ExecuteDlgInit()(WINCORE.CPP) 두가지 버전이 존재 Argument 로 dialog template name Argument 로 dialog template name Argument 로 dialog data 에 대한 pointer Argument 로 dialog data 에 대한 pointer 일단 첫번째 버전의 함수가 dialog template name 을 가지고 resource 파일에서 control 의 data 를 load 함 이 후 pointer 를 얻어서 두번째 버전의 함수를 호출 why CWnd class member function? CDialog Control Initialization (cont’d)
32
CWnd::ExecuteDlgInit(LPVOID) CWnd::ExecuteDlgInit(LPVOID) Resource file 의 raw data(DLGINIT) 를 parsing 함 BOOL CWnd::ExecuteDlgInit(LPVOID lpResource) { BOOL bSuccess = TRUE; UNALIGNED WORD* lpnRes = (WORD*)lpResource; while(bSuccess && *lpnRes != 0) { WORD nIDC = *lpnRes++; WORD nMsg = *lpnRes++; DWORD dwLen = *((UNALIGNED DWORD*&)lpnRes)++; if (nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING) { if (::SendDlgItemMessageA(m_hWnd, nIDC, nMsg, 0, (LONG)lpnRes) == -1) bSuccess = FALSE; } return bSuccess; } CDialog Control Initialization (cont’d)
33
DDX/DDV DDX/DDV DDX(Dynamic Data eXchange) DDV(Dynamic Data Validation) Data members Controls 활용 사례 void CMyDlg::DoDataExchange(CDataExchange * pDX) { CDialog::DoDataExchange(pDX); DDX_Text(pDX, IDC_EDIT1, m_strEdit1); DDV_MaxChars(pDX, IDC_EDIT1, 20); DDX_Text(pDX, IDC_EDIT2, m_uEdit2); DDV_MinMaxChars(pDX, IDC_EDIT2, 1, 234); DDX_Check(pDX, IDC_CHECK, m_bCheckState); DDX_Radio(pDX, IDC_RADIO, m_nRadioState); }
34
DDX/DDV (cont’d) Question CDataExchange class 의 역할 Control 들과 멤버 변수들간의 정보 교환은 언제, 어디에서, 어떻게 이루어지는가 DDX/DDV 함수는 무슨 일들을 하는가
35
DDX/DDV (cont’d) Helper class CDataExchange(AFXWIN.H) class CDataExchange { // Attributes public: BOOL m_bSaveAndValidate; // TRUE => save and validate data CWnd* m_pDlgWnd; // container usually a dialog // Operations (for implementors of DDX and DDV procs) HWND PrepareCtrl(int nIDC); // return HWND of control HWND PrepareEditCtrl(int nIDC); // return HWND of control void Fail(); // will throw exception CWnd* PrepareOleCtrl(int nIDC); // for OLE controls in dialog // Implementation CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate); HWND m_hWndLastControl; // last control used (for validation) BOOL m_bEditLastControl; // last control was an edit item };
36
DDX/DDV (cont’d) 멤버 변수 m_bSaveAndValidate TRUE data 가 control 에서 변수로 감 TRUE data 가 control 에서 변수로 감 FALSE data 가 변수에서 control 로 감 FALSE data 가 변수에서 control 로 감 Validation 은 TRUE 일때만 일어남 Validation 은 TRUE 일때만 일어남 m_pDlgWnd Dialog 에 대한 CWnd pointer Dialog 에 대한 CWnd pointer m_hWndLastControl Previous control 에 대한 handle 을 저장 Previous control 에 대한 handle 을 저장 m_bEditLastControl Previous control 이 수정되었는지를 저장 Previous control 이 수정되었는지를 저장
37
멤버 함수 Constructor PrepareCtrl() Non-edit control 을 위한 준비 Non-edit control 을 위한 준비 PrepareEditCtrl() Edit control 을 위한 준비 Edit control 을 위한 준비 Fail() Validation 이 실패하면 호출됨 Validation 이 실패하면 호출됨 Focus 를 previous control 로 보내고 CUserException 예외를 발생시킴 Focus 를 previous control 로 보내고 CUserException 예외를 발생시킴 PrepareOleCtrl() OLE control 을 위한 준비 OLE control 을 위한 준비 DDX/DDV (cont’d)
38
특징 DDX/DDV 는 Serialize 과정과 유사 CDataExchange 는 CArchive 와 비슷 DoDataExchange() 는 Serialize() 와 비슷 Save/load tag 를 가짐 DDX/DDV (cont’d)
39
DDX/DDV 함수들 DDX_Text()(DLGDATA.CPP) m_bSaveAndValidate 의 값을 기준으로 data 이동 m_bSaveAndValidate 의 값을 기준으로 data 이동 DDV_MaxChars()(DLGDATA.CPP) m_bSaveAndValidate 값이 TRUE 인경우 validation 코드 수행 m_bSaveAndValidate 값이 TRUE 인경우 validation 코드 수행 DDX_TextWithFormat()(DLGDATA.CPP) String 과 int 사이의 conversion String 과 int 사이의 conversion DDX/DDV (cont’d)
40
void AFXAPI DDX_Text(CDataExchange* pDX, int nIDC, CString& value) { HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC); if (pDX->m_bSaveAndValidate) { int nLen = ::GetWindowTextLength(hWndCtrl); ::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1); value.ReleaseBuffer(); } else { AfxSetWindowText(hWndCtrl, value); }
41
DDX/DDV (cont’d) void AFXAPI DDV_MaxChars(CDataExchange* pDX, CString const& value, int nChars) { ASSERT(nChars >= 1); // allow them something if (pDX->m_bSaveAndValidate && value.GetLength() > nChars) { TCHAR szT[32]; wsprintf(szT, _T("%d"), nChars); CString prompt; AfxFormatString1(prompt, AFX_IDP_PARSE_STRING_SIZE, szT); AfxMessageBox(prompt, MB_ICONEXCLAMATION, AFX_IDP_PARSE_STRING_SIZE); prompt.Empty(); // exception prep pDX->Fail(); } else if (pDX->m_hWndLastControl != NULL && pDX->m_bEditLastControl) { // limit the control max-chars automatically ::SendMessage(pDX->m_hWndLastControl, EM_LIMITTEXT, nChars, 0); }
42
언제 DoDataExchange() 가 호출되는가 ? 필요할 때 마다 UpdateData() 함수 호출 위 함수 내부에서 DoDataExchange() 를 호출함 UpdateData()(WINCORE.CPP) DDX/DDV (cont’d)
43
BOOL CWnd::UpdateData(BOOL bSaveAndValidate) { CDataExchange dx(this, bSaveAndValidate); _AFX_THREAD_STATE* pThreadState = AfxGetThreadState(); HWND hWndOldLockout = pThreadState->m_hLockoutNotifyWindow; ASSERT(hWndOldLockout != m_hWnd); // must not recurse pThreadState->m_hLockoutNotifyWindow = m_hWnd; BOOL bOK = FALSE; // assume failure TRY { DoDataExchange(&dx); bOK = TRUE; // it worked } CATCH(CUserException, e) { // validation failed - user already alerted, fall through ASSERT(!bOK); }
44
DDX/DDV (cont’d) void CDialog::OnOK() { if (!UpdateData(TRUE)){ TRACE0("UpdateData failed during dialog termination.\n"); // the UpdateData routine will set focus to correct item return; } EndDialog(IDOK); } BOOL CDialog::OnInitDialog() { BOOL bDlgInit; if (m_lpDialogInit != NULL) bDlgInit = ExecuteDlgInit(m_lpDialogInit); else bDlgInit = ExecuteDlgInit(m_lpszTemplateName); UpdateData(FALSE); return TRUE; // set focus to first one }
45
Common Dialogs Common Dialogs 표준 interface 제공을 위하여 종류 CColorDialog CColorDialog CFileDialog CFileDialog CFindReplaceDialog CFindReplaceDialog CFontDialog CFontDialog CPrintDialog CPrintDialog CPageSetupDialog ( MFC 4.0 ) CPageSetupDialog ( MFC 4.0 )
46
Steps 생성자 호출 DoModal() 호출 IDOK 가 리턴될 때 적절한 처리 Common Dialogs (cont’d) CFileDialog myDialog(TRUE, NULL, NULL, OFN_FILEMUSTEXIST); if ( myDialog.DoModal() == IDOK ) { Cstring strPath = myDialog.GetPathName(); CString strFile = myDialog.GetFileName(); } else // User selected Cancel …
47
Win32 API 관점에서 모든 common dialog 는 대응되는 structure 를 가지고 있다. 대응되는 structure 를 가지고 있다. 대응되는 API 를 가지고 있다. 대응되는 API 를 가지고 있다. 예 ) Open File common dialog 예 ) Open File common dialog Structure – OPENFILENAME API – GetOpenFileName(LP OPENFILENAME) 모든 common dialog 의 base class CCommonDialog(AFXDLGS.H) OnOK() 와 OnCancel() 추가 Common Dialogs (cont’d)
48
예제 dialog CFileDialog(AFXDLGS.H) Common Dialogs (cont’d) class CFileDialog : public CCommonDialog { public: OPENFILENAME m_ofn; // open file parameter block virtual int DoModal(); CString GetPathName() const; // return full path and filename CString GetFileName() const; // return only filename CString GetFileExt() const; // return only ext CString GetFileTitle() const; // return file title BOOL GetReadOnlyPref() const; // return TRUE if readonly checked // Enumerating multiple file selections POSITION GetStartPosition() const; CString GetNextPathName(POSITION& pos) const;
49
Common Dialogs (cont’d) protected: friend UINT CALLBACK _AfxCommDlgProc(HWND, UINT, WPARAM, LPARAM); virtual UINT OnShareViolation(LPCTSTR lpszPathName); virtual BOOL OnFileNameOK(); virtual void OnLBSelChangedNotify(UINT nIDBox, UINT iCurSel, UINT nCode); // only called back if OFN_EXPLORER is set virtual void OnInitDone(); virtual void OnFileNameChange(); virtual void OnFolderChange(); virtual void OnTypeChange(); // Implementation BOOL m_bOpenFileDialog; // TRUE for file open, FALSE for file save CString m_strFilter; // filter string TCHAR m_szFileTitle[64]; // contains file title after return TCHAR m_szFileName[_MAX_PATH]; // contains full path name after return OPENFILENAME* m_pofnTemp; virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult); };
50
예제 dialog CFileDialog(AFXDLGS.H) OPENFILENAME structure OPENFILENAME structure 여러 개의 virtual protected 함수 여러 개의 virtual protected 함수 기타 여러 정보 저장을 위한 변수 기타 여러 정보 저장을 위한 변수 CFileDialog 의 생성 (DLGFILE.CPP) 생성자의 argument 들을 OPENFILENAME structure 의 멤버에 setting 함 (m_ofn) 생성자의 argument 들을 OPENFILENAME structure 의 멤버에 setting 함 (m_ofn) Window95 이상일 경우에는 OFN_EXPLORER 와 OFN_ENABLEHOOK flag 를 set 함 Window95 이상일 경우에는 OFN_EXPLORER 와 OFN_ENABLEHOOK flag 를 set 함 OFN_ENABLEHOOK Hook routine 을 제공 (_AfxCommDlgProc() 를 m_ofn 의 hook field 에 set) Common Dialogs (cont’d)
51
CFileDialog::DoModal()(DLGFILE.CPP) M_bOpenFileDialog 변수의 값을 보고 Win32 API 인 GetOpenFileName() 을 호출할건지 GetSaveFileName() 을 호출할건지를 결정 M_bOpenFileDialog 변수의 값을 보고 Win32 API 인 GetOpenFileName() 을 호출할건지 GetSaveFileName() 을 호출할건지를 결정 Common Dialogs (cont’d)
52
int CFileDialog::DoModal() { int nResult; BOOL bEnableParent = FALSE; m_ofn.hwndOwner = PreModal(); AfxUnhookWindowCreate(); if (m_ofn.hwndOwner != NULL && ::IsWindowEnabled(m_ofn.hwndOwner)) { bEnableParent = TRUE; ::EnableWindow(m_ofn.hwndOwner, FALSE); } if (m_bOpenFileDialog) nResult = ::GetOpenFileName(&m_ofn); else nResult = ::GetSaveFileName(&m_ofn); if (bEnableParent) ::EnableWindow(m_ofn.hwndOwner, TRUE); PostModal(); return nResult ? nResult : IDCANCEL; }
53
Property Sheets Tabbed dialogs MFC 3.0 때부터 제공 하나의 dialog 에서 사용자로부터 많은 입력을 받을 수 있는 인터페이스
54
Property Sheets (cont’d) 두개의 class CPropertySheet Tabbed dialog 를 위한 class Tabbed dialog 를 위한 class CPropertyPage Tabbed dialog 의 각각의 tab(page) 을 위한 class Tabbed dialog 의 각각의 tab(page) 을 위한 class 일반 dialog 와의 차이점 Apply 버튼 제공 Page 별로 update 하는 기능을 제공 Page 별로 update 하는 기능을 제공
55
Property Sheets (cont’d) STEP 1. Dialog template 생성 및 property sheet 의 layout 설정 2. 각 template 에 대응하는 CPropertyPage 파생 클래스들을 생성 3-1. (modal property sheet) CPropertySheet 의 instance 를 생성하고 AddPage() 멤버 함수를 통해 추가한 뒤 DoModal() 호출 CPropertySheet 의 instance 를 생성하고 AddPage() 멤버 함수를 통해 추가한 뒤 DoModal() 호출 OK/Apply/Cancel 버튼이 자동적으로 추가 OK/Apply/Cancel 버튼이 자동적으로 추가 3-2. (modeless property sheet) CPropertySheet 의 파생클래스 생성한 뒤 인스턴스를 생성하고 Create() 함수 호출 CPropertySheet 의 파생클래스 생성한 뒤 인스턴스를 생성하고 Create() 함수 호출 OK/Apply/Cancel 버튼이 자동적으로 추가되지 않음 OK/Apply/Cancel 버튼이 자동적으로 추가되지 않음
56
Property Sheets (cont’d) CPropertySheet mySheet( “ My Property Sheet! ”, this); CPageOne myPage1; CPageTwo myPage2; CPageThree myPage3; mySheet.AddPage(&myPage1); mySheet.AddPage(&myPage2); mySheet.AddPage(&myPage3); mySheet.DoModal(); …
57
CPropertySheet Class Declaration of CPropertySheet AFXDLGS.H class CPropertySheet : public CWnd { // Attributes public: AFX_OLDPROPSHEETHEADER m_psh; int GetPageCount() const; CPropertyPage* GetActivePage() const; int GetActiveIndex() const; CPropertyPage* GetPage(int nPage) const; int GetPageIndex(CPropertyPage* pPage); BOOL SetActivePage(int nPage); BOOL SetActivePage(CPropertyPage* pPage); void SetTitle(LPCTSTR lpszText, UINT nStyle = 0); void EnableStackedTabs(BOOL bStacked);
58
CPropertySheet Class (cont’d) // Operations public: virtual int DoModal(); void AddPage(CPropertyPage* pPage); void RemovePage(CPropertyPage* pPage); void RemovePage(int nPage); void EndDialog(int nEndID); // used to terminate a modal dialog BOOL PressButton(int nButton); // Implementation public: virtual ~CPropertySheet(); void CommonConstruct(CWnd* pParentWnd, UINT iSelectPage); virtual BOOL PreTranslateMessage(MSG* pMsg); virtual void BuildPropPageArray(); virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); virtual BOOL OnInitDialog(); virtual BOOL ContinueModal();
59
CPropertySheet Class (cont’d) protected: CPtrArray m_pages; // array of CPropertyPage pointers CString m_strCaption; // caption of the pseudo-dialog CWnd* m_pParentWnd; // parent window of property sheet BOOL m_bStacked; // EnableStackedTabs sets this BOOL m_bModeless; // TRUE when Create called instead of DoModal // Generated message map functions //{{AFX_MSG(CPropertySheet) afx_msg BOOL OnNcCreate(LPCREATESTRUCT); afx_msg LRESULT HandleInitDialog(WPARAM, LPARAM); afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); afx_msg LRESULT OnCommandHelp(WPARAM, LPARAM); afx_msg void OnClose(); afx_msg void OnSysCommand(UINT nID, LPARAM); afx_msg LRESULT OnSetDefID(WPARAM, LPARAM); //}}AFX_MSG friend class CPropertyPage; };
60
Declaration of CPropertySheet AFXDLGS.H CWnd 에서 상속받음 (why?) 멤버 CommonConstruct() CommonConstruct() 수많은 constructor 들이 호출하는 공통 함수 m_pages m_pages CPtrArray 형의 pointer 로 CPropertyPage class 의 pointer 의 배열 CPropertySheet Class (cont’d)
61
m_strCaption m_strCaption Property sheet 의 caption m_pParentWnd m_pParentWnd Parent window 에 대한 pointer m_bStacked m_bStacked Tab 을 stacked mode 로 할건지 scrolled mode 로 할 건지를 결정 m_bModeless m_bModeless Property sheet 를 modal 로 할건지 modeless 로 할건지 CPropertySheet Class (cont’d)
62
CPropertySheet::DoModal() DLGPROP.CPP 내부 수행 AfxDeferRegisterClass() 호출 AfxDeferRegisterClass() 호출 내부적으로 InitCommonControls() 함수 호출 (Windows common controls DLL 을 초기화 ) BuildPropPageArray() 호출 BuildPropPageArray() 호출 Main window 를 disable 하고 ::PropertySheet() 함수를 호출 ( 이후는 CDialog::DoModal() 과 동일 ) Main window 를 disable 하고 ::PropertySheet() 함수를 호출 ( 이후는 CDialog::DoModal() 과 동일 ) CPropertySheet Class (cont’d)
63
CPropertySheet::AddPage() DLGPROP.CPP m_pages 멤버 변수에 page 추가 CPropertySheet::BuildPropPageArray() DLGPROP.CPP 각 page 에 있는 PROPSHEETPAGE structure 정보를 저장함 CPropertySheet Class (cont’d)
64
int CPropertySheet::DoModal() { VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG)); BuildPropPageArray(); HWND hWndParent = CWnd::GetSafeOwner_(); ::EnableWindow(hWndParent, FALSE); HWND hWnd = (HWND)::PropertySheet((PROPSHEETHEADER*)psh); nResult = RunModalLoop(dwFlags); DestroyWindow(); ::EnableWindow(hWndTop, TRUE); return nResult; }
65
CPropertySheet Class (cont’d) void CPropertySheet::AddPage(CPropertyPage* pPage) { m_pages.Add(pPage); if (m_hWnd != NULL){ HPROPSHEETPAGE hPSP = CreatePropertySheetPage((PROPSHEETPAGE*)ppsp); if (hPSP == NULL) AfxThrowMemoryException(); if (!SendMessage(PSM_ADDPAGE, 0, (LPARAM)hPSP)) { DestroyPropertySheetPage(hPSP); AfxThrowMemoryException(); }
66
CPropertySheet Class (cont’d) void CPropertySheet::BuildPropPageArray() { delete[] (PROPSHEETPAGE*)m_psh.ppsp; m_psh.ppsp = NULL; AFX_OLDPROPSHEETPAGE* ppsp = new AFX_OLDPROPSHEETPAGE[m_pages.GetSize()]; m_psh.ppsp = (LPPROPSHEETPAGE)ppsp; for (int i = 0; i < m_pages.GetSize(); i++){ CPropertyPage* pPage = GetPage(i); memcpy(&ppsp[i], &pPage->m_psp, sizeof(pPage->m_psp)); pPage->PreProcessPageTemplate ((PROPSHEETPAGE&)ppsp[i], bWizard); } m_psh.nPages = m_pages.GetSize(); }
67
Control Classes Control class 의 세가지 group Old fashioned (6) Button, combo box, edit, list box, scroll bar, static Button, combo box, edit, list box, scroll bar, static New fangled Window common controls Window common controls OLE controls
68
Old-Fashioned 특징 모두 CWnd 에서 상속받음 Cbitmap, CBitmapButton, CComboBox, CEdit, CListBox, CDragListBox, CCheckListBox, CScrollBar, CStatic Declaration 은 AFXWIN.H Implementation AFXWIN2.INL AFXWIN2.INL WINCTRL1.CPP WINCTRL1.CPP WINCTRL2.CPP WINCTRL2.CPP WINCTRL3.CPP WINCTRL3.CPP WINBTN.CPP WINBTN.CPP
69
Old-Fashioned (cont’d) Cbutton* pButton = (Cbutton *)pDialog->GetDlgItem(IDC_CHECK1); ASSERT(pButton != NULL); pButton->SetCheck(m_bShowState); //// Crect rectButton(10, 10, 50, 50); Cbutton* pButton = new Cbutton; pButton->Create( “ Text ”, WS_CHILD|BS_PUSHBUTTON, rectButton, pView, ID_BUTTON); … pBtton->DestroyWindow(); delete pButton;
70
New-fangled 특징 모두 CWnd 에서 상속받음 CAnimateCtrl, CDragListBox, CHotKeyCtrl, CImageList, CProgressCtrl, CRichEditCtrl, CSliderCtrl, CSpinButtonCtrl, … Declaration 은 AFXCMN.H Implementation AFXCMN.INL AFXCMN.INL WINCTRL2.CPP WINCTRL2.CPP WINCTRL4.CPP WINCTRL4.CPP
71
Chap. 7 Document/View Architecture
72
Contents Introduction Architecture Inside document/view architecture Document/view internals
73
Introduction Application 의 data 관리 Data 를 분리하여 관리하자. 중요한 이슈 누가 data 를 관리할 것인가 누가 data 를 관리할 것인가 누가 data 를 update 할 것인가 누가 data 를 update 할 것인가 data 의 rendering 어떻게 다르게 할 것인가 data 의 rendering 어떻게 다르게 할 것인가 … Print 와 print preview 의 지원 두 부분 Data management Data management User-interface management User-interface management
74
Introduction (cont’d) 기존의 방법 분리하지 않고 하나의 클래스에서 처리 대단히 복잡 중요성 Multiple ways to represent your data Rendering & Updating Rendering & Updating Multiple types of data User interface User interface
75
Architecture Document 와 view Document Application 의 data 를 의미 Application 의 data 를 의미 View Application 의 data 의 표현을 의미 Application 의 data 의 표현을 의미
76
Document/View Components MFC document/view architecture 를 위한 4 개의 components Documents Views Document/view frames Document templates
77
Documents CDocument class Managing file I/O Managing file I/O Updating renderings of the data Updating renderings of the data CCmdTarget(CObject) 로 부터 상속 받음 CCmdTarget(CObject) 로 부터 상속 받음 CObject Run-time type information, dynamic creation, serialization CCmdTarget Command message (WM_COMMAND) 를 받을 수 있음 Document/View Components (cont’d)
78
Views CView class CWnd(CCmdTarget, CObject) 로 부터 상속 받음 CWnd(CCmdTarget, CObject) 로 부터 상속 받음 CCmdTarget Command message (WM_COMMAND) 를 받을 수 있음 CWnd Window message(WM_PAINT) 를 받을 수 있음 View 는 border 가 없는 window 임 View 는 border 가 없는 window 임 View 를 둘러싸고 있는 border 있는 window 를 frame window 라고 함 View 를 둘러싸고 있는 border 있는 window 를 frame window 라고 함 Document/View Components (cont’d)
79
Document/View Frames 각각의 view 에 서로 다른 user-interface 를 적용할 수 있게 함 View Frame Document/View Components (cont’d)
80
SDI CFrameWnd class Single Document Interface Single Document Interface 워드패드 워드패드 MDI CMDIChildWnd class Multiple Document Inteface Multiple Document Inteface MS Word MS Word Document/View Components (cont’d)
81
Document templates CDocTemplate class Document, view, frame 을 묶어서 하나의 unit 으로 관리 각각의 서로 다른 document type 에 대하여 하나씩의 template 을 가질 수 있다. 실제 사용시 한 type 의 document CSingleDocTemplate class 한 type 의 document CSingleDocTemplate class 여러 type 의 document CMultiDocTemplate class 여러 type 의 document CMultiDocTemplate class Document/View Components (cont’d)
82
CSingleDocTemplate 생성자의 인자 Resource ID Resource ID Documet/View/Frame 의 Run-time class Documet/View/Frame 의 Run-time class CMultiDocTemplate CSingleDocTemplate 와 생성자의 인자가 동일 차이점 : linked list 를 통해 다수의 정보 유지 Document/View Components (cont’d)
83
Resource ID application 의 string table window title, document name 새 document 생성 시 description 파일 open 시 파일 type 에 대한 description file extension filter, … Document/View Components (cont’d)
84
CWinApp 의 역할 CWinApp 의 역할은 ? Document template 을 관리함 CWinApp::InitInstance() 함수 Document template 을 생성함 Document template 을 생성함 생성이 끝나면 CWinApp::AddDocTemplate() 호출 생성이 끝나면 CWinApp::AddDocTemplate() 호출 CWinApp 의 document template list 에 추가함
85
CWinApp 의 역할 (cont’d) BOOL CTestApp::InitInstance() { … CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_TESTTYPE, RUNTIME_CLASS(CTestDoc), RUNTIME_CLASS(CChildFrame), // custom MDI child frame RUNTIME_CLASS(CTestView)); AddDocTemplate(pDocTemplate); … }
86
Document/View Arch. Internals Document/View arch. 의 기본 CWinApp Document template 의 관리 Document template 의 관리 Document template Frames/Views/Documents 의 관리 Frames/Views/Documents 의 관리
87
CDocManager Class CDocManager CWinApp 와 CDocTemplate 사이의 interface 역할 CWinApp 가 필요한 document template 의 list 를 관리하는 역할 CWinApp 의 declaration(AFXWIN.H) CDocManager * m_pDocManager; CDocManager * m_pDocManager;
88
CDocManager Class(contd.) class CDocManager : public CObject { DECLARE_DYNAMIC(CDocManager) CDocManager(); virtual void AddDocTemplate(CDocTemplate* pTemplate); virtual POSITION GetFirstDocTemplatePosition() const; virtual CDocTemplate* GetNextDocTemplate(POSITION& pos) const; virtual void RegisterShellFileTypes(BOOL bCompat); void UnregisterShellFileTypes(); virtual CDocument* OpenDocumentFile(LPCTSTR lpszFileName); virtual BOOL SaveAllModified(); // save before exit virtual void CloseAllDocuments(BOOL bEndSession); virtual int GetOpenDocumentCount(); CPtrList m_templateList; int GetDocumentCount(); };
89
CDocManager Class(contd.) Declaration(AFXWIN.H) 멤버 변수 m_templateList m_templateList CPtrList type 실제 document template 의 list 멤버 함수 대부분의 함수가 m_templateList 에 대한 조작과 CWinApp 와의 interface 를 위해서 존재 대부분의 함수가 m_templateList 에 대한 조작과 CWinApp 와의 interface 를 위해서 존재
90
CDocManager Class(contd.) 대부분의 CWinApp 의 document template 관련 함수는 CDocManager 의 함수를 그대로 호출함 대부분의 CWinApp 의 document template 관련 함수는 CDocManager 의 함수를 그대로 호출함 CWinApp::AddDocTemplate() CWinApp::CloseAllDocument() CWinApp::DoPromptFileName() CWinApp::GetFirstDocTemplatePosition() CWinApp::GetNextDocTemplate() CWinApp::GetOpenDocumentCount() CWinApp::OnFileNew() CWinApp::OnFileOpen() …
91
CDocManager Class(contd.) void CWinApp::AddDocTemplate(CDocTemplate* pTemplate) { if (m_pDocManager == NULL) m_pDocManager = new CDocManager; m_pDocManager->AddDocTemplate(pTemplate); } void CWinApp::OnFileNew() { if (m_pDocManager != NULL) m_pDocManager->OnFileNew(); }
92
CDocManager Class(contd.) CDocManager::OnFileNew() 새로운 document template 을 생성하는 역할 하나 이상의 document template 가 있을때는 CNewTypeDlg dialog class 를 이용 (DOCMGR.CPP) 사용자가 document template 을 선택하게 함 사용자가 document template 을 선택하게 함 사용자에게 document template list 로 보여주는 좋은 예가 됨 사용자에게 document template list 로 보여주는 좋은 예가 됨
93
CDocManager Class(contd.) “ DocMgr.cpp ” void CDocManager::OnFileNew() { CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead(); if (m_templateList.GetCount() > 1) { CNewTypeDlg dlg(&m_templateList); int nID = dlg.DoModal(); if (nID == IDOK) pTemplate = dlg.m_pSelectedTemplate; else return; // none - cancel operation } pTemplate->OpenDocumentFile(NULL); }
94
CDocManager Class(contd.) class CNewTypeDlg : public CDialog { protected: CPtrList* m_pList; // actually a list of doc templates public: CDocTemplate* m_pSelectedTemplate; enum { IDD = AFX_IDD_NEWTYPEDLG }; CNewTypeDlg(CPtrList* pList) : CDialog(CNewTypeDlg::IDD) { m_pList = pList; m_pSelectedTemplate = NULL; } protected: BOOL OnInitDialog(); void OnOK(); }; CNewTypeDlg class DOCMGR.CPP
95
CDocManager Class(contd.) CNewTypeDlg resource AFXRES.RC
96
CDocManager Class(contd.) BOOL CNewTypeDlg::OnInitDialog() { CListBox* pListBox = (CListBox*)GetDlgItem(AFX_IDC_LISTBOX); POSITION pos = m_pList->GetHeadPosition(); while (pos != NULL){ CDocTemplate* pTemplate = (CDocTemplate*)m_pList->GetNext(pos); CString strTypeName; if (pTemplate->GetDocString(strTypeName, CDocTemplate::fileNewName) && !strTypeName.IsEmpty()) { int nIndex = pListBox->AddString(strTypeName); pListBox->SetItemDataPtr(nIndex, pTemplate); } return CDialog::OnInitDialog(); }
97
CDocTemplate class CDocTemplate Document/View/Frame 을 관리 Base class 실제 사용시에는 CSingleDocTemplate CSingleDocTemplate DOCSINGL.CPP CMultiDocTemplate CMultiDocTemplate DOCMULTI.CPP
98
CDocTemplate class(contd.) Declaration(AFXWIN.H) class CDocTemplate : public CCmdTarget { DECLARE_DYNAMIC(CDocTemplate) protected: CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass); // Attributes public: virtual POSITION GetFirstDocPosition() const = 0; virtual CDocument* GetNextDoc(POSITION& rPos) const = 0; virtual void AddDocument(CDocument* pDoc); // must override virtual void RemoveDocument(CDocument* pDoc); // must override virtual BOOL GetDocString(CString& rString, enum DocStringIndex index) const; // get one of the info strings CFrameWnd* CreateOleFrame(CWnd* pParentWnd, CDocument* pDoc, BOOL bCreateView); virtual CDocument* CreateNewDocument(); virtual CFrameWnd* CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther);
99
CDocTemplate class(contd.) virtual void InitialUpdateFrame(CFrameWnd* pFrame, CDocument* pDoc, BOOL bMakeVisible = TRUE); virtual BOOL SaveAllModified(); // for all documents virtual void CloseAllDocuments(BOOL bEndSession); virtual CDocument* OpenDocumentFile( LPCTSTR lpszPathName, BOOL bMakeVisible = TRUE) = 0; virtual void SetDefaultTitle(CDocument* pDocument) = 0; public: BOOL m_bAutoDelete; virtual ~CDocTemplate(); protected: UINT m_nIDResource; CRuntimeClass* m_pDocClass; // class for creating new documents CRuntimeClass* m_pFrameClass; // class for creating new frames CRuntimeClass* m_pViewClass; // class for creating new views CString m_strDocStrings; // '\n' separated names };
100
CDocTemplate class(contd.) Declaration(AFXWIN.H) 멤버 변수 m_nIDResource m_nIDResource Document template 에 대한 resource ID m_pDocClass m_pDocClass CDocument 에 대한 CRuntimeClass structure 의 pointer m_pFrameClass m_pFrameClass CFrameWnd 에 대한 CRuntimeClass structure 의 pointer
101
CDocTemplate class(contd.) m_pViewClass m_pViewClass CView 에 대한 CRuntimeClass structure 의 pointer m_strDocStrings m_strDocStrings Document template 의 string resource Implementation(DOCTEMPL.CPP) Document/View/Frame 을 생성하는 함수 CDocTemplate::CreateNewDocument() CDocTemplate::CreateNewDocument() CDocTemplate::CreateNewFrame() CDocTemplate::CreateNewFrame() View 에 관한 명시적인 함수는 없음 View 에 관한 명시적인 함수는 없음
102
CDocTemplate class(contd.) CDocument* CDocTemplate::CreateNewDocument() { CDocument* pDocument = (CDocument*)m_pDocClass->CreateObject(); AddDocument(pDocument); return pDocument; }
103
CDocTemplate class(contd.) CFrameWnd* CDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther) { CCreateContext context; context.m_pCurrentFrame = pOther; context.m_pCurrentDoc = pDoc; context.m_pNewViewClass = m_pViewClass; context.m_pNewDocTemplate = this; CFrameWnd* pFrame = (CFrameWnd*)m_pFrameClass->CreateObject(); pFrame->LoadFrame(m_nIDResource, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL, &context)) return pFrame; }
104
CDocTemplate class(contd.) CDocTemplate::CreateNewDocument() m_pDocClass->CreateObject() 를 이용해 document 생성 m_pDocClass->CreateObject() 를 이용해 document 생성 생성된 document 를 open 된 document list 에 추가 생성된 document 를 open 된 document list 에 추가 CDocTemplate::CreateNewFrame() CCreateContext 에 필요한 정보를 채움 CCreateContext 에 필요한 정보를 채움 m_pFrameClass->CreateObject() 를 이용해 frame 생성 m_pFrameClass->CreateObject() 를 이용해 frame 생성 Frame 에 필요한 resource 를 load Frame 에 필요한 resource 를 load
105
CDocTemplate class(contd.) CCreateContext structure Declaration(AFXEXT.H) Declaration(AFXEXT.H) struct CCreateContext // Creation information structure // All fields are optional and may be NULL { CRuntimeClass* m_pNewViewClass; CDocument* m_pCurrentDoc; // for creating MDI children (CMDIChildWnd::LoadFrame) CDocTemplate* m_pNewDocTemplate; // for sharing view/frame state from the original view/frame CView* m_pLastView; CFrameWnd* m_pCurrentFrame; // Implementation CCreateContext(); };
106
CDocTemplate class(contd.) CCreateContext structure Declaration(AFXEXT.H) Declaration(AFXEXT.H) m_pNewViewClass View 생성을 위한 CRuntimeClass pointer m_pCurrentDoc Current document m_pCurrentFrame Current frame m_pNewDocTemplate Multiple document 일 때 마지막 document 를 가리킴 m_pLastView Multiple view 일 때 마지막 view 를 가리킴
107
CDocTemplate class(contd.) Open 된 document 의 관리는 ? CSingleDocTemplate 와 CMultiDocTemplate 가 담당 CSingleDocTemplate CDocument* m_pOnlyDoc; CMultiDocTemplate CPtrList m_docList; int m_nUntitledCount; Untitled document 의 수를 저장함 (Untitled[X])
108
CDocTemplate class(contd.) CMultiDocTemplate::OpenDocumentFile() DOCMULTI.CPP DOCMULTI.CPP Document 와 frame 의 생성 Document 와 frame 의 생성 CFrameWnd::InitialUpdateFrame() 호출 CFrameWnd::InitialUpdateFrame() 호출
109
CDocTemplate class(contd.) “ DocMulti.cpp ” CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible) { CDocument* pDocument = CreateNewDocument(); CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL); if (lpszPathName == NULL){ // create a new document - with default document name SetDefaultTitle(pDocument); pDocument->OnNewDocument(); } else { // open an existing document CWaitCursor wait; pDocument->OnOpenDocument(lpszPathName); pDocument->SetPathName(lpszPathName); } return pDocument; }
110
CFrameWnd class CFrameWnd CView 의 생성 ! m_pViewActive 현재 atcive 한 view 에 대한 pointer 현재 atcive 한 view 에 대한 pointer CFrameWnd::GetActiveView() CFrameWnd::GetActiveView() CFrameWnd::SetActiveView() CFrameWnd::SetActiveView() InitialUpdateFrame() 함수 모든 view 의 OnInitialUpdate() 함수를 호출함 모든 view 의 OnInitialUpdate() 함수를 호출함
111
CFrameWnd class(contd.) Implementation(WINFRM.CPP) CFrameWnd::CreateView() 진정한 view 의 생성 진정한 view 의 생성 CWnd* CFrameWnd::CreateView(CCreateContext* pContext, UINT nID) { CWnd* pView = (CWnd*)pContext->m_pNewViewClass ->CreateObject(); if (pView == NULL) return NULL; if (!pView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(0,0,0,0), this, nID, pContext)) return NULL; // can't continue without a view return pView; }
112
CFrameWnd class(contd.) 그러면 CreateView() 는 어디서 호출되나 ? int CFrameWnd::OnCreate(LPCREATESTRUCT lpcs) { return OnCreateHelper(lpcs, pContext); } int CFrameWnd::OnCreateHelper(LPCREATESTRUCT lpcs, CCreateContext* pContext) { if (CWnd::OnCreate(lpcs) == -1) return -1; // create special children first OnCreateClient(lpcs, pContext); }
113
CFrameWnd class(contd.) BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext) { if (pContext != NULL && pContext->m_pNewViewClass != NULL) { CreateView(pContext, AFX_IDW_PANE_FIRST); }
114
CFrameWnd class(contd.) CreateNewFrame() 이 호출되면 Windows 가 WM_CREATE message 를 보냄 OnCreate() 함수의 호출 OnCreateHelper() 의 호출 OnCreateClient() 의 호출 CreateView() 의 호출 결국 CreateNewFrame() 의 호출 결과임
115
CFrameWnd class(contd.) CFrameWnd::InitialUpdateFrame() Frame 의 모든 view 를 update 함 void CFrameWnd::InitialUpdateFrame(CDocument* pDoc, BOOL bMakeVisible) { CView* pView = NULL; if (bMakeVisible) { SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE); ActivateFrame(nCmdShow); if (pView != NULL) pView->OnActivateView(TRUE, pView, pView); } // update frame counts and frame title (may already have been visible) if (pDoc != NULL) pDoc->UpdateFrameCounts(); OnUpdateFrameTitle(TRUE); }
116
CDocument Class CDocument Declaration(AFXWIN.H) class CDocument : public CCmdTarget { public: const CString& GetTitle() const; virtual void SetTitle(LPCTSTR lpszTitle); const CString& GetPathName() const; virtual void SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU = TRUE); virtual BOOL IsModified(); virtual void SetModifiedFlag(BOOL bModified = TRUE); virtual POSITION GetFirstViewPosition() const; virtual CView* GetNextView(POSITION& rPosition) const; void UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL); virtual void DeleteContents(); // delete doc items etc
117
CDocument Class (cont’d) // File helpers virtual BOOL OnNewDocument(); virtual BOOL OnOpenDocument(LPCTSTR lpszPathName); virtual CFile* GetFile(LPCTSTR lpszFileName, UINT nOpenFlags, … ); virtual void ReleaseFile(CFile* pFile, BOOL bAbort); protected: CString m_strTitle; CString m_strPathName; CDocTemplate* m_pDocTemplate; CPtrList m_viewList; // list of views BOOL m_bModified; // changed since last saved virtual BOOL DoSave(LPCTSTR lpszPathName, BOOL bReplace = TRUE); virtual BOOL DoFileSave(); virtual void UpdateFrameCounts(); void DisconnectViews(); void SendInitialUpdate(); friend class CDocTemplate; };
118
Implementation(DOCCORE.CPP) Key aspects Creating documents Saving documents Communicating with views CDocument Class (cont’d)
119
Creating Documents Empty document 일 경우 OnNewDocument() 함수 호출 OnNewDocument() 함수 호출 DeleteContents() 호출 Modified flag 를 FALSE 로 함 m_strPathName 이 NULL 인지 확인 File 로 부터 create 하는 경우 OnOpenDocument() 함수 호출 OnOpenDocument() 함수 호출 GetFile() 함수를 이용하여 file open DeleteContents() 함수 호출 Modified flag 를 TRUE 로 함 CArchive class 를 이용하여 serialization Modified flag 를 FALSE 로 함 CDocument Class (cont’d)
120
BOOL CDocument::OnNewDocument() { if (IsModified()) TRACE0("Warning: OnNewDocument replaces an unsaved document.\n"); DeleteContents(); m_strPathName.Empty(); // no path name yet SetModifiedFlag(FALSE); // make clean return TRUE; }
121
CDocument Class (cont’d) BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName) { CFileException fe; CFile* pFile = GetFile(lpszPathName, CFile::modeRead|CFile::shareDenyWrite, &fe); DeleteContents(); SetModifiedFlag(); // dirty during de-serialize CArchive loadArchive(pFile, CArchive::load | CArchive::bNoFlushOnDelete); loadArchive.m_pDocument = this; loadArchive.m_bForceFlat = FALSE; CWaitCursor wait; if (pFile->GetLength() != 0) Serialize(loadArchive); // load me loadArchive.Close(); ReleaseFile(pFile, FALSE); SetModifiedFlag(FALSE); // start off with unmodified return TRUE; }
122
CDocument Class (cont’d) Saving Documents OnSaveDocument() GetFile() 함수를 이용하여 file open GetFile() 함수를 이용하여 file open CArchive class 를 이용하여 serialization CArchive class 를 이용하여 serialization Modified flag 를 FALSE 로 함 Modified flag 를 FALSE 로 함
123
CDocument Class (cont’d) BOOL CDocument::OnSaveDocument(LPCTSTR lpszPathName) { CFileException fe; CFile* pFile = NULL; pFile = GetFile(lpszPathName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive, &fe); CArchive saveArchive(pFile, CArchive::store | CArchive::bNoFlushOnDelete); saveArchive.m_pDocument = this; saveArchive.m_bForceFlat = FALSE; CWaitCursor wait; Serialize(saveArchive); // save me saveArchive.Close(); ReleaseFile(pFile, FALSE); SetModifiedFlag(FALSE); // back to unmodified return TRUE; // success }
124
View 와의 통신 m_viewList 에 view 의 list 를 저장 통신이 필요한 경우 Destroy 시 Destroy 시 DisconnectViews() 함수를 호출하여 각 viwe 의 m_pDocument 가 NULL 이 되게 함 Frame 에 접근하고자 할 때 Frame 에 접근하고자 할 때 Cview::GetParentFrame() 함수 이용 View 들에게 document 의 변경을 알리고자 할 때 View 들에게 document 의 변경을 알리고자 할 때 UpdateAllViews() 함수 호출 CDocument Class (cont’d)
125
void CDocument::UpdateAllViews(CView* pSender, LPARAM lHint, CObject* pHint) // walk through all views { ASSERT(pSender == NULL || !m_viewList.IsEmpty()); // must have views if sent by one of them POSITION pos = GetFirstViewPosition(); while (pos != NULL) { CView* pView = GetNextView(pos); ASSERT_VALID(pView); if (pView != pSender) pView->OnUpdate(pSender, lHint, pHint); }
126
CView Class CView Declaration(AFXWIN.H) Implementation(VIEWCORE.CPP) void CView::OnPaint() { // standard paint routine CPaintDC dc(this); OnPrepareDC(&dc); OnDraw(&dc); }
127
Document/View Internals CWinApp::OnFileOpen() CWinApp::OnFileNew() CDocManager::OnFileOpen() CDocManager::OnFileNew() CDocTemplate::OpenDocumentFile() CDocTemplate::CreateNewDocument() CDocTemplate::CreateNewFrame() WM_CREATE
128
Document/View…(contd.) CFrameWnd::OnCreate() CFrameWnd::OnCreateHelper() CFrameWnd::OnCreateClient() CFrameWnd::CreateView() CMyDocument::OnOpenDocument() CMyDocument::OnNewDocument()
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.