2.44k likes | 3.11k Views
Visual C++. 0. C++ Review. DrawOb j. int a. virtual Draw(). Point. Line. int x, y. Point start, end. virtual Draw(). virtual Draw() virtual Calc(). PolyLine. Point[5] pt. virtual Draw(). Virtual Function. 동적 바인딩 (dynamic binding) 프로그램의 수행 중에 실제 수행할 함수를 결정
E N D
DrawObj int a virtual Draw() Point Line int x, y Point start, end virtual Draw() virtual Draw() virtual Calc() PolyLine Point[5] pt virtual Draw() Virtual Function • 동적 바인딩(dynamic binding) • 프로그램의 수행 중에 실제 수행할 함수를 결정 • Virtual function table(hidden pointer) • vs. 정적 바인딩(static binding) DrawObj* p_obj; p_obj = new Point; p_obj->Draw(); p_obj = new Line; p_obj->Draw(); p_obj = new PolyLine; p_obj->Draw();
Virtual Function - 메모리 구조 p_obj = new PolyLine; p_obj->Draw(); p_obj = new DrawObj; p_obj->Draw(); 50 250 100 350 430 vtbl 50 vtbl 180 virtual function table int a int a 180 550 430 int x int y p_obj = new Line; p_obj->Draw(); Point start 250 DrawObj::Draw Point end pointer of virtual function table 350 vtbl 100 Point[0] pt Line::Draw int a Point[1] pt 430 Line::Calc int x Point[2] pt int y Point[3] pt Point start Point[4] pt 550 PolyLine::Draw Point end Code 영역
Why MFC? • 이해가 쉬움 • 연관된 함수와 데이타를 “클래스”를 이용하여 그룹화하였음 • 코드의 재사용성 향상 • 소프트웨어 개발의 용이성 • 애플리케이션 프레임워크(application framework) 제공 • 멤버 함수 나열 • 코드 삽입의 용이성 응용프로그램 MFC SDK API 운영체제
Introducing MFC • MFC Design Philosophy • MFC should provide an object-oriented interface to the Windows operating system that supports reusability, self-containment, and other tenets of OOP. • It should do so without imposing undue overhead on the system or unnecessarily adding to an application's memory requirements. • Document/View Architecture • MFC Class Hierarchy • Serialization support • Run-time class information support • Diagnostic and debugging support • AFX Functions
Commonly Used AFX Functions • AfxAbort Unconditionally terminates an application; usually called when an unrecoverable error occurs • AfxBeginThread Creates a new thread and begins executing it • AfxEndThread Terminates the thread that is currently executing • AfxMessageBox Displays a Windows message box • AfxGetApp Returns a pointer to the application object • AfxGetAppName Returns the name of the application • AfxGetMainWnd Returns a pointer to the application's main window • AfxGetInstanceHandle Returns a handle identifying the current application instance • AfxRegisterWndClass Registers a custom WNDCLASS for an MFC application
AFX Classes • 어플리케이션 프로그램을 구성하는 오브젝트 단위로 분할 • 분리된 오브젝트는 철저하게 역할을 분담 • 프레임 윈도우와 뷰를 분리 • 도큐먼트와 뷰를 분리
나머지 클래스들 • 그래픽 관련 클래스 • 자료 구조 클래스 • 파일 및 데이터베이스 관련 클래스 • 인터넷 관련 클래스 • OLE 관련 클래스 • 에러 처리 및 디버깅을 위한 클래스
Hello, MFC • The Hello window program
Hello.h class CMyApp : public CWinApp { public: virtual BOOL InitInstance (); }; class CMainWindow : public CFrameWnd { public: CMainWindow (); protected: afx_msg void OnPaint (); DECLARE_MESSAGE_MAP () };
Hello.cpp #include <afxwin.h> #include "Hello.h" CMyApp myApp; // CMyApp member functions BOOL CMyApp::InitInstance () { m_pMainWnd = new CMainWindow; m_pMainWnd->ShowWindow (m_nCmdShow); m_pMainWnd->UpdateWindow (); return TRUE; } BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd) ON_WM_PAINT () END_MESSAGE_MAP () CMainWindow::CMainWindow () { Create (NULL, _T ("The Hello Application")); } void CMainWindow::OnPaint () { CPaintDC dc (this); CRect rect; GetClientRect (&rect); dc.DrawText (_T ("Hello, MFC"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); }
프로그램의 뼈대 만들기 • AppWiard가 해 주는 일 • MFC의 AFX 클래스에서 상속을 받아 그림 1과 같이 네 개의 클래스를 생성 • 상속 받은 클래스에는 MFC의 막강한 기능들이 상속
CWinApp 클래스 • CWinApp 클래스의 역할 • 프로그램의 시작과 종료를 담당 • 프로그램이 시작될 때, 메인 프레임 윈도우를 생성 • 무한루프를 돌면서 메시지를 뿌려줌 • WM_QUIT 메시지를 만나면 무한루프를 빠져 나옴 • 프로그램을 전체를 대표하는 기능들을 수행 • CMyApp 클래스의 인스턴스가 유일하게 전역변수로 선언
CWinApp 클래스 • 인스턴스가 생성되면서 다음 그림 멤버 함수를 차례로 호출 • AfxGetApp – 프로그램 객체 포인터 반환 • AfxWinInit – hInstance, nCmdShow 등을 멤버변수에 복사 • InitApplication, InitInstance – 프로그램 초기화 • Run – 메시지 루프 • ExitInstance – WinMain으로 돌아감 • AfxWinTerm – 프로그램 종료
CWinApp 클래스 • “stdafx.h”는 “Standard Application Frameworks”의 약자 • AFX 클래스인 도큐먼트 클래스, 프레임 윈도우 클래스, 뷰 클래스를 엮어서 등록하는 루틴 class CMyApp : public CWinApp { // …… // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMyApp) public: virtual BOOL InitInstance(); virtual int ExitInstance(); //}}AFX_VIRTUAL // …… };
CWinApp 클래스 • 도큐먼트 클래스, 프레임 윈도우 클래스, 뷰 클래스로 각각 CMyDoc, CMainFrame, CMyView 클래스를 사용할 것임을 명시 • 위 정보를 CSingleDocTemplate 클래스에 설정한 후 CWinApp 클래스의 멤버 함수인 AddDocTemplate 함수를 호출하여 CWinApp 클래스와 연결 • CMyApp theApp; • BOOL CMyApp::InitInstance() • { • CSingleDocTemplate* pDocTemplate; • pDocTemplate = new CSingleDocTemplate( • IDR_MAINFRAME, • RUNTIME_CLASS(CMyDoc), • RUNTIME_CLASS(CMainFrame), • RUNTIME_CLASS(CMyView)); • AddDocTemplate(pDocTemplate); • return TRUE; • }
CWnd 클래스 • 메시지 핸들러 함수 • 윈도우의 크기, 위치, 모양, 상태 등을 제어하기 위한 기능을 제공 • 메시지 핸들러-윈도우에서 발생하는 메시지를 처리
메시지 핸들러 호출의 원리 • 이벤트가 발생 윈도우 운영체제가 감지 프로그램의 메시지 큐에 적재 메시지 핸들로 호출
윈도우 메시지에 대응 int CMyWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { CWnd::OnCreate(lpCreateStruct); // 여기에 수행 하고자 하는 기능을 넣으면 됩니다. }
메시지 맵 • 가상 함수 • 바인딩 될 함수로 점프할 번지를 저장하기 위해 4바이트 짜리 포인터가 필요 • CWnd 클래스의 메시지 핸들러 함수가 약 200개 이를 모두 가상 함수로 선언하면 약 800바이트의 메모리가 더 필요 • 프레임 윈도우,뷰 윈도우, 툴바, 상태바, 다이얼로그 박스, 각종 컨트롤 등 수십 개의 윈도우가 생성 • 메시지 맵 • 파생 클래스의 메시지 핸들러 함수를 여기에 등록하면 기반 클래스의 함수를 무시하고, 파생 클래스의 함수를 호출하는 매크로
CFrameWnd 클래스 • 일반적인 윈도우로서의 역할 • 프레임 윈도우도 일종의 윈도우 • 프레임 윈도우로서의 고유한 역할 • 윈도우의 크기, 위치, 상태 등의 조절에 관한 일과 같은 윈도우로서의 역할 • 툴바와 상태바를 다는 것은 CFrameWnd 클래스에서 상속을 받은 파생 클래스에서 추가 • OnCreate 함수를 오버라이딩 하고, 그 함수 안에다가 툴바와 상태바를 생성시켜 메다는 기능을 추가 • 오버라이딩 된 OnCreate 함수에서 기반 클래스의 OnCreate 함수를 반드시 호출 int CMyWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { CWnd::OnCreate(lpCreateStruct); // 여기에 수행 하고자 하는 기능을 넣으면 됩니다. }
CFrameWnd 클래스 • afx_msg : virtual 대신 오버라이딩 된 함수임을 나타내기 위해 사용 class CMainFrame : public CFrameWnd { // …… // Generated message map functions protected: //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); //}}AFX_MSG DECLARE_MESSAGE_MAP() };
CView 클래스 • 일반적인 윈도우로서의 역할 • CView 클래스는 프레임 윈도우의 클라이언트 영역 전체를 덮고 있는 윈도우인 뷰라는 오브젝트를 클래스로 구현한 것 • 뷰 윈도우로서의 고유한 역할 • 프로그램에서 다루는 데이터를 보여줌 class CMyView : public CView { public: CMyDoc* GetDocument( ); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMyView) public: virtual void OnDraw(CDC* pDC); // overridden to draw this view protected: virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); //}}AFX_VIRTUAL };
CView 클래스 • GetDocument() • 도큐먼트 오브젝트의 포인터를 얻는 함수 • OnDraw() • 각각 도큐먼트에서 데이터를 가져와 그리는 기능을 수행하는 함수 • OnXXXPrinting() • 프린터 출력에 관한 함수
CDocument클래스 • CDocument 클래스의 역할 • 파일로부터 데이터를 읽어오는 기능 (“파일” 메뉴의 “열기” 기능) • 파일에 데이터를 저장하는 기능 (“파일” 메뉴의 “저장” 기능) • 새로운 데이터를 만드는 기능 (“파일” 메뉴의 “새 파일” 기능) • 작업 중인 데이터를 닫는 기능 (“파일” 메뉴의 “닫기” 기능) • 데이터가 변경된 사실을 뷰 오브젝트에 알리는 기능 // MyDoc.h class CMyDoc : public CDocument { protected: // create from serialization only CMyDoc(); // Overrides public: virtual BOOL OnNewDocument(); // Implementation public: virtual ~CMyDoc(); };
Framework 클래스간 상호참조 • 전역함수 • CWinApp* AfxGetApp( ) • CWinApp 파생 클래스의 인스턴스 포인터를 반환 • 프로그램 상의 어디에서든 참조 가능 • CWnd* AfxGetMainWnd( ) • 메인 프레임 클래스의 인스턴스 포인터를 반환 • 프로그램 상의 어디에서든 참조 가능 • 프레임 윈도우 클래스에서 도큐먼트/뷰 참조 • virtual CDocument* GetActiveDocument( ) • 프레임 윈도우 클래스에서 도큐먼트 클래스를 참조 • CView* GetActiveView( ) const • 현재 프레임 윈도우와 연결된 뷰 클래스의 인스턴스 포인터를 반환
Framework 클래스간 상호참조 • 프레임 윈도우 클래스에서 도큐먼트/뷰 참조 • virtual CDocument* GetActiveDocument( ) • 현재 프레임 윈도우와 연결된 도큐먼트 클래스의 인스턴스 포인터를 반환 • CView* GetActiveView( ) const • 함수는 현재 프레임 윈도우와 연결된 뷰 클래스의 인스턴스 포인터를 반환 • 뷰 클래스에서 프레임 윈도우/도큐먼트 참조 • CFrameWnd* GetParentFrame( ) const • 뷰 클래스에서 그 뷰를 둘러싸고 있는 프레임 윈도우를 참조 • CDocument* GetDocument( ) const • 뷰 클래스에서 그 뷰와 연결된 도큐먼트 클래스를 참조
Framework 클래스간 상호참조 • 도큐먼트 클래스에서 뷰 참조 • CDocument::GetFirstViewPosition, GetNextView • 하나의 도큐먼트에 여러 개의 뷰가 결합 • 도큐먼트에는 이와 연결된 뷰가 연결 리스트 구조로 관리 • 도큐먼트 클래스에서 프레임 윈도우 참조 • SDI : AfxGetMainWnd 함수를 호출 • MDI : 뷰를 거쳐서 참조 POSITION pos = GetFirstViewPosition(); while (pos != NULL) { CView* pView = GetNextView(pos); pView->UpdateWindow(); }
메시지를 이용한 통신 • CWnd::SendMessage • 메시지가 메시지 큐를 거치지 않음 • CWnd::PostMessage • 메시지를 메시지 큐에 넣어줌 • CWinApp 클래스나 CDocument 파생 클래스에서는 XxxxMessage 함수 호출 불가능 • AfxGetMainWnd( )->XxxxMessage( …, …, …)
실습 • “Hello MFC” 프로그램 작성 • Project->Win32 Application • Project menu->settings(alt+F7)->general->Use MFC in a Shared DLL • Menu 달기 • System 메뉴없애기 • Minimize,Maximize 버튼 없애기 • 초기 윈도우 크기, 위치 바꾸기
Menu 편집 • 메뉴 항목을 선택하고, ID와 Caption을 편집
Loading and Displaying a Menu • 메뉴를 읽어들여 윈도우에 붙인다. • CFrameWnd::Create 함수에 메뉴의 ID를 전달 Create (NULL, _T ("My Application"), WS_OVERLAPPEDWINDOW, rectDefault, NULL, MAKEINTRESOURCE (IDR_MAINFRAME)); • CFrameWnd::LoadFrame 함수 호출 LoadFrame (IDR_MAINFRAME, WS_OVERLAPPEDWINDOW, NULL, NULL); • CMenu 객체 생성후 LoadMenu 호출 CMenu menu; menu.LoadMenu (IDR_MAINFRAME); SetMenu (&menu); menu.Detach ();
Menu 바꾸기 • CWnd::DrawMenuBar() • 윈도우가 생성된 이후에 메뉴를 다시 그려줌 Create (NULL, _T ("My Application")); m_menuLong.LoadMenu (IDR_LONGMENU); m_menuShort.LoadMenu (IDR_SHORTMENU); SetMenu (m_bShortMenu ? &m_menuShort : &m_menuLong); m_bShortMenu = TRUE; SetMenu (&m_menuShort); DrawMenuBar (); m_bShortMenu = FALSE; SetMenu (&m_menuLong); DrawMenuBar ();
Responding to Menu Commands • WM_COMMAND Message • wParam에 항목 ID 저장 • SDK에서는 switch-case 사용 • MFC에서는 ON_COMMAND 매크로 사용하여 메시지 맵 엔트리 작성 ON_COMMAND (ID_FILE_NEW, OnFileNew) ON_COMMAND (ID_FILE_OPEN, OnFileOpen) ON_COMMAND (ID_FILE_SAVE, OnFileSave) ON_COMMAND (ID_FILE_SAVE_AS, OnFileSaveAs) ON_COMMAND (ID_FILE_EXIT, OnFileExit) void CMainWindow::OnFileExit () { PostMessage (WM_CLOSE, 0, 0); }
Command Message • 프로그램 실행 중에 메뉴가 선택되면, WM_COMMAND 라는 윈도우 메시지가 발생 • 어떤 메뉴가 눌렸는지를 구별하기 위해 메뉴의 ID가 추가적인 정보로 전달 • 만일 OnCommand라는 메시지 핸들러에서 처리를 하면 할 일이 너무 많아짐
Command Message 전달 경로 • 일반적인 윈도우 메시지를 처리하는 기능은 CWnd 클래스 • CWnd 상위에 있는 클래스는 윈도우 메시지를 받는 기능이 없슴 • 사용자가 메뉴 항목을 선택하여 프로그램에 명령을 내리면 WM_COMMAND 메시지가 모든 AFX 클래스에 전달
Command Message 처리 • 프로그램의 데이터를 처리하는 기능 CDocument 파생 클래스 • 데이터를 화면에 표시하는 방법 CView 파생 클래스 • 프로그램의 시작과 종료에 관련된 커맨드 CWinApp 파생 클래스 • 프레임 윈도우의 제어에 관계된 커맨드를 처리 CFrameWnd 파생 클래스
Command Ranges // In CMainWindow's message map ON_COMMAND (ID_COLOR_RED, OnColorRed) ON_COMMAND (ID_COLOR_GREEN, OnColorGreen) ON_COMMAND (ID_COLOR_BLUE, OnColorBlue) void CMainWindow::OnColorRed () { m_nCurrentColor = 0; } void CMainWindow::OnColorGreen () { m_nCurrentColor = 1; } void CMainWindow::OnColorBlue () { m_nCurrentColor = 2; }
Command Ranges // In CMainWindow's message map ON_COMMAND (ID_COLOR_RED, OnColor) ON_COMMAND (ID_COLOR_GREEN, OnColor) ON_COMMAND (ID_COLOR_BLUE, OnColor) void CMainWindow::OnColor () { UINT nID = (UINT) LOWORD (GetCurrentMessage ()->wParam); //wParam 에 의존 m_nCurrentColor = nID; } // In CMainWindow's message map ON_COMMAND_RANGE (ID_COLOR_RED, ID_COLOR_BLUE, OnColor) void CMainWindow::OnColor (UINT nID) { m_nCurrentColor = nID; }
GDI • 그래픽 디바이스 인터페이스 (GDI: Graphic Device Interface) • 그래픽 기능과 관련해서 윈도우 운영체제가 어플리케이션 프로그램에 제공하는 모든 기능 • 디바이스 컨텍스트 (DC: Device Context) • 그래픽에 필요한 모든 옵션을 한곳에 모아둔 구조체 • GDI 오브젝트 (GDI Object) • 독립적으로 저장되는 각 범주의 그래픽 옵션
그래픽 관련 MFC 클래스 • CDC 클래스 • GDI 오브젝트를 통해 그래픽에 관련된 옵션을 저장 • 모든 그래픽 함수들은 CDC 클래스의 멤버 함수 • 하위 클래스 • CClientDC • CWindowDC • CPaintDC • CMetaFileDC CDC *pDC = GetDC(); pDC->Rectangle(10, 10, 100, 100); ReleaseDC(pDC);
CClientDC • CDC 클래스에서 상속 • 생성자 함수에서 GetDC를 호출 • 소멸자 함수에서 ReleaseDC를 호출 CClientDC dc(this); dc.Rectangle(10, 10, 100, 100);
GDI MFC 오브젝트 클래스 CPen 펜 ( ) CBrush 브러시 붓 CFont 글 꼴 CBitmap 비트맵 CPalette 팔레트 CRgn 영역 GDI 오브젝트 클래스 • 그래픽 옵션을 바꿔 주려면 새로운 설정을 갖는 GDI 오브젝트 클래스를 생성한 후에 이것을 DC에 넣고, 이 DC를 이용하여 그림을 그림