128
Chapter 06 MFC Dialog 와 Control Class

Chapter 06 MFC Dialog 와 Control Class

  • Upload
    adie

  • View
    244

  • Download
    3

Embed Size (px)

DESCRIPTION

Chapter 06 MFC Dialog 와 Control Class. Contents. CDialog class Common Dialogs Property Sheets Control classes. CDialog Class. Dialog 의 종류 Modal dialog Close 될 때 까지 다른 부분을 사용할 수 없음 DoModal() 함수를 이용 예 : common dialog box Modeless dialog Close 되기 전에 다른 부분을 사용할 수 있음 Create() 함수를 이용 - PowerPoint PPT Presentation

Citation preview

Chapter 06MFC Dialog 와 Control Class

비트교육센터[2]

비트교육센터

ContentsCDialog classCommon DialogsProperty SheetsControl classes

비트교육센터[3]

비트교육센터

CDialog ClassDialog 의 종류

– Modal dialogClose 될 때 까지 다른 부분을 사용할 수 없음DoModal() 함수를 이용예 : common dialog box

– Modeless dialogClose 되기 전에 다른 부분을 사용할 수 있음Create() 함수를 이용DestroyWindow() 함수를 이용하여 명시적으로 종료함예 : find and replace dialog box

비트교육센터[4]

비트교육센터

CDialog Class (cont’d)History

– MFC 1.0 Modal dialog : CModalDialogModeless dialog : CDialog

– Current version Modal dialog : CDialogModeless 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 somethingm_pDlgMyDlgPtr->DestroyWindow();m_pDlgMyDlgPtr = NULL;

비트교육센터[6]

비트교육센터

Win32 APIsDialog 생성을 위한 Win32 APIs

– CreateDialog()Modeless dialog 생성 , template resource 이용

– CreateDialogIndirect()Modeless dialog 생성 , template pointer 이용

Modal()/Modaless 를 만들때 모두 사용되는 함수

– DialogBox()Modal dialog 생성 , template resource 이용

– DialogBoxIndirect()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 constructpublic: 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);

// Operationspublic: // 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();// Implementationpublic: 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– Button 을 위한 help ID

m_lpszTemplateName– Resource template 의 이름

m_hDialogTemplate– 일단 load 된 후의 resource template 의 handle

m_lpDialogInit– 초기화에 관련된 data 에 대한 pointer

CDialog (cont’d)

비트교육센터[12]

비트교육센터

m_pParentWnd– Parent window 에 대한 pointer

m_hWndTop– Top-level parent window

m_pOccDialogInfo– OLE controls 을 위한 stored information

– 멤버 함수virtual PreTranslateMessage()

– 특별한 message(tool tips, context-sensitive help) 에 대한 filtering

CDialog (cont’d)

비트교육센터[13]

비트교육센터

virtual OnCmdMsg()– Command message 처리작업

virtual CheckAutoCenter()– Auto-center 옵션이 체크되었는지 확인

virtual SetOccDialogInfo()– M_pOccDialogInfo 변수에 데이터를 setting

virtual PreInitDialog()– WM_INITDIALOG message 이전에 불리워지는 함수

PreModal()– DoModal() 함수 실행을 위한 준비작업

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 loopDWORD dwFlags = MLF_SHOWONIDLE;if (GetStyle() & DS_NOIDLEMSG) dwFlags |= MLF_NOIDLEMSG;VERIFY(RunModalLoop(dwFlags) == m_nModalResult);

} CWnd Run 함수를 대치한다 .

비트교육센터[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 modelessASSERT(m_hWnd == NULL);

// allow OLE servers to disable themselvesCWinApp* pApp = AfxGetApp();if (pApp != NULL) pApp->EnableModeless(FALSE);

// find parent HWNDHWND hWnd = CWnd::GetSafeOwner_

(m_pParentWnd->GetSafeHwnd(), &m_hWndTop);

// hook for creation of dialogAfxHookWindowCreate(this);

// return window to use as parent for dialogreturn hWnd; 부모 핸들

}

비트교육센터[20]

비트교육센터

Modal Dialog Creation (cont’d)

int CWnd::RunModalLoop(DWORD dwFlags) CWnd Run 함수를 대치한다 .{ CWnd 에 존재한다 .( 다이얼로그 이외의 다른 클레스에서도 사용된다는 의미 ) 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 를 생성하기 위한 준비

PreModal() 함수를 호출함– Safety checks

Parent window handle 을 찾음– m_hWndTop 에 저장

EnableWindow(FALSE) 를 호출– Parent window 를 disable 시킴

Modal Dialog Creation (cont’d)

비트교육센터[22]

비트교육센터

– Dialog 를 생성하고 보여줌CWnd::CreateDlgIndirect() 함수 호출내부적으로 Win32API 인 CreateDialogIndirect() 를 호출CWnd::RunModalLoop() 함수 호출Dialog 가 끝날때 까지 일을 수행사용자가 ok 나 cancel 버튼을 누르면 CWnd::EndModalLoop()

함수가 호출됨Dialog 를 화면에서 보이지 않게 함Dialog 가 종료하면 EnableWindow(TRUE) 를 호출Parent window 를 enable 시킴

– 마지막 단계DestroyWindow() 함수 호출PostModal() 함수 호출

Modal Dialog Creation (cont’d)

비트교육센터[23]

비트교육센터

Modeless dialog creation– 두가지 과정을 거침

New operator 를 사용하여 변수 생성 힙메모리에 변수 생성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 soonreturn 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() 함수 호출– 사용자가 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 InitializationDialog 에 있는 control 의 초기화 작업

– Resource 에 의한 초기화– Combo box 를 예로 살펴봄

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 DLGINITBEGIN IDC_COMBO1, 0x403, 4, 00x6e6f, 0x0065, IDC_COMBO1, 0x403, 4, 00x7774, 0x006f, IDC_COMBO1, 0x403, 6, 00x6874, 0x6572, 0x0065, 0END

예제를 쎃넣을 경우 다음과 같은 내용이 첨부된다 .

비트교육센터[31]

비트교육센터

CWnd::ExecuteDlgInit()(WINCORE.CPP)– 두가지 버전이 존재

Argument 로 dialog template nameArgument 로 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)– 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)++;

AddString 등의 동일한 작업을 할수 있게 if 문 작성됨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/DDVDDX/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{// Attributespublic: 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_bSaveAndValidateTRUE data 가 control 에서 변수로 감FALSE data 가 변수에서 control 로 감Validation 은 TRUE 일때만 일어남

– m_pDlgWndDialog 에 대한 CWnd pointer

– m_hWndLastControlPrevious control 에 대한 handle 을 저장

– m_bEditLastControlPrevious control 이 수정되었는지를 저장

비트교육센터[37]

비트교육센터

멤버 함수– Constructor– PrepareCtrl()

Non-edit control 을 위한 준비– PrepareEditCtrl()

Edit control 을 위한 준비– Fail()

Validation 이 실패하면 호출됨Focus 를 previous control 로 보내고 CUserException 예외를

발생시킴– PrepareOleCtrl()

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 이동– DDV_MaxChars()(DLGDATA.CPP)

m_bSaveAndValidate 값이 TRUE 인경우 validation 코드 수행– DDX_TextWithFormat()(DLGDATA.CPP)

String 과 int 사이의 conversion

DDX/DDV (cont’d)

비트교육센터[40]

비트교육센터

DDX/DDV (cont’d)

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); 맴버변수에서 컨트롤로 (FALSE) }}

비트교육센터[41]

비트교육센터

DDX/DDV (cont’d)

void AFXAPI DDV_MaxChars(CDataExchange* pDX, CString const& value, int nChars) 예 ) 범위에 맞는지 틀린지 check{ 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 preppDX->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]

비트교육센터

DDX/DDV (cont’d)

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 recursepThreadState->m_hLockoutNotifyWindow = m_hWnd;BOOL bOK = FALSE; // assume failureTRY {

DoDataExchange(&dx);bOK = TRUE; // it worked

}CATCH(CUserException, e) {

// validation failed - user already alerted, fall throughASSERT(!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 itemreturn;

}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 DialogsCommon Dialogs

– 표준 interface 제공을 위하여– 종류

CColorDialogCFileDialogCFindReplaceDialogCFontDialogCPrintDialogCPageSetupDialog ( 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 를 가지고 있다 .

대응되는 API 를 가지고 있다 .

예 ) 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 blockvirtual int DoModal();CString GetPathName() const; // return full path and filenameCString GetFileName() const; // return only filenameCString GetFileExt() const; // return only extCString GetFileTitle() const; // return file titleBOOL GetReadOnlyPref() const; // return TRUE if readonly checked// Enumerating multiple file selectionsPOSITION 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여러 개의 virtual protected 함수기타 여러 정보 저장을 위한 변수

– CFileDialog 의 생성 (DLGFILE.CPP)생성자의 argument 들을 OPENFILENAME structure 의 멤버에 settin

g 함 (m_ofn)Window95 이상일 경우에는 OFN_EXPLORER 와 OFN_ENABLEHOOK f

lag 를 set 함– OFN_ENABLEHOOK Hook routine 을 제공 (_AfxCommDlgProc() 를 m_of

n 의 hook field 에 set)

Common Dialogs (cont’d)

비트교육센터[51]

비트교육센터

– CFileDialog::DoModal()(DLGFILE.CPP)M_bOpenFileDialog 변수의 값을 보고 Win32 API 인 GetOpenFileNa

me() 을 호출할건지 GetSaveFileName() 을 호출할건지를 결정

Common Dialogs (cont’d)

비트교육센터[52]

비트교육센터

Common Dialogs (cont’d)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 SheetsTabbed dialogsMFC 3.0 때부터 제공하나의 dialog 에서 사용자로부터 많은 입력을 받을 수 있는 인터페이스

비트교육센터[54]

비트교육센터

Property Sheets (cont’d)두개의 class

– CPropertySheet 버튼역할Tabbed dialog 를 위한 class

– CPropertyPage 리소스와 관련Tabbed dialog 의 각각의 tab(page) 을 위한 class

일반 dialog 와의 차이점– Apply 버튼 제공

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() 호출

OK/Apply/Cancel 버튼이 자동적으로 추가– 3-2. (modeless property sheet)

CPropertySheet 의 파생클래스 생성한 뒤 인스턴스를 생성하고 Create() 함수 호출

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 ClassDeclaration of CPropertySheet

– AFXDLGS.H (CWnd 의 파생클래스임… ) 다이얼로그의 특성을 가져오기가 어렵다는 뜻임 .

class CPropertySheet : public CWnd{// Attributespublic: 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)// Operationspublic: 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);// Implementationpublic: 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()– 수많은 constructor 들이 호출하는 공통 함수

m_pages– CPtrArray 형의 pointer 로 CPropertyPage class 의 pointer 의 배열

CPropertySheet Class (cont’d)

비트교육센터[61]

비트교육센터

m_strCaption– Property sheet 의 caption

m_pParentWnd– Parent window 에 대한 pointer

m_bStacked– Tab 을 stacked mode 로 할건지 scrolled mode 로 할 건지를 결정

m_bModeless– Property sheet 를 modal 로 할건지 modeless 로 할건지

CPropertySheet Class (cont’d)

비트교육센터[62]

비트교육센터

CPropertySheet::DoModal()– DLGPROP.CPP– 내부 수행

AfxDeferRegisterClass() 호출– 내부적으로 InitCommonControls() 함수 호출 (Windows common controls

DLL 을 초기화 )BuildPropPageArray() 호출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]

비트교육센터

CPropertySheet Class (cont’d)

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 ClassesControl class 의 세가지 group

– Old fashioned (6)Button, combo box, edit, list box, scroll bar, static

– New fangledWindow common controls

– OLE controls

비트교육센터[68]

비트교육센터

Old-Fashioned 특징

– 모두 CWnd 에서 상속받음– Cbitmap, CBitmapButton, CComboBox, CEdit, CListBox, CDragListBox, CCheckList

Box, CScrollBar, CStatic– Declaration 은 AFXWIN.H– Implementation

AFXWIN2.INLWINCTRL1.CPPWINCTRL2.CPPWINCTRL3.CPPWINBTN.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, CRichEditCtr

l, CSliderCtrl, CSpinButtonCtrl, …– Declaration 은 AFXCMN.H– Implementation

AFXCMN.INLWINCTRL2.CPPWINCTRL4.CPP

Chapter 07MFC 의 Document View Arhitecture

비트교육센터[72]

비트교육센터

ContentsIntroductionArchitectureInside document/view architectureDocument/view internals

비트교육센터[73]

비트교육센터

IntroductionApplication 의 data 관리

– Data 를 분리하여 관리하자 .– 중요한 이슈

누가 data 를 관리할 것인가누가 data 를 update 할 것인가data 의 rendering 어떻게 다르게 할 것인가…

– Print 와 print preview 의 지원– 두 부분

Data management(Document)User-interface management(Frame/View)

비트교육센터[74]

비트교육센터

Introduction (cont’d)기존의 방법

– 분리하지 않고 하나의 클래스에서 처리– 대단히 복잡

중요성– Multiple ways to represent your data

Rendering & Updating– Multiple types of data

User interface

비트교육센터[75]

비트교육센터

ArchitectureDocument 와 view

– DocumentApplication 의 data 를 의미

– ViewApplication 의 data 의 표현을 의미

비트교육센터[76]

비트교육센터

Document/View ComponentsMFC document/view architecture 를 위한 4 개의 components

– Documents– Views– Document/view frames– Document templates

비트교육센터[77]

비트교육센터

Documents– CDocument class

Managing file I/OUpdating renderings of the dataCCmdTarget(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) 로 부터 상속 받음– CCmdTarget Command message (WM_COMMAND) 를 받을 수 있음– CWnd Window message(WM_PAINT) 를 받을 수 있음

View 는 border 가 없는 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 classSingle Document Interface워드패드

– MDI CMDIChildWnd classMultiple Document IntefaceMS Word

Document/View Components(cont’d)

비트교육센터[81]

비트교육센터

Document templates– CDocTemplate class– Document, view, frame 을 묶어서 하나의 unit 으로 관리– 각각의 서로 다른 document type 에 대하여 하나씩의 template 을 가질 수 있다 . – 실제 사용시

한 type 의 document CSingleDocTemplate class여러 type 의 document CMultiDocTemplate class

Document/View Components(cont’d)

비트교육센터[82]

비트교육센터

CSingleDocTemplate– 생성자의 인자

Resource IDDocumet/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 을 생성함생성이 끝나면 CWinApp::AddDocTemplate() 호출

– CWinApp 의 document template list 에 추가함

CWinApp에서 각각의 DoucmentTemplate를 관리한다 .

버전이 올라가면서 이탬플릿을 관리하는 것을 만들었는데CDocMenager이다 .

비트교육센터[85]

비트교육센터

CWinApp 의 역할 (cont’d)

BOOL CTestApp::InitInstance(){

…CMultiDocTemplate* pDocTemplate;pDocTemplate = new CMultiDocTemplate(

IDR_TESTTYPE,RUNTIME_CLASS(CTestDoc),RUNTIME_CLASS(CChildFrame), // custom MDI child frameRUNTIME_CLASS(CTestView));

AddDocTemplate(pDocTemplate); 리스트로 넣어주는부분…

}

비트교육센터[86]

비트교육센터

Document/View Arch. InternalsDocument/View arch. 의 기본

– CWinAppDocument template 의 관리

– Document templateFrames/Views/Documents 의 관리

비트교육센터[87]

비트교육센터

CDocManager ClassCDocManager

– CWinApp 와 CDocTemplate 사이의 interface 역할– CWinApp 가 필요한 document template 의 list 를 관리하는 역할– CWinApp 의 declaration(AFXWIN.H)

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 exitvirtual void CloseAllDocuments(BOOL bEndSession); virtual int GetOpenDocumentCount();CPtrList m_templateList;int GetDocumentCount();

};

비트교육센터[89]

비트교육센터

CDocManager Class(contd.)Declaration(AFXWIN.H)

– 멤버 변수m_templateList

– CPtrList type– 실제 document template 의 list

– 멤버 함수대부분의 함수가 m_templateList 에 대한 조작과 CWinApp 와의 inte

rface 를 위해서 존재

비트교육센터[90]

비트교육센터

CDocManager Class(contd.)대부분의 CWinApp 의 document template 관련 함수는 CDocManag

er 의 함수를 그대로 호출함– 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 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 templatespublic:

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 classCDocTemplate

– Document/View/Frame 을 관리– Base class– 실제 사용시에는 둘중하나의 파생클래스를 사용

CSingleDocTemplate– DOCSINGL.CPP

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);// Attributespublic: 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

– Document template 에 대한 resource IDm_pDocClass

– CDocument 에 대한 CRuntimeClass structure 의 pointerm_pFrameClass

– CFrameWnd 에 대한 CRuntimeClass structure 의 pointer

비트교육센터[101]

비트교육센터

CDocTemplate class(contd.)m_pViewClass

– CView 에 대한 CRuntimeClass structure 의 pointerm_strDocStrings

– Document template 의 string resourceImplementation(DOCTEMPL.CPP)

– Document/View/Frame 을 생성하는 함수CDocTemplate::CreateNewDocument()CDocTemplate::CreateNewFrame()

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;

View 의 생성에 필요한 정보들을 저장한다 .(4 가지… )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 생성생성된 document 를 open 된 document list 에 추가

– CDocTemplate::CreateNewFrame()CCreateContext 에 필요한 정보를 채움m_pFrameClass->CreateObject() 를 이용해 frame 생성Frame 에 필요한 resource 를 load

비트교육센터[105]

비트교육센터

CDocTemplate class(contd.)– CCreateContext structure

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/frameCView* m_pLastView;CFrameWnd* m_pCurrentFrame;

// ImplementationCCreateContext();

};

비트교육센터[106]

비트교육센터

CDocTemplate class(contd.)– CCreateContext structure

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( 여러개저장필요 LinkedList 사용 )– CPtrList m_docList;– int m_nUntitledCount; Untitled document 의 수를 저장함 (Untitled[X])

비트교육센터[108]

비트교육센터

CDocTemplate class(contd.)– CMultiDocTemplate::OpenDocumentFile()

DOCMULTI.CPPDocument 와 frame 의 생성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 nameSetDefaultTitle(pDocument);pDocument->OnNewDocument();

} else {// open an existing document( 기존의 파일을 오픈하는 경우 )

CWaitCursor wait;pDocument->OnOpenDocument(lpszPathName);pDocument->SetPathName(lpszPathName);

}return pDocument;

}

비트교육센터[110]

비트교육센터

CFrameWnd classCFrameWnd

– CView 의 생성 !– m_pViewActive

현재 atcive 한 view 에 대한 pointerCFrameWnd::GetActiveView()CFrameWnd::SetActiveView()

– InitialUpdateFrame() 함수모든 view 의 OnInitialUpdate() 함수를 호출함

비트교육센터[111]

비트교육센터

CFrameWnd class(contd.)

Implementation(WINFRM.CPP)– CFrameWnd::CreateView()

진정한 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;}Frame 윈도우가 부모윈도우 , View 윈도우가 자식윈도우가 될것이라는 것을 암시

비트교육센터[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 firstOnCreateClient(lpcs, pContext);

}

비트교육센터[113]

비트교육센터

CFrameWnd class(contd.)

여기서 CreateView 가 호출된다 .

BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext){

if (pContext != NULL && pContext->m_pNewViewClass != NULL)

{CreateView(pContext, AFX_IDW_PANE_FIRST);

}}

여기부분을 수정하게 되면 다중의 View 도 구현이 된다 .

비트교육센터[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 ClassCDocument

– 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() 함수 호출– DeleteContents() 호출– Modified flag 를 FALSE 로 함– m_strPathName 이 NULL 인지 확인

– File 로 부터 create 하는 경우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 yetSetModifiedFlag(FALSE); // make clean

return TRUE;}

CDocument Class (cont’d)

비트교육센터[121]

비트교육센터

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

CDocument Class (cont’d)

비트교육센터[122]

비트교육센터

CDocument Class (cont’d)Saving Documents

– OnSaveDocument()GetFile() 함수를 이용하여 file openCArchive class 를 이용하여 serializationModified 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 시– DisconnectViews() 함수를 호출하여 각 viwe 의 m_pDocument 가 NULL

이 되게 함 자신을 관리하는 Docment(m_ViewList) 를 가리키는 포인터

Frame 에 접근하고자 할 때– Cview::GetParentFrame() 함수 이용

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(); //view 의 포지션을 가져오고while (pos != NULL){

CView* pView = GetNextView(pos); // 각각의 View 포인터ASSERT_VALID(pView);if (pView != pSender)

pView->OnUpdate(pSender, lHint, pHint);}

}

CDocument Class (cont’d)

비트교육센터[126]

비트교육센터

CView ClassCView

– Declaration(AFXWIN.H)– Implementation(VIEWCORE.CPP)

void CView::OnPaint(){

// standard paint routineCPaintDC dc(this);OnPrepareDC(&dc);OnDraw(&dc);

}

비트교육센터[127]

비트교육센터

Document/View Internals

CWinApp::OnFileOpen()CWinApp::OnFileOpen() CWinApp::OnFileNew()CWinApp::OnFileNew()

CDocManager::OnFileOpen()CDocManager::OnFileOpen() CDocManager::OnFileNew()CDocManager::OnFileNew()

CDocTemplate::OpenDocumentFile()CDocTemplate::OpenDocumentFile()

CDocTemplate::CreateNewDocument()CDocTemplate::CreateNewDocument()

CDocTemplate::CreateNewFrame()CDocTemplate::CreateNewFrame()

WM_CREATEWM_CREATE

비트교육센터[128]

비트교육센터

Document/View…(contd.)

WM_CREATEWM_CREATE

CFrameWnd::OnCreate()CFrameWnd::OnCreate()

CFrameWnd::OnCreateHelper()CFrameWnd::OnCreateHelper()

CFrameWnd::OnCreateClient()CFrameWnd::OnCreateClient()

CFrameWnd::CreateView()CFrameWnd::CreateView()

CMyDocument::OnOpenDocument()CMyDocument::OnOpenDocument()

CMyDocument::OnNewDocument()CMyDocument::OnNewDocument()