비트교육센터

Download Report

Transcript 비트교육센터

Chapter
06
MFC Dialog 와 Control Class
Contents
CDialog class
Common Dialogs
Property Sheets
Control classes
[1]
비트교육센터
CDialog Class
Dialog의 종류
– Modal dialog
Close될 때 까지 다른 부분을 사용할 수 없음
DoModal()함수를 이용
예 : common dialog box
– Modeless dialog
Close되기 전에 다른 부분을 사용할 수 있음
Create()함수를 이용
DestroyWindow()함수를 이용하여 명시적으로 종료함
예 : find and replace dialog box
[2]
비트교육센터
CDialog Class (cont’d)
History
– MFC 1.0
Modal dialog : CModalDialog
Modeless dialog : CDialog
– Current version
Modal dialog : CDialog
Modeless dialog : Cdialog
– AFXWIN.H
// all CModalDialog functionality is now in CDialog
#define CModalDialog CDialog
[3]
비트교육센터
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;
[4]
비트교육센터
Win32 APIs
Dialog생성을 위한 Win32 APIs
– CreateDialog()
Modeless dialog생성, template resource이용
– CreateDialogIndirect()
Modeless dialog생성, template pointer이용
 Modal()/Modaless를 만들때 모두 사용되는 함수
– DialogBox()
Modal dialog생성, template resource이용
– DialogBoxIndirect()
Modal dialog생성, template pointer이용
[5]
비트교육센터
Win32 APIs (cont’d)
CDialog Class
–
–
–
–
오직 CreateDialogIndirect() API을 이용
Modality를 내부적으로 구현
AFXWIN.H
DLGCORE.CPP, AFXWIN2.INL
[6]
비트교육센터
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();
[7]
비트교육센터
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();
[8]
비트교육센터
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()
};
[9]
비트교육센터
CDialog (cont’d)
Declaration(AFXWIN.H)
– 멤버 변수
m_nIDHelp
– Button을 위한 help ID
m_lpszTemplateName
– Resource template의 이름
m_hDialogTemplate
– 일단 load된 후의 resource template의 handle
m_lpDialogInit
– 초기화에 관련된 data에 대한 pointer
[10]
비트교육센터
CDialog (cont’d)
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
[11]
비트교육센터
CDialog (cont’d)
virtual OnCmdMsg()
– Command message처리작업
virtual CheckAutoCenter()
– Auto-center옵션이 체크되었는지 확인
virtual SetOccDialogInfo()
– M_pOccDialogInfo변수에 데이터를 setting
virtual PreInitDialog()
– WM_INITDIALOG message이전에 불리워지는 함수
PreModal()
– DoModal()함수 실행을 위한 준비작업
PostModal()
– DoModal()함수가 끝난후의 뒤처리
[12]
비트교육센터
Modal Dialog Creation
일반적으로 두가지의 과정을 거침
– CDialog construction
– DoModal()함수의 호출
CDialog construction
– DLGCORE.CPP에 있음
– 두가지 버전이 있으며 CDialog class의 필요한 변수에 값을 입력하는 역할을 함
[13]
비트교육센터
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;
}
[14]
비트교육센터
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;
[15]
비트교육센터
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);
}
 CWnd Run함수를 대치한다.
[16]
비트교육센터
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();
}
[17]
비트교육센터
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;  부모 핸들
}
[18]
비트교육센터
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));
}
}
[19]
비트교육센터
Modal Dialog Creation (cont’d)
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시킴
[20]
비트교육센터
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()함수 호출
[21]
비트교육센터
Modeless Dialog Creation
Modeless dialog creation
– 두가지 과정을 거침
New operator를 사용하여 변수 생성 힙메모리에 변수 생성
CDialog::Create()함수 호출
[22]
비트교육센터
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;
}
[23]
비트교육센터
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);
}
[24]
비트교육센터
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가 사라짐
[25]
비트교육센터
Dialog Terminator
void CDialog::EndDialog(int nResult)
{
ASSERT(::IsWindow(m_hWnd));
if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL))
EndModalLoop(nResult);
::EndDialog(m_hWnd, nResult);
}
[26]
비트교육센터
CDialog Control Initialization
Dialog에 있는 control의 초기화 작업
– Resource에 의한 초기화
– Combo box를 예로 살펴봄
Data는 “one”, “two”, “three”라 가정
– 다음과 같은 코드가 생성되지 않는다.
m_pCombo->AddString(“one”);
m_pCombo->AddString(“two”);
m_pCombo->AddString(“three”);
[27]
비트교육센터
CDialog Control Initialization (cont’d)
WM_INITDIALOG
– Dialog가 화면에 보이기 전에 발생하는 message
– Application으로 하여금 dialog에 있는 control들을 초기화 할 수 있도록 함
– CDialog::HandleInitDialog()함수에 mapping되어 있음
CDialog::HandleInitDialog()
– OLE control 관련 초기화 작업을 하고 CDialog::OnInitDialog()를 호출
CDialog::OnInitDialog()
– CWnd::ExecuteDlgInit()를 호출
[28]
비트교육센터
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
[29]
비트교육센터
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?
[30]
비트교육센터
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)++;
 AddString등의 동일한 작업을 할수 있게 if문 작성됨
if (nMsg == LB_ADDSTRING || nMsg == CB_ADDSTRING) {
if (::SendDlgItemMessageA(m_hWnd, nIDC, nMsg, 0,
(LONG)lpnRes) == -1)
bSuccess = FALSE;
}
}
return bSuccess;
}
[31]
비트교육센터
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);
}
[32]
비트교육센터
DDX/DDV (cont’d)
Question
– CDataExchange class의 역할
– Control들과 멤버 변수들간의 정보 교환은 언제, 어디에서, 어떻게 이루어지는가
– DDX/DDV 함수는 무슨 일들을 하는가
[33]
비트교육센터
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
};
[34]
비트교육센터
DDX/DDV (cont’d)
멤버 변수
– m_bSaveAndValidate
TRUE  data가 control에서 변수로 감
FALSE  data가 변수에서 control로 감
Validation은 TRUE일때만 일어남
– m_pDlgWnd
Dialog에 대한 CWnd pointer
– m_hWndLastControl
Previous control에 대한 handle을 저장
– m_bEditLastControl
Previous control이 수정되었는지를 저장
[35]
비트교육센터
DDX/DDV (cont’d)
멤버 함수
– Constructor
– PrepareCtrl()
Non-edit control을 위한 준비
– PrepareEditCtrl()
Edit control을 위한 준비
– Fail()
Validation이 실패하면 호출됨
Focus를 previous control로 보내고 CUserException예외를 발생시킴
– PrepareOleCtrl()
OLE control을 위한 준비
[36]
비트교육센터
DDX/DDV (cont’d)
특징
–
–
–
–
DDX/DDV는 Serialize과정과 유사
CDataExchange 는 CArchive 와 비슷
DoDataExchange()는 Serialize() 와 비슷
Save/load tag를 가짐
[37]
비트교육센터
DDX/DDV (cont’d)
DDX/DDV 함수들
– DDX_Text()(DLGDATA.CPP)
m_bSaveAndValidate의 값을 기준으로 data이동
– DDV_MaxChars()(DLGDATA.CPP)
m_bSaveAndValidate값이 TRUE인경우 validation코드 수행
– DDX_TextWithFormat()(DLGDATA.CPP)
String과 int사이의 conversion
[38]
비트교육센터
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)
}
}
[39]
비트교육센터
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 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);
}
}
비트교육센터
[40]
DDX/DDV (cont’d)
언제 DoDataExchange()가 호출되는가?
– 필요할 때 마다 UpdateData()함수 호출
– 위 함수 내부에서 DoDataExchange()를 호출함
UpdateData()(WINCORE.CPP)
[41]
비트교육센터
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);
}
}
[42]
비트교육센터
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
}
[43]
비트교육센터
Common Dialogs
Common Dialogs
– 표준 interface제공을 위하여
– 종류
CColorDialog
CFileDialog
CFindReplaceDialog
CFontDialog
CPrintDialog
CPageSetupDialog ( MFC 4.0 )
[44]
비트교육센터
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 …
[45]
비트교육센터
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() 추가
[46]
비트교육센터
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;
[47]
비트교육센터
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);
비트교육센터
};
[48]
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)
[49]
비트교육센터
Common Dialogs (cont’d)
– CFileDialog::DoModal()(DLGFILE.CPP)
M_bOpenFileDialog변수의 값을 보고 Win32 API인 GetOpenFileName()을
호출할건지 GetSaveFileName()을 호출할건지를 결정
[50]
비트교육센터
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;
}
[51]
비트교육센터
Property Sheets
Tabbed dialogs
MFC 3.0 때부터 제공
하나의 dialog 에서 사용자로부터 많은 입력을 받을 수 있는 인터페이스
[52]
비트교육센터
Property Sheets (cont’d)
두개의 class
– CPropertySheet  버튼역할
Tabbed dialog를 위한 class
– CPropertyPage  리소스와 관련
Tabbed dialog의 각각의 tab(page)을 위한 class
일반 dialog와의 차이점
– Apply버튼 제공
Page별로 update하는 기능을 제공
[53]
비트교육센터
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 버튼이 자동적으로 추가되지 않음
[54]
비트교육센터
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();
…
[55]
비트교육센터
CPropertySheet Class
Declaration of CPropertySheet
– AFXDLGS.H (CWnd의 파생클래스임…) 다이얼로그의 특성을 가져오기가 어
렵다는 뜻임.
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);
[56]
비트교육센터
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();
[57]
비트교육센터
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;
};
[58]
비트교육센터
CPropertySheet Class (cont’d)
Declaration of CPropertySheet
– AFXDLGS.H
– CWnd에서 상속받음 (why?)
– 멤버
CommonConstruct()
– 수많은 constructor들이 호출하는 공통 함수
m_pages
– CPtrArray형의 pointer로 CPropertyPage class의 pointer의 배열
[59]
비트교육센터
CPropertySheet Class (cont’d)
m_strCaption
– Property sheet의 caption
m_pParentWnd
– Parent window에 대한 pointer
m_bStacked
– Tab을 stacked mode로 할건지 scrolled mode로 할 건지를 결정
m_bModeless
– Property sheet를 modal로 할건지 modeless로 할건지
[60]
비트교육센터
CPropertySheet Class (cont’d)
CPropertySheet::DoModal()
– DLGPROP.CPP
– 내부 수행
AfxDeferRegisterClass()호출
– 내부적으로 InitCommonControls()함수 호출(Windows common
controls DLL을 초기화)
BuildPropPageArray()호출
Main window를 disable하고 ::PropertySheet()함수를 호출 (이후는
CDialog::DoModal()과 동일)
[61]
비트교육센터
CPropertySheet Class (cont’d)
CPropertySheet::AddPage()
– DLGPROP.CPP
– m_pages멤버 변수에 page 추가
CPropertySheet::BuildPropPageArray()
– DLGPROP.CPP
– 각 page에 있는 PROPSHEETPAGE structure정보를 저장함
[62]
비트교육센터
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;
}
[63]
비트교육센터
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();
}
}
}
[64]
비트교육센터
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();
}
[65]
비트교육센터
Control Classes
Control class의 세가지 group
– Old fashioned (6)
Button, combo box, edit, list box, scroll bar, static
– New fangled
Window common controls
– OLE controls
[66]
비트교육센터
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
[67]
비트교육센터
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;
[68]
비트교육센터
New-fangled
특징
– 모두 CWnd에서 상속받음
– CAnimateCtrl, CDragListBox, CHotKeyCtrl, CImageList, CProgressCtrl,
CRichEditCtrl, CSliderCtrl, CSpinButtonCtrl, …
– Declaration은 AFXCMN.H
– Implementation
AFXCMN.INL
WINCTRL2.CPP
WINCTRL4.CPP
[69]
비트교육센터
Chapter
07
MFC 의 Document View Arhitecture
Contents
Introduction
Architecture
Inside document/view architecture
Document/view internals
[71]
비트교육센터
Introduction
Application의 data관리
– Data를 분리하여 관리하자.
– 중요한 이슈
누가 data를 관리할 것인가
누가 data를 update할 것인가
data 의 rendering 어떻게 다르게 할 것인가
…
– Print 와 print preview의 지원
– 두 부분
Data management(Document)
User-interface management(Frame/View)
[72]
비트교육센터
Introduction (cont’d)
기존의 방법
– 분리하지 않고 하나의 클래스에서 처리
– 대단히 복잡
중요성
– Multiple ways to represent your data
Rendering & Updating
– Multiple types of data
User interface
[73]
비트교육센터
Architecture
Document와 view
– Document
Application의 data를 의미
– View
Application의 data의 표현을 의미
[74]
비트교육센터
Document/View Components
MFC document/view architecture를 위한 4개의 components
–
–
–
–
Documents
Views
Document/view frames
Document templates
[75]
비트교육센터
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)를 받을 수 있
음
[76]
비트교육센터
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라고 함
[77]
비트교육센터
Document/View Components(cont’d)
Document/View Frames
– 각각의 view에 서로 다른 user-interface를 적용할 수 있게 함
Frame
View
[78]
비트교육센터
Document/View Components(cont’d)
– SDI  CFrameWnd class
Single Document Interface
워드패드
– MDI  CMDIChildWnd class
Multiple Document Inteface
MS Word
[79]
비트교육센터
Document/View Components(cont’d)
Document templates
–
–
–
–
CDocTemplate class
Document, view, frame을 묶어서 하나의 unit으로 관리
각각의 서로 다른 document type에 대하여 하나씩의 template을 가질 수 있다.
실제 사용시
한 type의 document  CSingleDocTemplate class
여러 type의 document  CMultiDocTemplate class
[80]
비트교육센터
Document/View Components(cont’d)
CSingleDocTemplate
– 생성자의 인자
Resource ID
Documet/View/Frame 의 Run-time class
CMultiDocTemplate
– CSingleDocTemplate와 생성자의 인자가 동일
– 차이점 : linked list를 통해 다수의 정보 유지
[81]
비트교육센터
Document/View Components(cont’d)
Resource ID
–
–
–
–
–
application 의 string table
window title, document name
새 document 생성 시 description
파일 open 시 파일 type 에 대한 description
file extension filter, …
[82]
비트교육센터
CWinApp의 역할
CWinApp의 역할은?
– Document template을 관리함
– CWinApp::InitInstance()함수  여기에서 초기화한다.
Document template을 생성함
생성이 끝나면 CWinApp::AddDocTemplate()호출
– CWinApp의 document template list에 추가함
CWinApp에서 각각의 DoucmentTemplate를 관리한다.
버전이 올라가면서 이탬플릿을 관리하는 것을 만들었는데
CDocMenager이다.
[83]
비트교육센터
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); 리스트로 넣어주는부분
…
}
[84]
비트교육센터
Document/View Arch. Internals
Document/View arch.의 기본
– CWinApp
Document template의 관리
– Document template
Frames/Views/Documents의 관리
[85]
비트교육센터
CDocManager Class
CDocManager
– CWinApp와 CDocTemplate사이의 interface역할
– CWinApp가 필요한 document template의 list를 관리하는 역할
– CWinApp의 declaration(AFXWIN.H)
CDocManager * m_pDocManager;
 이 객체가 관리한다.
[86]
비트교육센터
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();
};
[87]
비트교육센터
CDocManager Class(contd.)
Declaration(AFXWIN.H)
– 멤버 변수
m_templateList
– CPtrList type
– 실제 document template의 list
– 멤버 함수
대부분의 함수가 m_templateList에 대한 조작과 CWinApp와의 interface를
위해서 존재
[88]
비트교육센터
CDocManager Class(contd.)
대부분의 CWinApp의 document template관련 함수는 CDocManager의 함수
를 그대로 호출함
– CWinApp::AddDocTemplate()
– CWinApp::CloseAllDocument()
– CWinApp::DoPromptFileName()
– CWinApp::GetFirstDocTemplatePosition()
– CWinApp::GetNextDocTemplate()
– CWinApp::GetOpenDocumentCount()
– CWinApp::OnFileNew()
– CWinApp::OnFileOpen()
– …
[89]
비트교육센터
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();
}
[90]
비트교육센터
CDocManager Class(contd.)
CDocManager::OnFileNew()
– 새로운 document template을 생성하는 역할
– 하나 이상의 document template가 있을때는 CNewTypeDlg dialog class를 이
용(DOCMGR.CPP)
사용자가 document template을 선택하게 함
사용자에게 document template list로 보여주는 좋은 예가 됨
[91]
비트교육센터
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);
}
[92]
비트교육센터
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();
};
[93]
비트교육센터
CDocManager Class(contd.)
CNewTypeDlg resource
– AFXRES.RC
[94]
비트교육센터
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();
}
[95]
비트교육센터
CDocTemplate class
CDocTemplate
– Document/View/Frame을 관리
– Base class
– 실제 사용시에는 둘중하나의 파생클래스를 사용
CSingleDocTemplate
– DOCSINGL.CPP
CMultiDocTemplate
– DOCMULTI.CPP
[96]
비트교육센터
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);
[97]
비트교육센터
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
};
[98]
비트교육센터
CDocTemplate class(contd.)
Declaration(AFXWIN.H)
– 멤버 변수
m_nIDResource
– Document template에 대한 resource ID
m_pDocClass
– CDocument에 대한 CRuntimeClass structure의 pointer
m_pFrameClass
– CFrameWnd에 대한 CRuntimeClass structure의 pointer
[99]
비트교육센터
CDocTemplate class(contd.)
m_pViewClass
– CView에 대한 CRuntimeClass structure의 pointer
m_strDocStrings
– Document template의 string resource
Implementation(DOCTEMPL.CPP)
– Document/View/Frame을 생성하는 함수
CDocTemplate::CreateNewDocument()
CDocTemplate::CreateNewFrame()
View에 관한 명시적인 함수는 없음
[100]
비트교육센터
CDocTemplate class(contd.)
CDocument* CDocTemplate::CreateNewDocument()
{
CDocument* pDocument =
(CDocument*)m_pDocClass->CreateObject();
AddDocument(pDocument); //생성될 때 바로 연결리스트에 넣어준다.
return pDocument;
}
[101]
비트교육센터
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;
}
[102]
비트교육센터
CDocTemplate class(contd.)
– CDocTemplate::CreateNewDocument()
m_pDocClass->CreateObject()를 이용해 document생성
생성된 document를 open된 document list에 추가
– CDocTemplate::CreateNewFrame()
CCreateContext에 필요한 정보를 채움
m_pFrameClass->CreateObject()를 이용해 frame생성
Frame에 필요한 resource를 load
[103]
비트교육센터
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();
};
[104]
비트교육센터
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를 가리킴
[105]
비트교육센터
CDocTemplate class(contd.)
Open된 document의 관리는?
– CSingleDocTemplate와 CMultiDocTemplate가 담당
CSingleDocTemplate(하나만 저장되면 됨  포인터변수하나면충분)
– CDocument* m_pOnlyDoc;
CMultiDocTemplate(여러개저장필요 LinkedList사용)
– CPtrList m_docList;
– int m_nUntitledCount;  Untitled document의 수를 저장함(Untitled[X])
[106]
비트교육센터
CDocTemplate class(contd.)
– CMultiDocTemplate::OpenDocumentFile()
DOCMULTI.CPP
Document와 frame의 생성
CFrameWnd::InitialUpdateFrame()호출
[107]
비트교육센터
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;
비트교육센터
}
[108]
CFrameWnd class
CFrameWnd
– CView의 생성!
– m_pViewActive
현재 atcive한 view에 대한 pointer
CFrameWnd::GetActiveView()
CFrameWnd::SetActiveView()
– InitialUpdateFrame()함수
모든 view의 OnInitialUpdate()함수를 호출함
[109]
비트교육센터
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윈도우가 자식윈도우가 될것이라는 것을 암시
[110]
비트교육센터
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);
}
[111]
비트교육센터
CFrameWnd class(contd.)
여기서 CreateView가 호출된다.
BOOL CFrameWnd::OnCreateClient(LPCREATESTRUCT, CCreateContext*
pContext)
{
if (pContext != NULL &&
pContext->m_pNewViewClass != NULL)
{
CreateView(pContext, AFX_IDW_PANE_FIRST);
}
}
 여기부분을 수정하게 되면 다중의 View 도 구현이 된다.
[112]
비트교육센터
CFrameWnd class(contd.)
CreateNewFrame()이 호출되면
– Windows가 WM_CREATE message를 보냄
– OnCreate()함수의 호출
–  OnCreateHelper()의 호출
– OnCreateClient()의 호출
– CreateView()의 호출
결국 CreateNewFrame()의 호출 결과임
[113]
비트교육센터
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);
}
비트교육센터
[114]
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(); //[115]
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;
비트교육센터
};
[116]
CDocument Class (cont’d)
Implementation(DOCCORE.CPP)
Key aspects
– Creating documents
– Saving documents
– Communicating with views
[117]
비트교육센터
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로 함
[118]
비트교육센터
CDocument Class (cont’d)
BOOL CDocument::OnNewDocument()
{
if (IsModified())
TRACE0("Warning: OnNewDocument replaces an unsaved
document.\n");
DeleteContents();
m_strPathName.Empty();
SetModifiedFlag(FALSE);
// no path name yet
// make clean
return TRUE;
}
[119]
비트교육센터
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;
}
비트교육센터
[120]
CDocument Class (cont’d)
Saving Documents
– OnSaveDocument()
GetFile()함수를 이용하여 file open
CArchive class를 이용하여 serialization
Modified flag를 FALSE로 함
[121]
비트교육센터
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
}
[122]
비트교육센터
CDocument Class (cont’d)
View와의 통신
– m_viewList에 view의 list를 저장
– 통신이 필요한 경우
Destroy시
– DisconnectViews()함수를 호출하여 각 viwe의 m_pDocument가
NULL이 되게 함
 자신을 관리하는 Docment(m_ViewList)를 가리키는 포인터
Frame에 접근하고자 할 때
– Cview::GetParentFrame()함수 이용
View들에게 document의 변경을 알리고자 할 때
– UpdateAllViews()함수 호출
 가장 빈번하게 발생
[123]
비트교육센터
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(); //view의 포지션을 가져오고
while (pos != NULL)
{
CView* pView = GetNextView(pos); //각각의 View포인터
ASSERT_VALID(pView);
if (pView != pSender)
pView->OnUpdate(pSender, lHint, pHint);
}
}
[124]
비트교육센터
CView Class
CView
– Declaration(AFXWIN.H)
– Implementation(VIEWCORE.CPP)
void CView::OnPaint()
{
// standard paint routine
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
[125]
비트교육센터
Document/View Internals
CWinApp::OnFileOpen()
CWinApp::OnFileNew()
CDocManager::OnFileOpen()
CDocManager::OnFileNew()
CDocTemplate::OpenDocumentFile()
CDocTemplate::CreateNewDocument()
CDocTemplate::CreateNewFrame()
WM_CREATE
[126]
비트교육센터
Document/View…(contd.)
WM_CREATE
CFrameWnd::OnCreate()
CFrameWnd::OnCreateHelper()
CFrameWnd::OnCreateClient()
CFrameWnd::CreateView()
CMyDocument::OnOpenDocument()
CMyDocument::OnNewDocument()
[127]
비트교육센터