* 어플리케이션 구조
기본적인 프로그램을 제작할 때 필요한 기본 클래스는 다음 네가지이다. CWinApp, CDocument,
CFrameWnd, CView 의 네가지인데 실질적으로 앞의 두 클래스는 화면에 보이지 않고 뒤의 두
클래스는 화면에 보이는 클래스로 구분된다. 윈도우 프로그램은 메시지를 통해 프로그램이 진행
되므로 기본적으로 메시지를 주고 받는 클래스가 필요한데 이것은 CObject에서 상속을 받는 클
래스인 CCmdTarget이다.
CFrameWnd : 윈도우 외곽선, 타이틀, 윈도우 메뉴, 도구바, 상태창 등을 포함한 메인 윈도우.
CView : 메인 윈도우 내부의 작은 윈도우, 기본적인 화면 출력을 하는곳.
CDocument : 프로그램의 실행도중에 가지고 있는 데이터를 보관하는 클래스.
CWinApp : 위와같은 객체들을 서로 연결시켜주는 객체.
위의 네개의 클래스 모두 CCmdTarget을 상속받았으므로 메시지를 받을수 있다. 제일 먼저 메시
지가 실행되는 것이 CView이고 다음은 CView와 같이 출력되는 CDocument이며 CFrameWnd와
CWinApp가 메시지를 받는다. 따라서 이러한 메시지의 처리도 프로그램의 과정에서 중요한 부분
이 된다.
2. CWnd 클래스 계층
CWnd클래스의 하위 클래스로는 CFrameWnd, CView, CDialog, Controls 가 있으며 이 중에서
Controls는 리소스 자원중 MFC에서 제공하는 특징적인 자원을 말한다. 예를 들면, 리스트 상자,
애니메이션 실행 상자, 프로세서 bar 등을 말한다.
따라서, View 화면이 하나 있고 틀이 하나 있는 윈도형(보통 SDI)에서는 최소 CWinApp,
CDocument, CFrameWnd, CView 네 개의 클래스가 필요하며 대화상자를 n개 썼다면 CDialog
n개가 필요하여 모두 4+n개의 클래스가 필요하다.
1. CFrameWnd 클래스의 하위 클래스
CFrameWnd의 하위 클래스로는 CMIDChildWnd, CMIDFrameWnd, CMainFrameWnd,
COlelPFrameWnd의 네 개가 있다. MDI는 document가 여러개라는 뜻이므로 SDI가 아닌 여러개
의 View화면이 나타날 때 각 View윈도의 틀을 SDI에서의 CView대신 CMIDChildWnd가 구성하
며 마찬가지로 MDI형 프로그램을 제작할 때 메인 윈도우의 틀을 구성하는 것이 SDI에서의
CFrameWnd 대신 CMIDFrameWnd 가 된다. OLE를 사용하여 다른 프로그램을 자신의 윈도에
출력하고자 할 때 필요한 윈도 프레임은 COlelPFrameWnd가 구성한다. 이것은 같은 프레임 윈도
클래스라 해도 특정 환경에 맞게끔 프레임 윈도를 세부적으로 분할한 것이다.
2. CView 클래스의 하위 클래스
CView의 중요한 하위 클래스는 CFormView, CScrollView이며 CFormView는 View 클래스 안에
여러 자원을 설정할 수 있는 View이다. 즉 대화상자처럼 버튼과 에디터 상자, 리스트 상자등을
설정할 수 있는 View이다. CScrollView는 말그대로 스크롤 가능한 View를 구성할 때 필요한 클
래스이다.
3. CDialog 클래스의 하위 클래스
대표적인 클래스로는 CCommonDialog가 있고 파일을 열고 닫는 대화상자를 만들 때 CFileDialog
를, 프린터를 설정할 때 CPrintDialog를 사용한다.
3. Graphic Device Interface, GDI 객체 클래스
GDI란, 화면 출력시 출력을 담당하는 Video page라고 말할 수 있다. SDK 프로그래밍에서 화면
에 글자를 출력시킬 때
TextOut ( hdc, 0, 0, temp, strlen(temp) );
과 같이 사용했을 때 여기서 hdc가 GDI 핸들러인데 이 형이 바로 HDC이며 MFC에서는 HDC
를 포함하는 GDI 클래스가 있다. 이것이 바로 CDC이고 하위 클래스로는 CClientDC, CPaintDC,
CWindowDC, CMetaFileDC가 있다. CClientDC는 윈도에서 실질적으로 사용할 수 있는 화면 즉
제목바와 외곽선 등을 제외한 중앙의 상자 영역을 받는 DC(Device Context)를 말한다. 전체 윈도
를 받을 때는 CWindowDC를 쓰며 WM_PAINT 메시지에 의해 실행되는 MFC함수는 OnPaintd
인데 이 함수 안에서 DC를 핸들링할 때 사용하는 DC가 CPaintDC이다.
4. 기타 클래스
CFile
파일을 열고 닫으며 데이터를 파일에 기록할 때 파일을 원활하게 컨트롤할 수 있도록 설계된 클
래스이다.
CMenu
메인 윈도우 안에 붙어 있는 메뉴도 직접 컨트롤할 수 있게 해주는 클래스이다.
CGdiObject
그래픽에 필요한 객체로 선을 그릴 때 CPen, 면을 칠할 때 CBrush, 글자를 설정할 때 CFont, 비
트맵을 출력할 때 CBitmap등이 있다.
5. 클래스로만 프로그램 만들기
* 비트맵 이미지를 출력하는 예제 프로그램 작성
1단계
CWinApp : 프로그램간의 연결.
CFrameWnd : 프로그램의 메인 윈도 프레임 설정.
CScrollView : SDI 프로그램으로 만들 경우 이미지의 크기가 클수 있으므로 CView대신 사용.
CDocument : 이미지 데이터를 저장.
2단계
CWinApp : 프로그램간의 연결.
CFrameWnd : 프로그램의 메인 윈도 프레임 설정. CMenu를 사용하여 메뉴에 파일 열기, 저
장 항목을 만들고 CFileDialog를 이용하여 파일을 열고 저장하도록 함.
CScrollView : 화면을 상하 좌우로 이동하는 View를 만든다.
CDocument : 이미지 데이터를 저장. 이때 CBitmap클래스를 설정한다.
3단계
CWinApp : 프로그램간의 연결.
CFrameWnd : 프로그램의 메인 윈도 프레임 설정. CMenu를 사용하여 메뉴에 파일 열기, 저
장 항목을 만들고 CFileDialog를 이용하여 파일을 열고 저장하도록 함.
CScrollView : 화면을 상하 좌우로 이동하는 View를 만든다. CDC를 이용하여 CDocument에
의해 저장된 CBitmap 이미지를 화면에 출력한다.
CDocument : 이미지 데이터를 저장. CFrameWnd의 CFileDialog에 의해 설정된 파일명을
받아 CFile클래스를 이용하여 데이터를 읽어서 CBitmap에 설정한다.
이러한 클래스들은 실제로는 그대로 사용하지 않고 상속받아서 사용한다. 즉 다음과 같이
class CTestApp :: public CWndApp
class CTestView :: public CScrollView
class CTestDoc :: public CDocument
class CTestFrame :: public CFrameWnd
이렇게 상속을 받아서 사용한다.
6. 자동으로 만들어진 4개의 클래스 분석
DEMO 프로젝트를 만들고 나면 자동적으로 CWinApp 형태인 CDEMO1App,
CMDIFrameWnd 형태인 CMainFrame, CDocument 형태인 CDEMO1Doc, CView 형태인
CDEMO1View 4개의 클래스가 만들어지고 그 안에 기본적인 코드가 기록된다.
CDemo1App-CWinApp 클래스
애플리케이션 클래스로 CDemo1App란 클래스가 만들어지고 그것은 DEMO1.cpp 파일에 기록되
어 있다. 이 CDemo1App 클래스는 신경 조직으로 프레임과 뷰 화면을 서로 연결해 준다. 이
CDemo1App 클래스는 CWinApp 클래스를 상속받아서 사용한다. 즉 CWinApp 클래스의 기능을
갖추고 그곳에 자기의 특수 기능을 삽입하는 것이다. CWinApp라는 것은 애플리케이션을 만들
때 필요한 클래스이다. 그러나 새로운 프로그램을 만들 때 CWinApp라는 클래스를 상속받고 현
프로그램에 적합한 새로운 기능을 추가해야 한다. 즉 CWinApp의 성격을 받고 거기에 자신이 가
지고 있는 새로운 자원으로 새로운 클래스인 CDemo1App 파일이 만들어진 것이다.
CDemo1App 파일의 내부.
#include "stdafx.h"
#include "DEMO1.h"
#include "mainfrm.h"
#include "DEMO1doc.h"
#include "DEMO1vw.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CDEMO1App, CWinApp)
//{{AFX_MSG_MAP(CDEMO1App)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE-the Classwizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
* BEGIN_MESSAGE_MAP(CDEMO1App, CWinApp), END_MESSAGE_MAP()
윈도우에서는 메시지로 모든 것을 실행한다. 마우스 버튼을 누르면 마우스 버튼을 눌렀다는 메시
지가 나오고 키보드를 누르면 키보드를 눌렀다는 메시지가 나온다. 마우스 버튼을 누르는 메시지
이벤트 그리고 그 이벤트에 따라서 실행되는 함수, 즉 이벤트 메시지<->실행되는 함수명을 설정
해 준 것이다. 위의 소스를 다시 보면 다음과 같다.
//지금부터 메시지가 나오면 어떻게 할 것인지를 써 준다.
BEGIN_MESSAGE_MAP(CDEMO1App, CWinApp)
//CDEMO1App 클래스는 CWinApp 함수를 상속받은 것인데 다음 메시지에서는
//다음 함수를 실행하라.
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
//ID_APP_ABOUT란 팝업 메뉴에서 About DEMO1이란 항목을 리소스에서 ID로 설정한
//것인데 만약 About DEMO1이란 팝업 메뉴를 선택하면 OnAppAbout 함수를 실행하라.
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
//팝업 메뉴에서 File->New를 선택하면 CWinApp 클래스의 OnFileNew 함수를 실행하라.
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
//팝업 메뉴에서 File->Open을 선택하면 CWinApp 클래스의 OnFileOpen 함수를 실행하라.
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
//팝업 메뉴에서 File->PrintSetup을 선택하면 CWinApp 클래스의 OnFilePrintSetup
//함수를 실행하라.
END_MESSAGE_MAP()
//메시지 매핑이 끝났음.
기본적으로 만들어진 프로그램에는 보통 File 메뉴와 Edit 메뉴, Window 메뉴, Help 메뉴가 있다.
위에서 알겠지만 File 메뉴에서 New 항목과 Open 항목과 Print Setup 항목은 CWinApp에서 제
공하는 기본적인 함수로 설정되어 있다. 그렇기 때문에 버튼만 눌러서 만든 프로그램에서 파일을
열거나 파일을 닫거나 또는 프린터를 설정하는 것은 자동적으로 실행이 된다. 그러나 다른 메뉴
를 선택하였을 때의 메시지는 아무것도 설정되어 있지 않다. 그렇기 때문에 다른 메뉴에서는 아
무것도 하지 않는 것이다. 다른 메뉴에서도 어떤 프로그램이 동작되려면 위의 메시지 매핑 안에
써 주어야 한다.
다음 함수는 CDEMO1App의 생성자인데 이것은 이 클래스가 실행됨과 동시에 자동적으로 실행
되는 함수입니다. 이 클래스는 프로그램이 시작됨과 동시에 실행된다. 그런데 안에는 아무것도 없
다. 즉 지금 현재는 생성시 아무것도 하지 않겠지만 후에 애플리케이션 클래스가 생성될 때 어떤
일을 해야 한다면 이 함수 안에 기록해 주면 된다.
CDEMO1App::CDEMO1App()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
CWinApp 함수가 실행되면 자동적으로 CWinApp::InitInstance 함수가 실행되게 되어 있다.
이 CDEMO1App 함수는 CWinApp 함수를 상속받아 쓰기 때문에 이 클래스가 시작되면 자동적으
로 CWinApp::InitInstance도 실행됩니다. 그러나 상속받은 것을 안 쓰고 자기의 용도에 맞는 것을
써야하므로 그럴 때는 헤더에 다음과 같이 등록한다.
virtual BOOL InitInstance();
아버지격인 CWinApp 함수 안에 InitInstance를 안 쓰고 내 것인 InitInstance를 쓰겠다는 말이
다. 물론 이것은 프로젝트 만들 때 자동적으로 등록되어 있다. 그럼 우리가 만든 DEMO1.exe는
어떻게 초기화했는지 보자.
BOOL CDEMO1App::InitInstance()
{
//3d 컨트롤을 할 수 있게 한다. 전에 프로젝트 만들 때 선택했다.
#ifdef _AFXDLL //MFC DLL를 사용할 경우
Enable3dControls(); // Call this when using MFC in a shared DLL
#else //MFC LIB를 사용할 경우
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
//프로파일 세팅을 로드.
//특정 키를 등록. 프로그램을 만들고 나면 이 키를 적당하게
//원하는 형태로 바꾸어야 한다. 예)회사명...
SetRegistryKey(_T(?ocal AppWizard-Generated ApplicationsO));
//워드프로세서 같은 것을 실행하여 어떤 파일을 불러서 수정하고 끝냈을 때 다시 그
//프로그램을 실행하면 전에 작업했던 파일이 팝업의 파일 메뉴 하단부에 죽 써져 있는 것을
//보았을 것이다. 즉 전에 프로그램 실행시에 작업했던 파일 리스트를 세팅.
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
우리가 만든 프로그램은 MDI를 선택했다. 그렇다면 MDI에 사용될 데이터를저장할 공간이 있어
야 한다. 그 공간을 설정해 주는 클래스가 CMultiDocTemplate이다. 이 클래스를 pDocTemplate
라고 가상적으로 만든 다음에 그곳에 이 도큐먼트는 어떤 윈도우와 어떤 View와 어떤 Doc가 어
떤 형태로 연결되어 있다는 것을 설정해 준다. 그럴 때 이 클래스의 생성자가 로드되면서 설정된
다.
CMultiDocTemplate* pDocTemplate;
//pDoctemplate라는 가상적인 CMultiDocTemplate형의 변수를 선언하고
//이것이 생성될 때는 CDEMO1Doc 클래스인 Document와 CMDIChildWnd 형태인 틀과
//CDEMO1View인 화면이 링크되어서 RC(리소스) 파일의 String Table 안에 설정된
//IDR_DEMO1TYPE형으로 연결됩니다.
pDocTemplate = new CMultiDocTemplate(
IDR_DEMO1TYPE,
RUNTIME_CLASS(CDEMO1Doc),
RUNTIME_CLASS(CMDIChildWnd), // standard MDI child frame
RUNTIME_CLASS(CDEMO1View)); //연결된 것을 현재 프로그램에 등록하라.
AddDocTemplate(pDocTemplate);
CMultiDocTemplate 클래스를 생성할 때 4개의 인자가 필요하다. 첫번째 인자는 현 클래스의 형
태 이름을 설정하는 리소스의 String Table ID이고, 두 번째는 도큐먼트 클래스, 3번째는 프
레임 클래스, 4번째는 View 클래스이다. AppWizard를 실행시키면 자동으로 만들어진 3개의 클
래스를 CWinApp 클래스에 등록시켜 놓는다. 다음은 이 메인 프레임에 해당하는 메뉴와 정보를
등록한다.
// MDI 프레임을 만들기 위해서 CMainFrame 형태의 가상 pMainFrame을 새로 만들고
//여기에 IDR_MAINFRAME 형태인 틀로써 형성시키고 이것을 이 프로그램의
// m_pMainWnd(메인 윈도우 변수)에 연결시킨다.
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
다음은 도스 창에서 프로그램을 실행시켰을 경우나 또는 DDE(Dynamic Data Exchange)나 파일
설정 등으로 실행했을 때 이 프로그램에 넘겨주는 인자를 받는 내용이다.
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
위의 내용은 CCommandLineInfo라는 클래스 변수 cmdInfo를 만들고 현재 프로그램이 실행
되면서 어떤 인자가 들어왔나 조사하기 위한 ParseCommandLine라는 함수를 실행하는 것이
다. 또한 AddDocTemplate 함수를 이용하여 여러 개의 Doc와 View와 Frame이 연결된 템플리트
를 만들어 등록하였을 경우에도 cmdInfo 안에 이 정보가 들어간다. 다음 내용은 이 정보를 실행
시키는 것이다.
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
ProceShellCommand 함수가 실행되면서 OnFileNew()라는 함수가 실행된다. 이 함수가 실행되면
MDI일 경우 자식 윈도우의 프레임과 도큐먼트 그리고 View가 만들어진다. 이제 이렇게 하여 모
든 정보를 등록시킨 후 기본적인 메인 프레임을 화면에 보여준다.
// The main window has been initialized, so show and update it.
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
위의 내용을 정리한다면 이 프로그램이 실행되면서 필요한 부속 윈도우를 프레임과 View Doc와
함께 등록시키고 다음 메인 프레임을 만들어서 등록하고 이 메인 프레임을 출력하는 것이다. 이
항목으로 간단히 말해서 메인 프레임을 화면에 출력하는 때까지 이루어졌다고 보면 된다.
이제 메인 프레임이 만들어졌으니 메인 프레임 소스를 조사해 보자.
CMainFrame 클래스
이제 mainfrm.cpp를 열어 봅시다.
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the Classwizard will add and remove
mapping macros here.
// DO NOT EDIT what you see in these blocks
of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
다음의 indicators는 상태창에 써지는 string의 ID이다. 윈도우 하단부에 작은 상태바를 놔두고 파
일 메뉴에 마우스가 위치하면 “새로운 파일을 열거나 닫습니다”라는 메시지, 즉 도움말이 나타
나는데 그 외 필요한 몇 가지를 설정한다는 것이다. ID_SEPARATOR란 라인을 그어서 분리시
키고 ID_INDICATOR_CAPS란 CapsLock키의 설정을 확인할 것, ID_INDICATOR_NUM은
NumLock키가 눌려있나를 확인할 것, ID_INDICATOR_SCRL이란 ScrollLock키가 눌려 있
나를 확인하라는 ID이다. 프로그램을 실행시켜 놓고 위 3개의 키를 눌러보면 현재 설정된 모습
이 상태창 오른쪽에 나타날 것이다. .
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
메인 프레임의 생성자. 현재는 비어 있는 상태.
CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
메인 프레임의 소멸자.
CMainFrame::~CMainFrame()
{
}
메인 프레임이 만들어질 때 실행되는 함수이다. 아버지 클래스인 CMDIFrameWnd 것을 사용하지
않고 자기 것, 즉 virtual로 사용한다는 것이다.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//아버지 클래스의 OnCreate를 먼저 실행하고
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
//도구바를 만들고
if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0(failed to create toolbar\nO);
return -1; // fail to create
}
//상태창을 만들고
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))
{
TRACE0(?ailed to create status bar\nO);
return -1; // fail to create
}
// TODO: Delete these three lines if you don? want the toolbar to
// be dockable
//도구바가 분리 도킹을 원하면 아래 함수를 써 주고 그렇지 않으면 지우라는 말이다.
//demo1.exe를 실행시켜서 마우스로 도구바를 눌러서 움직여 보면 따로 떨어지는 것을
//볼 수 있다.
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY);
return 0;
}
CWinApp 클래스에서 CMainFrame 프로그램이 실행할 수 있도록 프레임을 로드한다.
CMainFrame의 OnCreate 함수는 CWinApp의 InitInstance 함수 안의
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))가 실행되면 후에 수행되는 함수이다.
CWinApp 클래스에서 메인 프레임을 만들면 CMainFramw의 OnCreate 함수가 실행되는 것이다.
OnCreate 함수는 메인 프레임이 만들 때 필요한 여러 정보를 수행하는 함수이다. 위의 내용은 메
인 프레임에 함께 있는 메뉴와 도구바 그리고 상태창 등을 메인 프레임에 등록하는 것을 하는 것
이다. 지금까지 내용으로 CWinApp 클래스에서 메인 프레임을 만들고 메인 프레임을 담당하는
CMainFrame에서 도구바와 메뉴와 상태바를 등록하는 것까지 보았다. 이제 실제적으로 필요한
View와 Document가 어떻게 기록되어 있는가를 보겠다.
CDocument 클래스
DEMO1Doc.cpp 안에 설정되어 있는 CDEMO1Doc 클래스는 CDocument 클래스를 상속받은 것이
다. 이 부분은 데이터를 저장하는 곳이다. 소스를 한 번 보고 전에 설명했으므로 넘어가겠다.
BEGIN_MESSAGE_MAP(CDEMO1Doc, CDocument)
//{{AFX_MSG_MAP(CDEMO1Doc)
// NOTE - the Classwizard will add and remove
mapping macros here.
// DO NOT EDIT what you see in these blocks
of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
생성자.
CDEMO1Doc::CDEMO1Doc()
{
// TODO: add one-time construction code here
}
소멸자.
CDEMO1Doc::~CDEMO1Doc()
{
}
OnNewDocument 함수는 파일 new를 실행하거나 OnFileNew() 함수를 실행하여서 새로운 파일
이 탄생될 때 실행해 주는 함수이다. 지금 현재는 아무것도 없이 아버지 클래스인 CDocument의
OnNewDosument만 실행한다.
BOOL CDEMO1Doc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
Serialize는 메모리에 있는 데이터를 디스크와 연결시켜 주는 함수이다. 간단히 말해서 데이터를
파일로 저장하고 저장된 데이터를 불러오는 함수이다.
void CDEMO1Doc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// 파일로 저장할 때
}
else
{
// 파일에서 불러올 때
}
}
CView 클래스
활성화되어 있는 윈도우의 화면에 보이는 것을 기록하는 클래스이다. CDEMO1View란 클래스로
CView 클래스를 상속받은 것이다. 이것은 DEMO1View.cpp에 설정되어 있다.
메시지 매핑
BEGIN_MESSAGE_MAP(CDEMO1View, CView)
//{{AFX_MSG_MAP(CDEMO1View)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
생성자 함수
CDEMO1View::CDEMO1View()
{
// TODO: add construction code here
}
소멸자 함수
CDEMO1View::~CDEMO1View()
{
}
함수 OnDraw 안에 화면에 뿌려 주는 여러 기능을 넣으면 화면에 뿌려진다. 화면에 출력할 여러
정보는 전에 말했듯이 도큐먼트에 저장한다고 하였다. 따라서 데이터는 도큐먼트에서 받아온다.
void CDEMO1View::OnDraw(CDC* pDC)
{
그래서 아래와 같이 일단 도큐먼트와 연결을 한다. CDEMO1Doc* pDoc = GetDocument(); 그
리고 ASSERT_VALID라는 함수는 pDoc가 활성화되어 있는 것을 보증하라는 말이다. 프로그
램이 돌다가 컴퓨터가 이상해져서 링크가 안 되어 도큐먼트를 받지 못하면 pDoc가 null값이 될
것이다. 이렇게 되면 ‘응용 프로그램 에러’라는 메시지를 내보내고 프로그램을 종료하라는 말
이 된다.
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
프린팅 미리 보기를 실행하는 함수이다. 이 함수는 파일 메뉴에서 Print 항목을 실행시키면 수행
된다.
BOOL CDEMO1View::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
//프린팅하는 함수
void CDEMO1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
//프린팅이 끝났을 때 사용하는 함수
void CDEMO1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
지금까지의 내용으로 MFC에서 만들어진 4개의 클래스에 대해서 다시 한 번 정리하면 먼저
CWinApp 클래스가 먼저 실행하여 메인 프레임을 만들고(LoadFrame) 메인 프레임을 담당하는
CMainFrame 클래스가 수행되면서 메뉴와 도구바, 상태바를 결합하고 CWinApp 클래스에서 다시
View와 Document를 만든다. (ProcessShellCommand) 이렇게 하여 CView와 CDocument 클래스 인 CDEMO1View와 CDEMO1Document가 수행되는 것이다.
기본적인 프로그램을 제작할 때 필요한 기본 클래스는 다음 네가지이다. CWinApp, CDocument,
CFrameWnd, CView 의 네가지인데 실질적으로 앞의 두 클래스는 화면에 보이지 않고 뒤의 두
클래스는 화면에 보이는 클래스로 구분된다. 윈도우 프로그램은 메시지를 통해 프로그램이 진행
되므로 기본적으로 메시지를 주고 받는 클래스가 필요한데 이것은 CObject에서 상속을 받는 클
래스인 CCmdTarget이다.
CFrameWnd : 윈도우 외곽선, 타이틀, 윈도우 메뉴, 도구바, 상태창 등을 포함한 메인 윈도우.
CView : 메인 윈도우 내부의 작은 윈도우, 기본적인 화면 출력을 하는곳.
CDocument : 프로그램의 실행도중에 가지고 있는 데이터를 보관하는 클래스.
CWinApp : 위와같은 객체들을 서로 연결시켜주는 객체.
위의 네개의 클래스 모두 CCmdTarget을 상속받았으므로 메시지를 받을수 있다. 제일 먼저 메시
지가 실행되는 것이 CView이고 다음은 CView와 같이 출력되는 CDocument이며 CFrameWnd와
CWinApp가 메시지를 받는다. 따라서 이러한 메시지의 처리도 프로그램의 과정에서 중요한 부분
이 된다.
2. CWnd 클래스 계층
CWnd클래스의 하위 클래스로는 CFrameWnd, CView, CDialog, Controls 가 있으며 이 중에서
Controls는 리소스 자원중 MFC에서 제공하는 특징적인 자원을 말한다. 예를 들면, 리스트 상자,
애니메이션 실행 상자, 프로세서 bar 등을 말한다.
따라서, View 화면이 하나 있고 틀이 하나 있는 윈도형(보통 SDI)에서는 최소 CWinApp,
CDocument, CFrameWnd, CView 네 개의 클래스가 필요하며 대화상자를 n개 썼다면 CDialog
n개가 필요하여 모두 4+n개의 클래스가 필요하다.
1. CFrameWnd 클래스의 하위 클래스
CFrameWnd의 하위 클래스로는 CMIDChildWnd, CMIDFrameWnd, CMainFrameWnd,
COlelPFrameWnd의 네 개가 있다. MDI는 document가 여러개라는 뜻이므로 SDI가 아닌 여러개
의 View화면이 나타날 때 각 View윈도의 틀을 SDI에서의 CView대신 CMIDChildWnd가 구성하
며 마찬가지로 MDI형 프로그램을 제작할 때 메인 윈도우의 틀을 구성하는 것이 SDI에서의
CFrameWnd 대신 CMIDFrameWnd 가 된다. OLE를 사용하여 다른 프로그램을 자신의 윈도에
출력하고자 할 때 필요한 윈도 프레임은 COlelPFrameWnd가 구성한다. 이것은 같은 프레임 윈도
클래스라 해도 특정 환경에 맞게끔 프레임 윈도를 세부적으로 분할한 것이다.
2. CView 클래스의 하위 클래스
CView의 중요한 하위 클래스는 CFormView, CScrollView이며 CFormView는 View 클래스 안에
여러 자원을 설정할 수 있는 View이다. 즉 대화상자처럼 버튼과 에디터 상자, 리스트 상자등을
설정할 수 있는 View이다. CScrollView는 말그대로 스크롤 가능한 View를 구성할 때 필요한 클
래스이다.
3. CDialog 클래스의 하위 클래스
대표적인 클래스로는 CCommonDialog가 있고 파일을 열고 닫는 대화상자를 만들 때 CFileDialog
를, 프린터를 설정할 때 CPrintDialog를 사용한다.
3. Graphic Device Interface, GDI 객체 클래스
GDI란, 화면 출력시 출력을 담당하는 Video page라고 말할 수 있다. SDK 프로그래밍에서 화면
에 글자를 출력시킬 때
TextOut ( hdc, 0, 0, temp, strlen(temp) );
과 같이 사용했을 때 여기서 hdc가 GDI 핸들러인데 이 형이 바로 HDC이며 MFC에서는 HDC
를 포함하는 GDI 클래스가 있다. 이것이 바로 CDC이고 하위 클래스로는 CClientDC, CPaintDC,
CWindowDC, CMetaFileDC가 있다. CClientDC는 윈도에서 실질적으로 사용할 수 있는 화면 즉
제목바와 외곽선 등을 제외한 중앙의 상자 영역을 받는 DC(Device Context)를 말한다. 전체 윈도
를 받을 때는 CWindowDC를 쓰며 WM_PAINT 메시지에 의해 실행되는 MFC함수는 OnPaintd
인데 이 함수 안에서 DC를 핸들링할 때 사용하는 DC가 CPaintDC이다.
4. 기타 클래스
CFile
파일을 열고 닫으며 데이터를 파일에 기록할 때 파일을 원활하게 컨트롤할 수 있도록 설계된 클
래스이다.
CMenu
메인 윈도우 안에 붙어 있는 메뉴도 직접 컨트롤할 수 있게 해주는 클래스이다.
CGdiObject
그래픽에 필요한 객체로 선을 그릴 때 CPen, 면을 칠할 때 CBrush, 글자를 설정할 때 CFont, 비
트맵을 출력할 때 CBitmap등이 있다.
5. 클래스로만 프로그램 만들기
* 비트맵 이미지를 출력하는 예제 프로그램 작성
1단계
CWinApp : 프로그램간의 연결.
CFrameWnd : 프로그램의 메인 윈도 프레임 설정.
CScrollView : SDI 프로그램으로 만들 경우 이미지의 크기가 클수 있으므로 CView대신 사용.
CDocument : 이미지 데이터를 저장.
2단계
CWinApp : 프로그램간의 연결.
CFrameWnd : 프로그램의 메인 윈도 프레임 설정. CMenu를 사용하여 메뉴에 파일 열기, 저
장 항목을 만들고 CFileDialog를 이용하여 파일을 열고 저장하도록 함.
CScrollView : 화면을 상하 좌우로 이동하는 View를 만든다.
CDocument : 이미지 데이터를 저장. 이때 CBitmap클래스를 설정한다.
3단계
CWinApp : 프로그램간의 연결.
CFrameWnd : 프로그램의 메인 윈도 프레임 설정. CMenu를 사용하여 메뉴에 파일 열기, 저
장 항목을 만들고 CFileDialog를 이용하여 파일을 열고 저장하도록 함.
CScrollView : 화면을 상하 좌우로 이동하는 View를 만든다. CDC를 이용하여 CDocument에
의해 저장된 CBitmap 이미지를 화면에 출력한다.
CDocument : 이미지 데이터를 저장. CFrameWnd의 CFileDialog에 의해 설정된 파일명을
받아 CFile클래스를 이용하여 데이터를 읽어서 CBitmap에 설정한다.
이러한 클래스들은 실제로는 그대로 사용하지 않고 상속받아서 사용한다. 즉 다음과 같이
class CTestApp :: public CWndApp
class CTestView :: public CScrollView
class CTestDoc :: public CDocument
class CTestFrame :: public CFrameWnd
이렇게 상속을 받아서 사용한다.
6. 자동으로 만들어진 4개의 클래스 분석
DEMO 프로젝트를 만들고 나면 자동적으로 CWinApp 형태인 CDEMO1App,
CMDIFrameWnd 형태인 CMainFrame, CDocument 형태인 CDEMO1Doc, CView 형태인
CDEMO1View 4개의 클래스가 만들어지고 그 안에 기본적인 코드가 기록된다.
CDemo1App-CWinApp 클래스
애플리케이션 클래스로 CDemo1App란 클래스가 만들어지고 그것은 DEMO1.cpp 파일에 기록되
어 있다. 이 CDemo1App 클래스는 신경 조직으로 프레임과 뷰 화면을 서로 연결해 준다. 이
CDemo1App 클래스는 CWinApp 클래스를 상속받아서 사용한다. 즉 CWinApp 클래스의 기능을
갖추고 그곳에 자기의 특수 기능을 삽입하는 것이다. CWinApp라는 것은 애플리케이션을 만들
때 필요한 클래스이다. 그러나 새로운 프로그램을 만들 때 CWinApp라는 클래스를 상속받고 현
프로그램에 적합한 새로운 기능을 추가해야 한다. 즉 CWinApp의 성격을 받고 거기에 자신이 가
지고 있는 새로운 자원으로 새로운 클래스인 CDemo1App 파일이 만들어진 것이다.
CDemo1App 파일의 내부.
#include "stdafx.h"
#include "DEMO1.h"
#include "mainfrm.h"
#include "DEMO1doc.h"
#include "DEMO1vw.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CDEMO1App, CWinApp)
//{{AFX_MSG_MAP(CDEMO1App)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE-the Classwizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
// Standard print setup command
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
* BEGIN_MESSAGE_MAP(CDEMO1App, CWinApp), END_MESSAGE_MAP()
윈도우에서는 메시지로 모든 것을 실행한다. 마우스 버튼을 누르면 마우스 버튼을 눌렀다는 메시
지가 나오고 키보드를 누르면 키보드를 눌렀다는 메시지가 나온다. 마우스 버튼을 누르는 메시지
이벤트 그리고 그 이벤트에 따라서 실행되는 함수, 즉 이벤트 메시지<->실행되는 함수명을 설정
해 준 것이다. 위의 소스를 다시 보면 다음과 같다.
//지금부터 메시지가 나오면 어떻게 할 것인지를 써 준다.
BEGIN_MESSAGE_MAP(CDEMO1App, CWinApp)
//CDEMO1App 클래스는 CWinApp 함수를 상속받은 것인데 다음 메시지에서는
//다음 함수를 실행하라.
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
//ID_APP_ABOUT란 팝업 메뉴에서 About DEMO1이란 항목을 리소스에서 ID로 설정한
//것인데 만약 About DEMO1이란 팝업 메뉴를 선택하면 OnAppAbout 함수를 실행하라.
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
//팝업 메뉴에서 File->New를 선택하면 CWinApp 클래스의 OnFileNew 함수를 실행하라.
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
//팝업 메뉴에서 File->Open을 선택하면 CWinApp 클래스의 OnFileOpen 함수를 실행하라.
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
//팝업 메뉴에서 File->PrintSetup을 선택하면 CWinApp 클래스의 OnFilePrintSetup
//함수를 실행하라.
END_MESSAGE_MAP()
//메시지 매핑이 끝났음.
기본적으로 만들어진 프로그램에는 보통 File 메뉴와 Edit 메뉴, Window 메뉴, Help 메뉴가 있다.
위에서 알겠지만 File 메뉴에서 New 항목과 Open 항목과 Print Setup 항목은 CWinApp에서 제
공하는 기본적인 함수로 설정되어 있다. 그렇기 때문에 버튼만 눌러서 만든 프로그램에서 파일을
열거나 파일을 닫거나 또는 프린터를 설정하는 것은 자동적으로 실행이 된다. 그러나 다른 메뉴
를 선택하였을 때의 메시지는 아무것도 설정되어 있지 않다. 그렇기 때문에 다른 메뉴에서는 아
무것도 하지 않는 것이다. 다른 메뉴에서도 어떤 프로그램이 동작되려면 위의 메시지 매핑 안에
써 주어야 한다.
다음 함수는 CDEMO1App의 생성자인데 이것은 이 클래스가 실행됨과 동시에 자동적으로 실행
되는 함수입니다. 이 클래스는 프로그램이 시작됨과 동시에 실행된다. 그런데 안에는 아무것도 없
다. 즉 지금 현재는 생성시 아무것도 하지 않겠지만 후에 애플리케이션 클래스가 생성될 때 어떤
일을 해야 한다면 이 함수 안에 기록해 주면 된다.
CDEMO1App::CDEMO1App()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
CWinApp 함수가 실행되면 자동적으로 CWinApp::InitInstance 함수가 실행되게 되어 있다.
이 CDEMO1App 함수는 CWinApp 함수를 상속받아 쓰기 때문에 이 클래스가 시작되면 자동적으
로 CWinApp::InitInstance도 실행됩니다. 그러나 상속받은 것을 안 쓰고 자기의 용도에 맞는 것을
써야하므로 그럴 때는 헤더에 다음과 같이 등록한다.
virtual BOOL InitInstance();
아버지격인 CWinApp 함수 안에 InitInstance를 안 쓰고 내 것인 InitInstance를 쓰겠다는 말이
다. 물론 이것은 프로젝트 만들 때 자동적으로 등록되어 있다. 그럼 우리가 만든 DEMO1.exe는
어떻게 초기화했는지 보자.
BOOL CDEMO1App::InitInstance()
{
//3d 컨트롤을 할 수 있게 한다. 전에 프로젝트 만들 때 선택했다.
#ifdef _AFXDLL //MFC DLL를 사용할 경우
Enable3dControls(); // Call this when using MFC in a shared DLL
#else //MFC LIB를 사용할 경우
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
//프로파일 세팅을 로드.
//특정 키를 등록. 프로그램을 만들고 나면 이 키를 적당하게
//원하는 형태로 바꾸어야 한다. 예)회사명...
SetRegistryKey(_T(?ocal AppWizard-Generated ApplicationsO));
//워드프로세서 같은 것을 실행하여 어떤 파일을 불러서 수정하고 끝냈을 때 다시 그
//프로그램을 실행하면 전에 작업했던 파일이 팝업의 파일 메뉴 하단부에 죽 써져 있는 것을
//보았을 것이다. 즉 전에 프로그램 실행시에 작업했던 파일 리스트를 세팅.
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
우리가 만든 프로그램은 MDI를 선택했다. 그렇다면 MDI에 사용될 데이터를저장할 공간이 있어
야 한다. 그 공간을 설정해 주는 클래스가 CMultiDocTemplate이다. 이 클래스를 pDocTemplate
라고 가상적으로 만든 다음에 그곳에 이 도큐먼트는 어떤 윈도우와 어떤 View와 어떤 Doc가 어
떤 형태로 연결되어 있다는 것을 설정해 준다. 그럴 때 이 클래스의 생성자가 로드되면서 설정된
다.
CMultiDocTemplate* pDocTemplate;
//pDoctemplate라는 가상적인 CMultiDocTemplate형의 변수를 선언하고
//이것이 생성될 때는 CDEMO1Doc 클래스인 Document와 CMDIChildWnd 형태인 틀과
//CDEMO1View인 화면이 링크되어서 RC(리소스) 파일의 String Table 안에 설정된
//IDR_DEMO1TYPE형으로 연결됩니다.
pDocTemplate = new CMultiDocTemplate(
IDR_DEMO1TYPE,
RUNTIME_CLASS(CDEMO1Doc),
RUNTIME_CLASS(CMDIChildWnd), // standard MDI child frame
RUNTIME_CLASS(CDEMO1View)); //연결된 것을 현재 프로그램에 등록하라.
AddDocTemplate(pDocTemplate);
CMultiDocTemplate 클래스를 생성할 때 4개의 인자가 필요하다. 첫번째 인자는 현 클래스의 형
태 이름을 설정하는 리소스의 String Table ID이고, 두 번째는 도큐먼트 클래스, 3번째는 프
레임 클래스, 4번째는 View 클래스이다. AppWizard를 실행시키면 자동으로 만들어진 3개의 클
래스를 CWinApp 클래스에 등록시켜 놓는다. 다음은 이 메인 프레임에 해당하는 메뉴와 정보를
등록한다.
// MDI 프레임을 만들기 위해서 CMainFrame 형태의 가상 pMainFrame을 새로 만들고
//여기에 IDR_MAINFRAME 형태인 틀로써 형성시키고 이것을 이 프로그램의
// m_pMainWnd(메인 윈도우 변수)에 연결시킨다.
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
m_pMainWnd = pMainFrame;
다음은 도스 창에서 프로그램을 실행시켰을 경우나 또는 DDE(Dynamic Data Exchange)나 파일
설정 등으로 실행했을 때 이 프로그램에 넘겨주는 인자를 받는 내용이다.
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
위의 내용은 CCommandLineInfo라는 클래스 변수 cmdInfo를 만들고 현재 프로그램이 실행
되면서 어떤 인자가 들어왔나 조사하기 위한 ParseCommandLine라는 함수를 실행하는 것이
다. 또한 AddDocTemplate 함수를 이용하여 여러 개의 Doc와 View와 Frame이 연결된 템플리트
를 만들어 등록하였을 경우에도 cmdInfo 안에 이 정보가 들어간다. 다음 내용은 이 정보를 실행
시키는 것이다.
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
ProceShellCommand 함수가 실행되면서 OnFileNew()라는 함수가 실행된다. 이 함수가 실행되면
MDI일 경우 자식 윈도우의 프레임과 도큐먼트 그리고 View가 만들어진다. 이제 이렇게 하여 모
든 정보를 등록시킨 후 기본적인 메인 프레임을 화면에 보여준다.
// The main window has been initialized, so show and update it.
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
위의 내용을 정리한다면 이 프로그램이 실행되면서 필요한 부속 윈도우를 프레임과 View Doc와
함께 등록시키고 다음 메인 프레임을 만들어서 등록하고 이 메인 프레임을 출력하는 것이다. 이
항목으로 간단히 말해서 메인 프레임을 화면에 출력하는 때까지 이루어졌다고 보면 된다.
이제 메인 프레임이 만들어졌으니 메인 프레임 소스를 조사해 보자.
CMainFrame 클래스
이제 mainfrm.cpp를 열어 봅시다.
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the Classwizard will add and remove
mapping macros here.
// DO NOT EDIT what you see in these blocks
of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
다음의 indicators는 상태창에 써지는 string의 ID이다. 윈도우 하단부에 작은 상태바를 놔두고 파
일 메뉴에 마우스가 위치하면 “새로운 파일을 열거나 닫습니다”라는 메시지, 즉 도움말이 나타
나는데 그 외 필요한 몇 가지를 설정한다는 것이다. ID_SEPARATOR란 라인을 그어서 분리시
키고 ID_INDICATOR_CAPS란 CapsLock키의 설정을 확인할 것, ID_INDICATOR_NUM은
NumLock키가 눌려있나를 확인할 것, ID_INDICATOR_SCRL이란 ScrollLock키가 눌려 있
나를 확인하라는 ID이다. 프로그램을 실행시켜 놓고 위 3개의 키를 눌러보면 현재 설정된 모습
이 상태창 오른쪽에 나타날 것이다. .
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
메인 프레임의 생성자. 현재는 비어 있는 상태.
CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
메인 프레임의 소멸자.
CMainFrame::~CMainFrame()
{
}
메인 프레임이 만들어질 때 실행되는 함수이다. 아버지 클래스인 CMDIFrameWnd 것을 사용하지
않고 자기 것, 즉 virtual로 사용한다는 것이다.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
//아버지 클래스의 OnCreate를 먼저 실행하고
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
//도구바를 만들고
if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0(failed to create toolbar\nO);
return -1; // fail to create
}
//상태창을 만들고
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))
{
TRACE0(?ailed to create status bar\nO);
return -1; // fail to create
}
// TODO: Delete these three lines if you don? want the toolbar to
// be dockable
//도구바가 분리 도킹을 원하면 아래 함수를 써 주고 그렇지 않으면 지우라는 말이다.
//demo1.exe를 실행시켜서 마우스로 도구바를 눌러서 움직여 보면 따로 떨어지는 것을
//볼 수 있다.
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY);
return 0;
}
CWinApp 클래스에서 CMainFrame 프로그램이 실행할 수 있도록 프레임을 로드한다.
CMainFrame의 OnCreate 함수는 CWinApp의 InitInstance 함수 안의
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))가 실행되면 후에 수행되는 함수이다.
CWinApp 클래스에서 메인 프레임을 만들면 CMainFramw의 OnCreate 함수가 실행되는 것이다.
OnCreate 함수는 메인 프레임이 만들 때 필요한 여러 정보를 수행하는 함수이다. 위의 내용은 메
인 프레임에 함께 있는 메뉴와 도구바 그리고 상태창 등을 메인 프레임에 등록하는 것을 하는 것
이다. 지금까지 내용으로 CWinApp 클래스에서 메인 프레임을 만들고 메인 프레임을 담당하는
CMainFrame에서 도구바와 메뉴와 상태바를 등록하는 것까지 보았다. 이제 실제적으로 필요한
View와 Document가 어떻게 기록되어 있는가를 보겠다.
CDocument 클래스
DEMO1Doc.cpp 안에 설정되어 있는 CDEMO1Doc 클래스는 CDocument 클래스를 상속받은 것이
다. 이 부분은 데이터를 저장하는 곳이다. 소스를 한 번 보고 전에 설명했으므로 넘어가겠다.
BEGIN_MESSAGE_MAP(CDEMO1Doc, CDocument)
//{{AFX_MSG_MAP(CDEMO1Doc)
// NOTE - the Classwizard will add and remove
mapping macros here.
// DO NOT EDIT what you see in these blocks
of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
생성자.
CDEMO1Doc::CDEMO1Doc()
{
// TODO: add one-time construction code here
}
소멸자.
CDEMO1Doc::~CDEMO1Doc()
{
}
OnNewDocument 함수는 파일 new를 실행하거나 OnFileNew() 함수를 실행하여서 새로운 파일
이 탄생될 때 실행해 주는 함수이다. 지금 현재는 아무것도 없이 아버지 클래스인 CDocument의
OnNewDosument만 실행한다.
BOOL CDEMO1Doc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
Serialize는 메모리에 있는 데이터를 디스크와 연결시켜 주는 함수이다. 간단히 말해서 데이터를
파일로 저장하고 저장된 데이터를 불러오는 함수이다.
void CDEMO1Doc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// 파일로 저장할 때
}
else
{
// 파일에서 불러올 때
}
}
CView 클래스
활성화되어 있는 윈도우의 화면에 보이는 것을 기록하는 클래스이다. CDEMO1View란 클래스로
CView 클래스를 상속받은 것이다. 이것은 DEMO1View.cpp에 설정되어 있다.
메시지 매핑
BEGIN_MESSAGE_MAP(CDEMO1View, CView)
//{{AFX_MSG_MAP(CDEMO1View)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
생성자 함수
CDEMO1View::CDEMO1View()
{
// TODO: add construction code here
}
소멸자 함수
CDEMO1View::~CDEMO1View()
{
}
함수 OnDraw 안에 화면에 뿌려 주는 여러 기능을 넣으면 화면에 뿌려진다. 화면에 출력할 여러
정보는 전에 말했듯이 도큐먼트에 저장한다고 하였다. 따라서 데이터는 도큐먼트에서 받아온다.
void CDEMO1View::OnDraw(CDC* pDC)
{
그래서 아래와 같이 일단 도큐먼트와 연결을 한다. CDEMO1Doc* pDoc = GetDocument(); 그
리고 ASSERT_VALID라는 함수는 pDoc가 활성화되어 있는 것을 보증하라는 말이다. 프로그
램이 돌다가 컴퓨터가 이상해져서 링크가 안 되어 도큐먼트를 받지 못하면 pDoc가 null값이 될
것이다. 이렇게 되면 ‘응용 프로그램 에러’라는 메시지를 내보내고 프로그램을 종료하라는 말
이 된다.
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
프린팅 미리 보기를 실행하는 함수이다. 이 함수는 파일 메뉴에서 Print 항목을 실행시키면 수행
된다.
BOOL CDEMO1View::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
//프린팅하는 함수
void CDEMO1View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
//프린팅이 끝났을 때 사용하는 함수
void CDEMO1View::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
지금까지의 내용으로 MFC에서 만들어진 4개의 클래스에 대해서 다시 한 번 정리하면 먼저
CWinApp 클래스가 먼저 실행하여 메인 프레임을 만들고(LoadFrame) 메인 프레임을 담당하는
CMainFrame 클래스가 수행되면서 메뉴와 도구바, 상태바를 결합하고 CWinApp 클래스에서 다시
View와 Document를 만든다. (ProcessShellCommand) 이렇게 하여 CView와 CDocument 클래스 인 CDEMO1View와 CDEMO1Document가 수행되는 것이다.
'MFC' 카테고리의 다른 글
스레드 정리 잘 된 글 2 (1) | 2008.09.03 |
---|---|
스레드 정리 잘 된 글 (0) | 2008.09.03 |
MFC에 고유의 명령(Command) 메시지 특징 (0) | 2008.09.02 |
DEBUG_NEW 간단한 이해 윈도우 프로그래밍 (0) | 2008.09.02 |
MFC 객체간 통신 방법 (0) | 2008.09.02 |
RTTI의 이해 (0) | 2008.09.02 |
MFC 프로그램의 흐름 살펴보기 - 인터널 (1) | 2008.09.01 |