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