5 장 MFC 기반다지기 김성영교수 금오공과대학교 컴퓨터공학부
들어가기 (1) pp.132 ~ 138 비주얼스튜디오에서 MFC 어플리케이션작성 참조 시스템메뉴 메뉴 최소 / 최대 / 닫기버튼 툴바 대화상자 클라이언트영역 (Client Area) 스크롤바 상태표시줄 2
들어가기 (2) 3
들어가기 (3) 4
들어가기 (4) 솔루션탐색기확인 WinMain() 함수가없다? MFC 프레임워크에대한이해가필요함 프로젝트를구성하는주요클래스는 4개로구성 4개의주요클래스및그부모클래스는무엇인가? 프로젝트에생성된클래스 C App CMainFrame C Doc C View 부모클래스 CWinApp CFrameWnd CDocument CView 5
MFC 프로그램시작 (1) 프로그래밍 주어진데이터를내가원하는데이터로만드는과정 ( 함수사용 ) 객체지향프로그래밍에서는 객체내부에변수와그값을변경하는함수가존재 개념적으로는객체만생성하면프로그래밍완성 관련 MFC클래스 : CWinApp, CFrameWnd, CView, CDocument 6
MFC 프로그램시작 (2) CWinApp: 프로그램구동 CView: 클라이언트윈도우처리 CFrameWnd: 프레임 ( 틀 ) 윈도우처리 CDocument: 데이터처리 C App theapp; //.h 에전역변수로선언 7
MFC 윈도우프로그래밍이란? MFC 프레임워크에서생성한기반클래스로부터상속한후변수와 함수를추가혹은재정의하여사용자클래스를작성하는것 8
기반클래스 CObject 파생클래스 : 188 개나머지 : 40 개 ( MFC 6.0 기준 ) 9
CWinApp ( 애플리케이션클래스 ) (1) CObject CCmdTarget CWinThread CWinApp 일부클래스를제외한모든클래스는 CObject 클래스로시작 CCmdTarget 클래스에서 WM_COMMAND 메시지처리 CWinApp 클래스에서도 WM_COMMAND 메시지처리가능 CWinApp 멤버변수 멤버함수 HINSTANCE m_hinstance CWnd* m_pmainwnd void InitInstance(); void Run(); void ExitInstance(); // 프로그램초기화 // 프로그램수행 // 프로그램종료 10
CWinApp ( 애플리케이션클래스 ) (2) My.cpp CMyApp theapp; BOOL CMyApp::InitInstance() {... } CMainFrame::CMainFrame() {... } void CMainFrame::OnPaint() {... } void CMainFrame::OnLButtonDown() {... } MFC 라이브러리내부코드 int WINAPI WinMain(... ) // 내부에숨겨진프로그램실행시작점 { ptr =...; // 응용프로그램객체의주소값으로변수 ptr 초기화... ptr->initinstance(); // 초기화 : 각종초기화작업과더불어 // 메인윈도우객체생성 // 메인윈도우객체의생성자에서 // 운영체제수준의실제윈도우를만든다. }... ptr->run(); // 메시지루프 : 메시지큐에서메시지를꺼내처리 // 메인윈도우가받은메시지의종류에따라 // 해당메시지핸들러가적절히호출된다.... ptr->exitinstance(); // 종료 : 각종청소작업수행... 11
CWinApp ( 애플리케이션클래스 ) (3) CWinApp 프로그램시작 InitInstance( ) 무한루프 Run( ) ExitInstance( ) 프로그램종료 12
CWinApp ( 애플리케이션클래스 ) (4) CWinApp 프로그램시작 상속 CMyApp InitInstance( ) InitInstance( ) 무한루프 Run( ) ExitInstance( ) 프로그램종료 13
CWinApp ( 애플리케이션클래스 ) (5) CWinApp 프로그램시작 상속 CMyApp InitInstance( ) InitInstance( ) 무한루프 Run( ) ExitInstance( ) ExitInstance( ) 프로그램종료 14
CWnd ( 윈도우클래스 ) CObject CCmdTarget CWnd CMainFrame 클래스와 CView 클래스의부모클래스 윈도우에대한클래스 멤버변수로 HWND 타입의변수를가짐 CWnd 멤버변수 멤버함수 HWND m_hwnd 첫번째인자로 HWND 를갖는모든 API 함수 메시지핸들러 15
메시지핸들러 WndProc(... ) { switch( msg ) { case WM_LBUTTONDOWN: MessageBox( hwnd, " 안녕하세요 ", " 인사 ", MB_OK ); break;... } } CWnd 클래스에서는 WM_LBUTTONDOWN 등의메시지에대한처 리기능을하나의멤버함수로제공 메시지핸들러 WM_CREATE OnCreate(... ) WM_LBUTTONDOWN OnLButtonDown(... ) 16
메시지맵 (1) class A { int d; int show() { cout << "A"; }; } class B: public A { int show() { cout << "B"; }; } void main() { A* pa; B b; pa = &b; // 형-변환은필요없음 pa->show(); // 출력결과는? } 17
메시지맵 (2) B 를출력하려면 class A { int d; int show() { cout << "A"; }; } class B: public A { int show() { cout << "B"; }; } 클래스 B 의메모리크기 (sizeof(b)) 확인 18
메시지맵 (3) 클래스 A 에 virtual 함수를하나더추가하여클래스 B 의크기확인? class A { int d; virtual int show() { cout << "A"; }; virtual int draw() { cout << "A"; }; } class B: public A { int show() { cout << "B"; }; } 19
메시지맵 (4) 변수 b 의메모리크기 (8) 가상함수테이블 vtable 을가리키는포인터 vptr(4) + 정수변수 d(4) 가상함수테이블의크기는 virtual 함수의증가에따라 4 바이트 ( 가상함수의주소 ) 씩증가 가삼함수테이블의함수주소는실행시간에결정 동적바인딩 (dynamic binding) 20
메시지맵 (5) 메시지핸들러는반드시가상함수이어야함 - CWnd 클래스상속받아메시지핸들러재정의 - 재정의한핸들러가호출되도록하기위해가상함수필요 문제점 - 가상함수테이블의크기가늘어남 - 모든메시지핸들러를가상함수로선언할경우메모리낭비 - 가상함수테이블관리필요 메시지맵 DECLARE_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() 21
CFrameWnd ( 프레임윈도우클래스 ) CObject CCmdTarget CWnd CFrameWnd WM_COMMAND 메시지처리가능 자식윈도우를만들수있는토대마련 멤버함수 OnCreate() PreCreateWindow() CFrameWnd // WM_CREATE 메시지핸들러 // 윈도우생성옵션지정 afx_msg int OnCreate( LPCREATESTRUCT lpcreatestruct ); WM_CREATE 메시지핸들러에서자식윈도우생성 virtual Bool PreCreateWindow( CREATESTRUCT & CS ); 윈도우클래스정의부분의일부를처리 22
CView ( 뷰클래스 ) CObject CCmdTarget CWnd CView WM_COMMAND 메시지처리 화면출력에대한함수제공 데이터를저장하는도큐먼트클래스에대한접근함수제공 뷰초기화함수제공 멤버함수 CView OnDraw() GetDocument() OnInitialUpdate() // 화면출력 // 도큐먼트객체의주소획득 // 뷰초기화 23
CDocument ( 도큐먼트클래스 ) CObject CCmdTarget CDocument WM_COMMAND 메시지처리 데이터처리를위해파일처리와관련된함수제공 뷰에게데이터변경을통보하는함수제공 객체의재생성없이초기화하는함수제공 CDocument 멤버함수 OnOpenDocumnet() OnCloseDocument() OnSaveDocument() UpdateAllViews() OnNewDocument() Seriallize() // 문서열기 // 문서닫기 // 문서저장 // 화면갱신공지 // 문서초기화 // 시리얼라이제이션 (serialization) 24
초기화멤버함수들 클래스 CWinApp CFrameWnd CView CDocumnet CDialog 초기화함수 InitInstance() OnCreate() OnInitialUpdate() OnNewDocument() OnInitDialog() 객체가만들어질때생성자다음으로자동으로호출되는함수 CFrameWnd 클래스의 OnCreate() 핸들러는초기화를위해정의된것은아니지만초기화작업에적합 CDialog 클래스의 OnInitDialog() 는대화상자윈도우에서초기화를위해발생시키는 WM_INITDIALOG 메시지에대한핸들러 25
윈도우의개수는? 프로그램실행화면의윈도우개수는? 윈도우 = HWND 1 1 개 2 2 개 3 3 개 4 4 개 5 그이상 26
CWnd HWND m_hwnd CMainFrame C View 프레임윈도우 클라이언트윈도우 (CMainFrame 클래스윈도우의자식윈도우 - WS_CHILD 속성을가짐 ) 27
Cobject CCmdTarget CWnd CControlBar CToolBar/CStatusBar CToolBar 와 CStatusBar 도 CWnd 클래스를상속받았으므로윈도우 CMainFrame CToolBar CMyView CStatuslBar 28
실습 5.1 툴바및상태바를제거하자. 29
실습 5.2 메뉴를제거하자. 30
윈도우클래스정의 WNDCLASS WndClass; char szappname[] ="This program is to create window"; WndClass.style = NULL; WndClass.lpfnWndProc = WndProc; WndClass.cbClsExtra = 0; WndClass.cbWndExtra = 0; WndClass.hInstance = hinstance; WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClass.lpszMenuName = NULL; WndClass.lpszClassName = szappname; MFC 프로그램에서도윈도우가생성되기전에메뉴필드를 NULL 로처리하면메뉴를없앨수있다! 31
윈도우메시지처리는어디에서? 프로젝트를구성하는네개의클래스중에서 WM_LBUTTONDOWN 메시지를처리할수있는클래스는 어느것인가? 다음보기에서모두고르시오. 1 C App 2 CMainFrame 3 C Doc 4 C View 32
Lab. 다음의요구사항을만족하는윈도우를생성하자. 프레임윈도우의시스템메뉴제거 초기윈도우의크기를 500x300으로지정 클라이언트영역에서의커서의모양이십자형이되도록지정 클라이언트영역의색상을파란색으로출력 힌트 : CreateSolidBrush( ) 함수사용 33