Transcript MFC3

Chap. 6
Dialog and Control Classes
Contents




CDialog class
Common Dialogs
Property Sheets
Control classes
CDialog Class

Dialog의 종류

Modal dialog




Close될 때 까지 다른 부분을 사용할 수 없음
DoModal()함수를 이용
예 : common dialog box
Modeless dialog




Close되기 전에 다른 부분을 사용할 수 있음
Create()함수를 이용
DestroyWindow()함수를 이용하여 명시적으로 종료함
예 : find and replace dialog box
CDialog Class (cont’d)

History

MFC 1.0



Current version



Modal dialog : CModalDialog
Modeless dialog : CDialog
Modal dialog : CDialog
Modeless dialog : Cdialog
AFXWIN.H
// all CModalDialog functionality is now in CDialog
#define CModalDialog CDialog
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;
Win32 APIs

Dialog생성을 위한 Win32 APIs

CreateDialog()


CreateDialogIndirect()


Modeless dialog생성, template pointer이용
DialogBox()


Modeless dialog생성, template resource이용
Modal dialog생성, template resource이용
DialogBoxIndirect()

Modal dialog생성, template pointer이용
Win32 APIs (cont’d)

CDialog Class




오직 CreateDialogIndirect() API을 이용
Modality를 내부적으로 구현
AFXWIN.H
DLGCORE.CPP, AFXWIN2.INL
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();
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();
CDialog (cont’d)
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)

Declaration(AFXWIN.H)

멤버 변수

m_nIDHelp


m_lpszTemplateName


Resource template의 이름
m_hDialogTemplate


Button을 위한 help ID
일단 load된 후의 resource template의 handle
m_lpDialogInit

초기화에 관련된 data에 대한 pointer
CDialog (cont’d)

m_pParentWnd


m_hWndTop


Top-level parent window
m_pOccDialogInfo


Parent window에 대한 pointer
OLE controls을 위한 stored information
멤버 함수

virtual PreTranslateMessage()

특별한 message(tool tips, context-sensitive help)에 대한
filtering
CDialog (cont’d)

virtual OnCmdMsg()


virtual CheckAutoCenter()


WM_INITDIALOG message이전에 불리워지는 함수
PreModal()


M_pOccDialogInfo변수에 데이터를 setting
virtual PreInitDialog()


Auto-center옵션이 체크되었는지 확인
virtual SetOccDialogInfo()


Command message처리작업
DoModal()함수 실행을 위한 준비작업
PostModal()

DoModal()함수가 끝난후의 뒤처리
Modal Dialog Creation

일반적으로 두가지의 과정을 거침



CDialog construction
DoModal()함수의 호출
CDialog construction


DLGCORE.CPP에 있음
두가지 버전이 있으며 CDialog class의 필요한 변수에
값을 입력하는 역할을 함
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;
}
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;
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);
}
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();
}
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;
}
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));
}
}
Modal Dialog Creation (cont’d)

DoModal()(DLGCORE.CPP)

Dialog resource의 loading


Dialog template name을 가지고 dialog template을 찾아서
load함
Dialog를 생성하기 위한 준비

PreModal()함수를 호출함


Parent window handle을 찾음


Safety checks
m_hWndTop에 저장
EnableWindow(FALSE)를 호출

Parent window를 disable시킴
Modal Dialog Creation (cont’d)

Dialog를 생성하고 보여줌









CWnd::CreateDlgIndirect()함수 호출
내부적으로 Win32API인 CreateDialogIndirect()를 호출
CWnd::RunModalLoop()함수 호출
Dialog가 끝날때 까지 일을 수행
사용자가 ok나 cancel버튼을 누르면
CWnd::EndModalLoop()함수가 호출됨
Dialog를 화면에서 보이지 않게 함
Dialog가 종료하면 EnableWindow(TRUE)를 호출
Parent window를 enable시킴
마지막 단계


DestroyWindow()함수 호출
PostModal()함수 호출
Modeless Dialog Creation

Modeless dialog creation

두가지 과정을 거침


New operator를 사용하여 변수 생성
CDialog::Create()함수 호출
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;
}
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);
}
Modeless Dialog Creation (cont’d)

CDialog::Create()(DLGCORE.CPP)



Template name과 help ID를 내부 변수에 저장
Dialog resource를 찾고 load함
CDialog::CreateIndirect()함수 호출


내부적으로 Win32 API인 CreateDialogIndirect()함수 호출
사용자가 ok나 cancel버튼을 누르면 EndDialog()가
호출되어 dialog가 사라짐
Dialog Terminator
void CDialog::EndDialog(int nResult)
{
ASSERT(::IsWindow(m_hWnd));
if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL))
EndModalLoop(nResult);
::EndDialog(m_hWnd, nResult);
}
CDialog Control Initialization

Dialog에 있는 control의 초기화 작업


Resource에 의한 초기화
Combo box를 예로 살펴봄


Data는 “one”, “two”, “three”라 가정
다음과 같은 코드가 생성되지 않는다.
m_pCombo->AddString(“one”);
m_pCombo->AddString(“two”);
m_pCombo->AddString(“three”);
CDialog Control Initialization (cont’d)

WM_INITDIALOG




CDialog::HandleInitDialog()


Dialog가 화면에 보이기 전에 발생하는 message
Application으로 하여금 dialog에 있는 control들을
초기화 할 수 있도록 함
CDialog::HandleInitDialog()함수에 mapping되어 있음
OLE control 관련 초기화 작업을 하고
CDialog::OnInitDialog()를 호출
CDialog::OnInitDialog()

CWnd::ExecuteDlgInit()를 호출
CDialog Control Initialization (cont’d)

Resource file
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
CDialog Control Initialization (cont’d)

CWnd::ExecuteDlgInit()(WINCORE.CPP)

두가지 버전이 존재


Argument로 dialog template name
Argument로 dialog data에 대한 pointer

일단 첫번째 버전의 함수가 dialog template name을
가지고 resource 파일에서 control의 data를 load함
이 후 pointer를 얻어서 두번째 버전의 함수를 호출

why CWnd class member function?

CDialog Control Initialization (cont’d)

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;
}
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);
}
DDX/DDV (cont’d)

Question



CDataExchange class의 역할
Control들과 멤버 변수들간의 정보 교환은 언제,
어디에서, 어떻게 이루어지는가
DDX/DDV 함수는 무슨 일들을 하는가
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
};
DDX/DDV (cont’d)

멤버 변수

m_bSaveAndValidate




m_pDlgWnd


Dialog에 대한 CWnd pointer
m_hWndLastControl


TRUE  data가 control에서 변수로 감
FALSE  data가 변수에서 control로 감
Validation은 TRUE일때만 일어남
Previous control에 대한 handle을 저장
m_bEditLastControl

Previous control이 수정되었는지를 저장
DDX/DDV (cont’d)

멤버 함수


Constructor
PrepareCtrl()


PrepareEditCtrl()


Edit control을 위한 준비
Fail()



Non-edit control을 위한 준비
Validation이 실패하면 호출됨
Focus를 previous control로 보내고 CUserException예외를
발생시킴
PrepareOleCtrl()

OLE control을 위한 준비
DDX/DDV (cont’d)

특징




DDX/DDV는 Serialize과정과 유사
CDataExchange 는 CArchive 와 비슷
DoDataExchange()는 Serialize() 와 비슷
Save/load tag를 가짐
DDX/DDV (cont’d)

DDX/DDV 함수들

DDX_Text()(DLGDATA.CPP)


DDV_MaxChars()(DLGDATA.CPP)


m_bSaveAndValidate의 값을 기준으로 data이동
m_bSaveAndValidate값이 TRUE인경우 validation코드 수행
DDX_TextWithFormat()(DLGDATA.CPP)

String과 int사이의 conversion
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);
}
}
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);
}
}
DDX/DDV (cont’d)

언제 DoDataExchange()가 호출되는가?



필요할 때 마다 UpdateData()함수 호출
위 함수 내부에서 DoDataExchange()를 호출함
UpdateData()(WINCORE.CPP)
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 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);
}
}
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
}
Common Dialogs

Common Dialogs


표준 interface제공을 위하여
종류






CColorDialog
CFileDialog
CFindReplaceDialog
CFontDialog
CPrintDialog
CPageSetupDialog ( MFC 4.0 )
Common Dialogs (cont’d)

Steps



생성자 호출
DoModal() 호출
IDOK가 리턴될 때 적절한 처리
CFileDialog myDialog(TRUE, NULL, NULL, OFN_FILEMUSTEXIST);
if ( myDialog.DoModal() == IDOK ) {
Cstring strPath = myDialog.GetPathName();
CString strFile = myDialog.GetFileName();
}
else
// User selected Cancel …
Common Dialogs (cont’d)

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)

예제 dialog

CFileDialog(AFXDLGS.H)
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;
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);
};
Common Dialogs (cont’d)

예제 dialog

CFileDialog(AFXDLGS.H)




OPENFILENAME structure
여러 개의 virtual protected 함수
기타 여러 정보 저장을 위한 변수
CFileDialog의 생성(DLGFILE.CPP)


생성자의 argument들을 OPENFILENAME structure의 멤버에
setting함(m_ofn)
Window95이상일 경우에는 OFN_EXPLORER와
OFN_ENABLEHOOK flag를 set함

OFN_ENABLEHOOK  Hook routine을
제공(_AfxCommDlgProc()를 m_ofn의 hook field에 set)
Common Dialogs (cont’d)

CFileDialog::DoModal()(DLGFILE.CPP)

M_bOpenFileDialog변수의 값을 보고 Win32 API인
GetOpenFileName()을 호출할건지 GetSaveFileName()을
호출할건지를 결정
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;
}
Property Sheets



Tabbed dialogs
MFC 3.0 때부터 제공
하나의 dialog 에서 사용자로부터 많은 입력을
받을 수 있는 인터페이스
Property Sheets (cont’d)

두개의 class

CPropertySheet


CPropertyPage


Tabbed dialog를 위한 class
Tabbed dialog의 각각의 tab(page)을 위한 class
일반 dialog와의 차이점

Apply버튼 제공

Page별로 update하는 기능을 제공
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 버튼이 자동적으로 추가되지 않음
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();
…
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);
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();
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;
};
CPropertySheet Class (cont’d)

Declaration of CPropertySheet



AFXDLGS.H
CWnd에서 상속받음 (why?)
멤버

CommonConstruct()


수많은 constructor들이 호출하는 공통 함수
m_pages

CPtrArray형의 pointer로 CPropertyPage class의 pointer의
배열
CPropertySheet Class (cont’d)

m_strCaption


m_pParentWnd


Parent window에 대한 pointer
m_bStacked


Property sheet의 caption
Tab을 stacked mode로 할건지 scrolled mode로 할 건지를
결정
m_bModeless

Property sheet를 modal로 할건지 modeless로 할건지
CPropertySheet Class (cont’d)

CPropertySheet::DoModal()


DLGPROP.CPP
내부 수행

AfxDeferRegisterClass()호출



내부적으로 InitCommonControls()함수 호출(Windows
common controls DLL을 초기화)
BuildPropPageArray()호출
Main window를 disable하고 ::PropertySheet()함수를 호출
(이후는 CDialog::DoModal()과 동일)
CPropertySheet Class (cont’d)

CPropertySheet::AddPage()



DLGPROP.CPP
m_pages멤버 변수에 page 추가
CPropertySheet::BuildPropPageArray()


DLGPROP.CPP
각 page에 있는 PROPSHEETPAGE structure정보를
저장함
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;
}
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();
}
}
}
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();
}
Control Classes

Control class의 세가지 group

Old fashioned (6)


New fangled


Button, combo box, edit, list box, scroll bar, static
Window common controls
OLE controls
Old-Fashioned

특징




모두 CWnd에서 상속받음
Cbitmap, CBitmapButton, CComboBox, CEdit,
CListBox, CDragListBox, CCheckListBox, CScrollBar,
CStatic
Declaration은 AFXWIN.H
Implementation





AFXWIN2.INL
WINCTRL1.CPP
WINCTRL2.CPP
WINCTRL3.CPP
WINBTN.CPP
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;
New-fangled

특징




모두 CWnd에서 상속받음
CAnimateCtrl, CDragListBox, CHotKeyCtrl, CImageList,
CProgressCtrl, CRichEditCtrl, CSliderCtrl,
CSpinButtonCtrl, …
Declaration은 AFXCMN.H
Implementation



AFXCMN.INL
WINCTRL2.CPP
WINCTRL4.CPP
Chap. 7
Document/View Architecture
Contents




Introduction
Architecture
Inside document/view architecture
Document/view internals
Introduction

Application의 data관리


Data를 분리하여 관리하자.
중요한 이슈






누가 data를 관리할 것인가
누가 data를 update할 것인가
data 의 rendering 어떻게 다르게 할 것인가
…
Print 와 print preview의 지원
두 부분


Data management
User-interface management
Introduction (cont’d)

기존의 방법



분리하지 않고 하나의 클래스에서 처리
대단히 복잡
중요성

Multiple ways to represent your data


Rendering & Updating
Multiple types of data

User interface
Architecture

Document와 view

Document


Application의 data를 의미
View

Application의 data의 표현을 의미
Document/View Components

MFC document/view architecture를 위한 4개의
components




Documents
Views
Document/view frames
Document templates
Document/View Components (cont’d)

Documents

CDocument class



Managing file I/O
Updating renderings of the data
CCmdTarget(CObject)로 부터 상속 받음


CObject  Run-time type information, dynamic creation,
serialization
CCmdTarget  Command message (WM_COMMAND)를
받을 수 있음
Document/View Components (cont’d)

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)

Document/View Frames

각각의 view에 서로 다른 user-interface를 적용할 수
있게 함
Frame
View
Document/View Components (cont’d)

SDI  CFrameWnd class



Single Document Interface
워드패드
MDI  CMDIChildWnd class


Multiple Document Inteface
MS Word
Document/View Components (cont’d)

Document templates




CDocTemplate class
Document, view, frame을 묶어서 하나의 unit으로
관리
각각의 서로 다른 document type에 대하여 하나씩의
template을 가질 수 있다.
실제 사용시


한 type의 document  CSingleDocTemplate class
여러 type의 document  CMultiDocTemplate class
Document/View Components (cont’d)

CSingleDocTemplate

생성자의 인자



Resource ID
Documet/View/Frame 의 Run-time class
CMultiDocTemplate


CSingleDocTemplate와 생성자의 인자가 동일
차이점 : linked list를 통해 다수의 정보 유지
Document/View Components (cont’d)

Resource ID





application 의 string table
window title, document name
새 document 생성 시 description
파일 open 시 파일 type 에 대한 description
file extension filter, …
CWinApp의 역할

CWinApp의 역할은?


Document template을 관리함
CWinApp::InitInstance()함수


Document template을 생성함
생성이 끝나면 CWinApp::AddDocTemplate()호출

CWinApp의 document template list에 추가함
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);
…
}
Document/View Arch. Internals

Document/View arch.의 기본

CWinApp


Document template의 관리
Document template

Frames/Views/Documents의 관리
CDocManager Class

CDocManager



CWinApp와 CDocTemplate사이의 interface역할
CWinApp가 필요한 document template의 list를
관리하는 역할
CWinApp의 declaration(AFXWIN.H)

CDocManager * m_pDocManager;
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();
};
CDocManager Class(contd.)

Declaration(AFXWIN.H)

멤버 변수

m_templateList



CPtrList type
실제 document template의 list
멤버 함수

대부분의 함수가 m_templateList에 대한 조작과
CWinApp와의 interface를 위해서 존재
CDocManager Class(contd.)

대부분의 CWinApp의 document template관련 함수는
CDocManager의 함수를 그대로 호출함









CWinApp::AddDocTemplate()
CWinApp::CloseAllDocument()
CWinApp::DoPromptFileName()
CWinApp::GetFirstDocTemplatePosition()
CWinApp::GetNextDocTemplate()
CWinApp::GetOpenDocumentCount()
CWinApp::OnFileNew()
CWinApp::OnFileOpen()
…
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();
}
CDocManager Class(contd.)

CDocManager::OnFileNew()


새로운 document template을 생성하는 역할
하나 이상의 document template가 있을때는
CNewTypeDlg dialog class를 이용(DOCMGR.CPP)


사용자가 document template을 선택하게 함
사용자에게 document template list로 보여주는 좋은 예가 됨
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);
}
CDocManager Class(contd.)

CNewTypeDlg class

DOCMGR.CPP
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();
};
CDocManager Class(contd.)

CNewTypeDlg resource

AFXRES.RC
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();
}
CDocTemplate class

CDocTemplate



Document/View/Frame을 관리
Base class
실제 사용시에는

CSingleDocTemplate


DOCSINGL.CPP
CMultiDocTemplate

DOCMULTI.CPP
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);
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
};
CDocTemplate class(contd.)

Declaration(AFXWIN.H)

멤버 변수

m_nIDResource


m_pDocClass


Document template에 대한 resource ID
CDocument에 대한 CRuntimeClass structure의 pointer
m_pFrameClass

CFrameWnd에 대한 CRuntimeClass structure의 pointer
CDocTemplate class(contd.)

m_pViewClass


m_strDocStrings


CView에 대한 CRuntimeClass structure의 pointer
Document template의 string resource
Implementation(DOCTEMPL.CPP)

Document/View/Frame을 생성하는 함수



CDocTemplate::CreateNewDocument()
CDocTemplate::CreateNewFrame()
View에 관한 명시적인 함수는 없음
CDocTemplate class(contd.)
CDocument* CDocTemplate::CreateNewDocument()
{
CDocument* pDocument =
(CDocument*)m_pDocClass->CreateObject();
AddDocument(pDocument);
return pDocument;
}
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;
}
CDocTemplate class(contd.)

CDocTemplate::CreateNewDocument()



m_pDocClass->CreateObject()를 이용해 document생성
생성된 document를 open된 document list에 추가
CDocTemplate::CreateNewFrame()



CCreateContext에 필요한 정보를 채움
m_pFrameClass->CreateObject()를 이용해 frame생성
Frame에 필요한 resource를 load
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/frame
CView* m_pLastView;
CFrameWnd* m_pCurrentFrame;
// Implementation
CCreateContext();
};
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를 가리킴
CDocTemplate class(contd.)

Open된 document의 관리는?


CSingleDocTemplate


CSingleDocTemplate와 CMultiDocTemplate가 담당
CDocument* m_pOnlyDoc;
CMultiDocTemplate


CPtrList m_docList;
int m_nUntitledCount;  Untitled document의 수를
저장함(Untitled[X])
CDocTemplate class(contd.)

CMultiDocTemplate::OpenDocumentFile()



DOCMULTI.CPP
Document와 frame의 생성
CFrameWnd::InitialUpdateFrame()호출
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;
}
CFrameWnd class

CFrameWnd


CView의 생성!
m_pViewActive




현재 atcive한 view에 대한 pointer
CFrameWnd::GetActiveView()
CFrameWnd::SetActiveView()
InitialUpdateFrame()함수

모든 view의 OnInitialUpdate()함수를 호출함
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;
}
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);
}
CFrameWnd class(contd.)
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT,
CCreateContext* pContext)
{
if (pContext != NULL &&
pContext->m_pNewViewClass != NULL)
{
CreateView(pContext, AFX_IDW_PANE_FIRST);
}
}
CFrameWnd class(contd.)

CreateNewFrame()이 호출되면






Windows가 WM_CREATE message를 보냄
OnCreate()함수의 호출
 OnCreateHelper()의 호출
OnCreateClient()의 호출
CreateView()의 호출
결국 CreateNewFrame()의 호출 결과임
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);
}
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
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;
};
CDocument Class (cont’d)


Implementation(DOCCORE.CPP)
Key aspects



Creating documents
Saving documents
Communicating with views
CDocument Class (cont’d)

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)
BOOL CDocument::OnNewDocument()
{
if (IsModified())
TRACE0("Warning: OnNewDocument replaces an unsaved
document.\n");
DeleteContents();
m_strPathName.Empty();
SetModifiedFlag(FALSE);
return TRUE;
}
// no path name yet
// make clean
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;
}
CDocument Class (cont’d)

Saving Documents

OnSaveDocument()



GetFile()함수를 이용하여 file open
CArchive class를 이용하여 serialization
Modified flag를 FALSE로 함
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
}
CDocument Class (cont’d)

View와의 통신


m_viewList에 view의 list를 저장
통신이 필요한 경우

Destroy시


Frame에 접근하고자 할 때


DisconnectViews()함수를 호출하여 각 viwe의
m_pDocument가 NULL이 되게 함
Cview::GetParentFrame()함수 이용
View들에게 document의 변경을 알리고자 할 때

UpdateAllViews()함수 호출
CDocument Class (cont’d)
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);
}
}
CView Class

CView


Declaration(AFXWIN.H)
Implementation(VIEWCORE.CPP)
void CView::OnPaint()
{
// standard paint routine
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
Document/View Internals
CWinApp::OnFileOpen()
CWinApp::OnFileNew()
CDocManager::OnFileOpen()
CDocManager::OnFileNew()
CDocTemplate::OpenDocumentFile()
CDocTemplate::CreateNewDocument()
CDocTemplate::CreateNewFrame()
WM_CREATE
Document/View…(contd.)
WM_CREATE
CFrameWnd::OnCreate()
CFrameWnd::OnCreateHelper()
CFrameWnd::OnCreateClient()
CFrameWnd::CreateView()
CMyDocument::OnOpenDocument()
CMyDocument::OnNewDocument()