visual c++

244
1 Visual C++

Upload: adia

Post on 31-Jan-2016

280 views

Category:

Documents


2 download

DESCRIPTION

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) 프로그램의 수행 중에 실제 수행할 함수를 결정 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Visual C++

1

Visual C++

Page 2: Visual C++

2

0. C++ Review

Page 3: Visual C++

3

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

int a

virtual Draw()

DrawObj

int x, y

virtual Draw()

Point

Point start, end

virtual Draw()virtual Calc()

Line

Point[5] pt

virtual Draw()

PolyLine

Page 4: Visual C++

4

Virtual Function - 메모리 구조

p_obj = new DrawObj;p_obj->Draw();

p_obj = new Line;

p_obj->Draw();

p_obj = new PolyLine;

p_obj->Draw(); vtbl 50

vtbl 100

int a

int x

int y

Point start

Point end

vtbl 180

int a

int x

int y

Point start

Point end

Point[0] pt

int a

250

350430

550430

DrawObj::Draw

Line::Draw

Line::Calc

PolyLine::Draw

50

100

180

250

350

430

550

Code 영역

virtualfunctiontable

pointerofvirtualfunctiontable

Point[1] pt

Point[2] pt

Point[3] pt

Point[4] pt

Page 5: Visual C++

5

Why MFC?

이해가 쉬움 • 연관된 함수와 데이타를 “

클래스”를 이용하여 그룹화하였음

코드의 재사용성 향상 소프트웨어 개발의 용이성

• 애플리케이션 프레임워크 (application framework) 제공

• 멤버 함수 나열• 코드 삽입의 용이성

응용프로그램

MFC

SDK API

운영체제

Page 6: Visual C++

6

1. Hello, MFC

Page 7: Visual C++

7

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

Page 8: Visual C++

8

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 win

dow AfxGetInstanceHandle Returns a handle identifying the current

application instance AfxRegisterWndClass Registers a custom WNDCLASS for an MF

C application

Page 9: Visual C++

9

AFX Classes

어플리케이션 프로그램을 구성하는 오브젝트 단위로 분할 분리된 오브젝트는 철저하게 역할을 분담 프레임 윈도우와 뷰를 분리 도큐먼트와 뷰를 분리

C F ram eWnd C View C D oc um ent

( ) 윈 도 우 의 프 레 임 틀 을 관 리 데 이 터 를 보 여 주 는 윈 도 우 , 데 이 터 를 저 장 처 리( )눈 에 는 안 보 임

C WinApp

, ( )위 의 세 오 브 젝 트 를 묶 어 주 고 프 로 그 램 을 구 동 시 킴 눈 에 는 안 보 임

Page 10: Visual C++

10

AFX 클래스의 상속 관계

CCm dTarget

CW inApp

CDocum ent

CObject

CW nd

CFram eW nd

CView

M F C 거 의 모 든 클 래 스 의 기 반 클 래 스

커 맨 드 메 세 지 를 받 는 기 능

프 로 그 램 을 구 동 시 키 는 기 능

데 이 터 를 저 장 하 고 처 리 하 는 기 능

( )윈 도 우 에 관 련 된 기 능 눈 에 보 이 는 오 브 젝 트

( ) 프 로 그 램 윈 도 우 프 레 임 외 곽 을 관 리 하 는 기 능

데 이 터 를 보 여 주 는 윈 도 우 관 리 하 는 기 능

CObject

CW nd

CFram eW nd

CView

CSplitterW nd

CControlBar

CPropertySheet

CPropertyPage

COlePropertyPage

CDialog

각 종 컨 트 롤 클 래 스 들

M F C 거 의 모 든 클 래 스 의 기 반 클 래 스

모 든 윈 도 우 관 련 클 래 스 의 기 반 클 래 스

프 레 임 윈 도 우 관 련 클 래 스 의 기 반 클 래 스

뷰 관 련 클 래 스 의 기 반 클 래 스

다 이 얼 로 그 박 스 관 련 클 래 스 의 기 반 클 래 스

분 할 윈 도 우 클 래 스

컨 트 롤 바 관 련 클 래 스 의 기 반 클 래 스

프 로 퍼 티 시 트 클 래 스

프 로 퍼 티 페 이 지 클 래 스

OL E 프 로 퍼 티 페 이 지 클 래 스

Page 11: Visual C++

11

나머지 클래스들 그래픽 관련 클래스 자료 구조 클래스 파일 및 데이터베이스 관련 클래스 인터넷 관련 클래스 OLE 관련 클래스 에러 처리 및 디버깅을 위한 클래스

Page 12: Visual C++

12

Hello, MFC

The Hello window program

Page 13: Visual C++

13

Hello.h

class CMyApp : public CWinApp{public: virtual BOOL InitInstance ();};

class CMainWindow : public CFrameWnd{public: CMainWindow ();

protected: afx_msg void OnPaint (); DECLARE_MESSAGE_MAP ()};

Page 14: Visual C++

14

Hello.cpp

#include <afxwin.h>#include "Hello.h"CMyApp myApp;// CMyApp member functionsBOOL 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);}

Page 15: Visual C++

15

프로그램의 뼈대 만들기 AppWiard 가 해 주는 일

• MFC 의 AFX 클래스에서 상속을 받아 그림 1 과 같이 네 개의 클래스를 생성

• 상속 받은 클래스에는 MFC 의 막강한 기능들이 상속

CCm dTarget

CW inApp

CDocum ent

CObject

CW nd

CFram eW nd

CView

CMyApp

CMyDoc

CMainFram e

CMyView

M F C 기 반 클 래 스 파 생 클 래 스

Page 16: Visual C++

16

CWinApp 클래스

CWinApp 클래스의 역할• 프로그램의 시작과 종료를 담당• 프로그램이 시작될 때 , 메인 프레임 윈도우를 생성• 무한루프를 돌면서 메시지를 뿌려줌• WM_QUIT 메시지를 만나면 무한루프를 빠져 나옴• 프로그램을 전체를 대표하는 기능들을 수행

CMyApp 클래스의 인스턴스가 유일하게 전역변수로 선언

Page 17: Visual C++

17

CWinApp 클래스

인스턴스가 생성되면서 다음 그림 멤버 함수를 차례로 호출• AfxGetApp – 프로그램 객체 포인터 반환• AfxWinInit – hInstance, nCmdShow 등을 멤버변수에 복사• InitApplication, InitInstance – 프로그램 초기화• Run – 메시지 루프• ExitInstance – WinMain 으로 돌아감• AfxWinTerm – 프로그램 종료

C W inApp

프 로 그 램 시 작

In itIns tance ( )

R un( )

E xitIns tance ( )

무 한 루 프

프 로 그 램 종 료

C W inApp

프 로 그 램 시 작

In itIns tance ( )

R un( )

E xitIns tance ( )

프 로 그 램 종 료

C M yApp

In itIns tance ( )

무 한 루 프

E xitIns tance ( )

상속

Page 18: Visual C++

18

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 // ……};

Page 19: Visual C++

19

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;}

Page 20: Visual C++

20

CWnd 클래스

메시지 핸들러 함수•윈도우의 크기 , 위치 , 모양 , 상태 등을 제어하기 위한 기능을 제공 •메시지 핸들러 - 윈도우에서 발생하는 메시지를 처리

윈도우 메시지 메시지 핸들러 함수

WM_CREATE OnCreate

WM_ACTIVATE OnActivate

WM_PAINT OnPaint

WM_MOUSEMOVE OnMouseMove

WM_DESTROY OnDestroy

WM_LBUTTONDOWN OnLButtonDown

WM_LBUTTONUP OnLButtonUp

WM_LBUTTONDBLCLK OnLButtonDblClk

WM_KEYDOWN OnKeyDown

WM_KEYUP OnKeyUp

WM_SIZE OnSize

WM_MOVE OnMove

WM_TIMER OnTimer

WM_COMMAND 다른 방식으로 처리됨

Page 21: Visual C++

21

메시지 핸들러 호출의 원리

이벤트가 발생 윈도우 운영체제가 감지 프로그램의 메시지 큐에 적재 메시지 핸들로 호출

W M _PAIN T

W M _M O U SEM O VE

W M _C R EAT E

W M _AC T IVATE

메 시 지 큐

윈 도 우 운 영 체 제

C W inApp::R un( ){ while(m sg != W M _Q U IT ) { sw itch (m sg) { case W M _C R EAT E: O nC reate( ); break ; case W M _AC T IVATE: O nActivate( ); break ; case W M _PAIN T : O nPaint( ); break ; ..... }}

차 례 로 꺼 내 서 처 리 함

메 시 지

Page 22: Visual C++

22

윈도우 메시지에 대응

OnCreate

WM_CREATE

CWnd

OnActivate

OnKeyDown

WM_ACTIVATE

WM_KEYDOWN

OnCreate

WM_CREATE

OnActivate

OnKeyDown

WM_ACTIVATE

WM_KEYDOWN

OnCreate

OnKeyDown

CWnd CMyWnd

int CMyWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){

CWnd::OnCreate(lpCreateStruct);// 여기에 수행 하고자 하는 기능을 넣으면 됩니다 .

}

Page 23: Visual C++

23

메시지 맵 가상 함수

• 바인딩 될 함수로 점프할 번지를 저장하기 위해 4 바이트 짜리 포인터가 필요

• CWnd 클래스의 메시지 핸들러 함수가 약 200 개 이를 모두 가상 함수로 선언하면 약 800 바이트의 메모리가 더 필요

• 프레임 윈도우 , 뷰 윈도우 , 툴바 , 상태바 , 다이얼로그 박스 , 각종 컨트롤 등 수십 개의 윈도우가 생성

메시지 맵• 파생 클래스의 메시지 핸들러 함수를 여기에 등록하면 기반

클래스의 함수를 무시하고 , 파생 클래스의 함수를 호출하는 매크로

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)

ON_WM_MOUSEMOVE()

ON_WM_CREATE()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

CFrameWnd 에서 상속 받은CMainFrame 클래스의 메시지 맵 임을 나타냄

메시지 맵의 시작을 나타냄

메시지 맵의 끝을 나타냄

ClassWizard .가 파싱하는 부분 ClassWizard 이 부분은 에 의해

자동으로 관리됨

OnMouseMove 함수 오버라이딩OnCreate 함수 오버라이딩

Page 24: Visual C++

24

CFrameWnd 클래스

일반적인 윈도우로서의 역할• 프레임 윈도우도 일종의 윈도우

프레임 윈도우로서의 고유한 역할• 윈도우의 크기 , 위치 , 상태 등의 조절에 관한 일과 같은

윈도우로서의 역할 • 툴바와 상태바를 다는 것은 CFrameWnd 클래스에서 상속을 받은

파생 클래스에서 추가• OnCreate 함수를 오버라이딩 하고 , 그 함수 안에다가 툴바와

상태바를 생성시켜 메다는 기능을 추가• 오버라이딩 된 OnCreate 함수에서 기반 클래스의 OnCreate

함수를 반드시 호출

int CMyWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){ CWnd::OnCreate(lpCreateStruct); // 여기에 수행 하고자 하는 기능을 넣으면 됩니다 .}

Page 25: Visual C++

25

CFrameWnd 클래스

afx_msg : virtual 대신 오버라이딩 된 함수임을 나타내기 위해 사용

class CMainFrame : public CFrameWnd{// ……// Generated message map functionsprotected: //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized); //}}AFX_MSG DECLARE_MESSAGE_MAP()};

Page 26: Visual C++

26

AFX 전체구조CF rameW nd

CW inA pp

CDocument

CV iew

CM y A pp ( )클 래 스 의 인 스 턴 스 전 역 변 수

protected/pr ivate 멤 버

멤 버 함 수

멤 버 변 수

Page 27: Visual C++

27

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 viewprotected: virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); //}}AFX_VIRTUAL};

Page 28: Visual C++

28

CView 클래스

GetDocument()• 도큐먼트 오브젝트의 포인터를 얻는 함수

OnDraw()• 각각 도큐먼트에서 데이터를 가져와 그리는 기능을 수행하는

함수 OnXXXPrinting()

• 프린터 출력에 관한 함수

Page 29: Visual C++

29

CDocument 클래스

CDocument 클래스의 역할• 파일로부터 데이터를 읽어오는 기능 (“ 파일” 메뉴의 “열기” 기능 )• 파일에 데이터를 저장하는 기능 (“ 파일” 메뉴의 “저장” 기능 )• 새로운 데이터를 만드는 기능 (“ 파일” 메뉴의 “새 파일” 기능 )• 작업 중인 데이터를 닫는 기능 (“ 파일” 메뉴의 “닫기” 기능 )• 데이터가 변경된 사실을 뷰 오브젝트에 알리는 기능

// MyDoc.hclass CMyDoc : public CDocument{protected: // create from serialization only CMyDoc();// Overrides public: virtual BOOL OnNewDocument();// Implementationpublic: virtual ~CMyDoc();};

Page 30: Visual C++

30

Framework 클래스간 상호참조

CFrameWnd

CDocument CView

GetActiveDocument

GetFirstViewPositionGetNextView

GetParentFrame

GetActiveView

GetDocument

AfxGetApp

AfxGetMainWnd

Page 31: Visual C++

31

Framework 클래스간 상호참조 전역함수

• CWinApp* AfxGetApp( ) CWinApp 파생 클래스의 인스턴스 포인터를 반환 프로그램 상의 어디에서든 참조 가능

• CWnd* AfxGetMainWnd( ) 메인 프레임 클래스의 인스턴스 포인터를 반환 프로그램 상의 어디에서든 참조 가능

프레임 윈도우 클래스에서 도큐먼트 / 뷰 참조• virtual CDocument* GetActiveDocument( )

프레임 윈도우 클래스에서 도큐먼트 클래스를 참조• CView* GetActiveView( ) const

현재 프레임 윈도우와 연결된 뷰 클래스의 인스턴스 포인터를 반환

Page 32: Visual C++

32

Framework 클래스간 상호참조 프레임 윈도우 클래스에서 도큐먼트 / 뷰 참조

• virtual CDocument* GetActiveDocument( ) 현재 프레임 윈도우와 연결된 도큐먼트 클래스의 인스턴스 포인터를

반환• CView* GetActiveView( ) const

함수는 현재 프레임 윈도우와 연결된 뷰 클래스의 인스턴스 포인터를 반환

뷰 클래스에서 프레임 윈도우 / 도큐먼트 참조• CFrameWnd* GetParentFrame( ) const

뷰 클래스에서 그 뷰를 둘러싸고 있는 프레임 윈도우를 참조• CDocument* GetDocument( ) const

뷰 클래스에서 그 뷰와 연결된 도큐먼트 클래스를 참조

Page 33: Visual C++

33

Framework 클래스간 상호참조 도큐먼트 클래스에서 뷰 참조

• CDocument::GetFirstViewPosition, GetNextView 하나의 도큐먼트에 여러 개의 뷰가 결합 도큐먼트에는 이와 연결된 뷰가 연결 리스트 구조로 관리

도큐먼트 클래스에서 프레임 윈도우 참조 • SDI : AfxGetMainWnd 함수를 호출• MDI : 뷰를 거쳐서 참조

POSITION pos = GetFirstViewPosition();

while (pos != NULL)

{

CView* pView = GetNextView(pos);

pView->UpdateWindow();

}

Page 34: Visual C++

34

메시지를 이용한 통신 CWnd::SendMessage

• 메시지가 메시지 큐를 거치지 않음 CWnd::PostMessage

• 메시지를 메시지 큐에 넣어줌

CWinApp 클래스나 CDocument 파생 클래스에서는 XxxxMessage 함수 호출 불가능

AfxGetMainWnd( )->XxxxMessage( …, …, …)

Page 35: Visual C++

35

실습 “Hello MFC” 프로그램 작성

• Project->Win32 Application• Project menu->settings(alt+F7)->general->Use MFC in a Shared D

LL Menu 달기 System 메뉴없애기 Minimize,Maximize 버튼 없애기 초기 윈도우 크기 , 위치 바꾸기

Page 36: Visual C++

36

2. Menu

Page 37: Visual C++

37

Menu 편집 메뉴 항목을 선택하고 , ID 와 Caption 을 편집

선택된 메뉴 항목

ID선택된 메뉴 항목의

메뉴에 실제 출력될 문자열

Page 38: Visual C++

38

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, NU

LL);

CMenu 객체 생성후 LoadMenu 호출CMenu menu;menu.LoadMenu (IDR_MAINFRAME);SetMenu (&menu); menu.Detach ();

Page 39: Visual C++

39

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

Page 40: Visual C++

40

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

}

Page 41: Visual C++

41

Command Message

프로그램 실행 중에 메뉴가 선택되면 , WM_COMMAND 라는 윈도우 메시지가 발생

어떤 메뉴가 눌렸는지를 구별하기 위해 메뉴의 ID 가 추가적인 정보로 전달

만일 OnCommand 라는 메시지 핸들러에서 처리를 하면 할 일이 너무 많아짐

Page 42: Visual C++

42

Command Message 전달 경로 일반적인 윈도우 메시지를 처리하는 기능은 CWnd 클래스 CWnd 상위에 있는 클래스는 윈도우 메시지를 받는 기능이

없슴 사용자가 메뉴 항목을 선택하여 프로그램에 명령을 내리면 W

M_COMMAND 메시지가 모든 AFX 클래스에 전달

CCm dTarget

CW inApp

CDocum ent

CObject

CW nd

CFram eW nd

CView

M F C 거 의 모 든 클 래 스 의 기 반 클 래 스

커 맨 드 메 세 지 를 받 는 기 능

프 로 그 램 을 구 동 시 키 는 기 능

데 이 터 를 저 장 하 고 처 리 하 는 기 능

( )윈 도 우 에 관 련 된 기 능 눈 에 보 이 는 오 브 젝 트

( ) 프 로 그 램 윈 도 우 프 레 임 외 곽 을 관 리 하 는 기 능

데 이 터 를 보 여 주 는 윈 도 우 관 리 하 는 기 능

Page 43: Visual C++

43

Command Message 처리 프로그램의 데이터를 처리하는 기능 CDocument 파생

클래스 데이터를 화면에 표시하는 방법 CView 파생 클래스 프로그램의 시작과 종료에 관련된 커맨드 CWinApp 파생

클래스 프레임 윈도우의 제어에 관계된 커맨드를 처리 CFrameWnd

파생 클래스

CView 파생 클래스

CDocum ent 파생 클래스

CFram eW nd 파생 클래스

CW inApp 파생 클래스

W M_COMMAND 메시지 전달 순서

Page 44: Visual C++

44

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;

}

Page 45: Visual C++

45

Command Ranges

// In CMainWindow's message map

ON_COMMAND_RANGE (ID_COLOR_RED, ID_COLOR_BLUE, OnColor)

void CMainWindow::OnColor (UINT nID)

{

m_nCurrentColor = nID;

}

// 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;

}

Page 46: Visual C++

46

3. Graphic Device Interface

Page 47: Visual C++

47

GDI

그래픽 디바이스 인터페이스 (GDI: Graphic Device Interface)• 그래픽 기능과 관련해서 윈도우 운영체제가 어플리케이션

프로그램에 제공하는 모든 기능 디바이스 컨텍스트 (DC: Device Context)

• 그래픽에 필요한 모든 옵션을 한곳에 모아둔 구조체 GDI 오브젝트 (GDI Object)

• 독립적으로 저장되는 각 범주의 그래픽 옵션 범주 GDI 오브젝트 기본값

선 그리기 옵션 펜 (Pen) 1 픽셀 굵기의 검은색 실선

영역의 내부를 채우

는 옵션 브러시 ( Brush) 단일 흰색 브러시

글꼴 옵션 글꼴 (Font) 시스템 글꼴

비트맵 옵션 비트맵 (Bitmap) 없음

팔레트 옵션 팔레트 (Palette) 없음

영역 옵션 영역 (Region) 없음

Page 48: Visual C++

48

그래픽 관련 MFC 클래스 CDC 클래스

• GDI 오브젝트를 통해 그래픽에 관련된 옵션을 저장 • 모든 그래픽 함수들은 CDC 클래스의 멤버 함수

• 하위 클래스 CClientDC CWindowDC CPaintDC CMetaFileDC

CDC *pDC = GetDC();

pDC->Rectangle(10, 10, 100, 100);

ReleaseDC(pDC);

Page 49: Visual C++

49

CClientDC

CDC 클래스에서 상속 생성자 함수에서 GetDC 를 호출 소멸자 함수에서 ReleaseDC 를 호출

CClientDC dc(this);

dc.Rectangle(10, 10, 100, 100);

1윈도우

2윈도우

DC1

DC2

DC1.Rectangle(10, 10, 100, 100)

DC2.Rectangle(200, 200, 300, 300)

DC화면의

DC프린터의

DC플로터의

DC모뎀의

DC.Rectangle(10, 10, 100,100);

Page 50: Visual C++

50

GDI 오브젝트 클래스 그래픽 옵션을 바꿔 주려면 새로운 설정을 갖는 GDI 오브젝트

클래스를 생성한 후에 이것을 DC 에 넣고 , 이 DC 를 이용하여 그림을 그림

GDI 오브젝트 MFC 클래스

펜 CPen

브러시 ( 붓) CBrush

글꼴 CFont

비트맵 CBitmap

팔레트 CPalette

영역 CRgn

Page 51: Visual C++

51

펜과 브러시 펜과 브러시를 이용한 그래픽

• 현재 DC 에 설정되어 있는 펜을 이용하여 경계선을 그림• 폐곡선일 경우 안쪽을 현재 DC 에 설정되어 있는 브러시로 채움

함수 그리기 기능

MoveTo, LineTo 선

Rectangle, FillRect, FrameRect, Draw3dRect 사각형

Ellipse 타원

Pie 파이

Arc, ArcTo, AngleArc, Chord 호

Polygon 다각형

PolyDraw, PolyBezier, PolyBezierTo 베지어 곡선

FrameRgn 영역의 경계선

Page 52: Visual C++

52

그래픽 옵션 바꾸기 펜 생성 예제

CPen pen;

pen.CreatePen(PS_SOLID, 3, RGB(255, 0, 0));

CClinetDC dc(this);

dc.SelectObject(&pen);

dc.Rectangle(10, 10, 100, 100);

PS_SOLID

PS_DASH

PS_DOT

PS_DASHDOT

PS_DASHDOTDOT

PS_NULL

PS_INSIDEFRAME PS_INSIDEFRAME

반지름 반지름

PS_SOLID

어떤 문제가 존재 ?

Page 53: Visual C++

53

그래픽 옵션 바꾸기 새로운 펜으로 선택하고 되돌리지 않으면 함수가 종료되는

순간에 DC 에 저장되어 있던 펜 오브젝트는 파괴 SelectObject 함수의 리턴값으로 넘어오는 GDI 오브젝트 저장

CPen pen;

pen.CreatePen(PS_SOLID, 3, RGB(255, 0, 0));

CClinetDC dc(this);

CPen *pOldPen = (CPen *)dc.SelectObject(&pen);

dc.Rectangle(10, 10, 100, 100);

dc.SelectObject(pOldPen);

Page 54: Visual C++

54

내장 (Stock) GDI 오브젝트 자주 쓰이는 스타일의 GDI 오브젝트는 윈도우 운영체제가

내장 GetStockObject 함수 사용

내장 오브젝트는 항상 메모리에 상주

CClientDC dc;

dc.SelectObject( GetStockObject(WHITE_PEN) );

Page 55: Visual C++

55

실습 튀는 공 예제 프로그램

Page 56: Visual C++

56

레스터 오퍼레이션

새로 그릴 그림과 기존에 그려져 있는 그림을 합성 int SetROP2( int nDrawMode )

• R2_COPYPEN 새로이 그려지는 그림으로 화면에 덮어 그림

• R2_XORPEN 배경을 깨뜨리지 않고 , 배경 위에서 움직이는 그림을 그릴 때 사용 똑같은 그림을 두 번 그려주면 원래 있던 바탕색이 복원

바탕색 출력되는 색

흰색 새로 그려진 색이 반전되어 출력됩니다.

검정색 새로 그려진 색이 그대로 출력됩니다.

임의의 색 새로 그려진 색과 바탕색이 XOR 연산되어 출력되는데,

이 값은 바탕색과 새로 그려진 색 양쪽과 모두 무관한

엉뚱한 색이 됩니다.

Page 57: Visual C++

57

실습 마우스를 드래그 해서 선을 그릴 수 있는 프로그램

Page 58: Visual C++

58

4. Dialog Box and Controls

Page 59: Visual C++

59

다이얼로그 박스 프로그램 수행 도중 사용자의 입력이 필요할 때 다이얼로그

박스 출력 다이얼로그 박스는 사용자로부터 입력 받은 데이터를 메인

루틴에 넘기고 소멸 다이얼로그 템플릿

• 다이얼로그 박스가 생성될 때 사용될 다이얼로그 박스의 모양에 대한 설계도

• 리소스 파일에 저장

Page 60: Visual C++

60

다이얼로그 박스 속성 설정 Caption: 항목에는 다이얼로그 박스의 타이틀 Font : 다이얼로그에서 사용하는 글꼴 설정 Styles : 다이얼로그 박스의 스타일 설정

Page 61: Visual C++

61

다이얼로그 박스 클래스 CWnd 클래스 상속

• CWnd 클래스에 있는 윈도우를 제어 기능 함수와 윈도우 메시지 핸들러 함수를 모두 이용

CDialog 클래스를 상속을 받아서 사용• cf) 컨트롤은 MFC 클래스를 그대로 사용

CObject

CWnd

CDialog

Page 62: Visual C++

62

다이얼로그 박스 만들기 (1/2)

CDialog 파생 클래스 만들기

class CNameDlg : public CDialog

{

//…

enum { IDD = IDD_DIALOG1 };

//…

};

Page 63: Visual C++

63

다이얼로그 박스 만들기 (2/2)

CDialog 파생 클래스의 인스턴스 만들어 사용하기 사용자의 입력을 받는 일은 다이얼로그 박스에 일임

#include “NameDlg.h”

 

void CDlgTestView::OnDialog( )

{

CNameDlg dlg; // CDialog 파생 클래스의 인스턴스를 생성

dlg.DoModal( ); // CDialog 클래스의 멤버 함수를 호출

// 다이얼로그 박스에서 입력 받은 값을 이용하는 루틴…

}

Page 64: Visual C++

64

CDialog 클래스의 기능

다이얼로그 박스와 컨트롤의 생성 메시지 핸들러 함수 커맨드 메시지 핸들러 함수 다이얼로그 박스는 확인 (OK) 버튼과 취소 (Cancel) 버튼과

각각의 메시지 핸들러를 가지고 있슴 #include “NameDlg.h”

 

void CDlgTestView::OnDialog( )

{

CNameDlg dlg;

if( dlg.DoModal( ) == IDOK)

{

// OK 버튼이 눌렸을 때만 실행되는 부분

// 다이얼로그 박스에서 입력 받은 값을 이용하는 루틴…

}

}

Page 65: Visual C++

65

CDialog 파생 클래스에 추가해야 하는 기능

사용자가 컨트롤에 입력한 내용을 관리• 사용자의 입력 내용을 컨트롤로부터 획득

컨트롤 자체를 하나의 윈도우로 보고 제어• Show/Hide• 활성화 / 비활성화

Page 66: Visual C++

66

Value 형 멤버변수 컨트롤에 입력된 값과 연결된 CDialog 파생 클래스의 멤버

변수 MFC 는 컨트롤과 변수를 연결하여 컨트롤에 입력된 값을

변수에 저장 변수에 설정된 값을 컨트롤에 입력하는 것을 자동으로 수행

다이얼로그 박스

홍길동

28

:이름

:나이

OK Cancel

CString m_strName

int m_nAge

CDialog ÆÄ»ý Ŭ·¡½º

Value Çü ¸â¹ö º¯¼ö

Page 67: Visual C++

67

컨트롤과 Value 형 멤버 변수 연결 다이얼로그 템플릿에서 Value 형 멤버 변수와 연결시키려는

컨트롤을 선택 [Ctrl] 키를 누른 상태에서 마우스 버튼을 더블 클릭

변수형을 선택

Page 68: Visual C++

68

컨트롤과 Value 형 멤버 변수 연결 코드의 변화

class CNameDlg : public CDialog

{

//…

//{{AFX_DATA(CNameDlg)

enum { IDD = IDD_DIALOG1 };

CString m_strName;

int m_nAge;

//}}AFX_DATA

//…

};

CNameDlg::CNameDlg(CWnd* pParent /*=NULL*/)

: CDialog(CNameDlg::IDD, pParent)

{

//{{AFX_DATA_INIT(CNameDlg)

m_strName = _T("");

m_nAge = 0;

//}}AFX_DATA_INIT

}

void CNameDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CNameDlg)

DDX_Text(pDX, IDC_EDIT1, m_strName);

DDX_Text(pDX, IDC_EDIT2, m_nAge);

//}}AFX_DATA_MAP

}

Page 69: Visual C++

69

컨트롤과 Value 형 멤버 변수 사이의 데이터 전송 UpdateData 함수를 이용한 데이터 전송

CDialog 클래스에서 기본적으로 호출하고 있는 UpdateData 함수 • 다이얼로그 박스 시작 시 UpdateData(FALSE) 호출 • 다이얼로그 박스 종료 시 UpdateData(TRUE) 호출

값이 확인 (OK) 버튼이 눌려지는 순간에 Value 형 멤버 변수에 저장

다이얼로그 박스

일지매

20

:이름

:나이

OK Cancel

컨트롤

int m_nAge;

CString m_strName;

Value 형 멤버 변수

UpdateData(TRUE)

UpdateData(FALSE)

Page 70: Visual C++

70

입력된 값의 유효성 검사 사용자 입력의 유효성 검사의 필요성 유효성 검사의 자동화

void CNameDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CNameDlg)

DDX_Text(pDX, IDC_EDIT1, m_strName);

DDV_MaxChars(pDX, m_strName, 10);

DDX_Text(pDX, IDC_EDIT2, m_nAge);

DDV_MinMaxInt(pDX, m_nAge, 0, 100);

//}}AFX_DATA_MAP

}

Page 71: Visual C++

71

받을 문자열의 최대 길이를 지정

Page 72: Visual C++

72

유효한 입력의 범위 설정 유효한 입력의 범위를 최대값 (Maximum Value) 과 최소값 (Mini

mum Value) 으로 설정

Page 73: Visual C++

73

UpdateData 함수의 동작 과정

UpdateData 함수는 내부적으로 DoDataExchange 함수를 호출

void CNameDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CNameDlg)

DDX_Text(pDX, IDC_EDIT1, m_strName);

DDV_MaxChars(pDX, m_strName, 10);

DDX_Text(pDX, IDC_EDIT2, m_nAge);

DDV_MinMaxInt(pDX, m_nAge, 0, 100);

//}}AFX_DATA_MAP

}

Page 74: Visual C++

74

UpdateData 함수의 동작 과정

UpdateData(TRUE)1. DoDataExchang 함수가 호출2. DDV_ 로 시작되는 함수들이 호출3. DDX_ 로 시작하는 함수들이 호출

UpdateData(FALSE)1. DoDataExchang 함수가 호출 2. DDX_ 로 시작하는 함수들이 호출

Page 75: Visual C++

75

컨트롤에 따른 Value 형 멤버 변수 편집 박스 컨트롤 CStiring,int,UINT,long,DWORD,float,double,B

YTE,short,BOOL,COleDateTime,COleCurrency 리스트 박스 컨트롤과 콤보 박스 컨트롤

• CString 체크 박스 컨트롤

• BOOL

Page 76: Visual C++

76

컨트롤에 따른 Value 형 멤버 변수 라디오 버튼 컨트롤

• Group 속성을 가진 라디오 버튼 컨트롤에서부터 다음 Group 속성을 가진 라디오 버튼 컨트롤까지가 하나의 범주

• Group 속성을 가진 컨트롤이 대표로 Value 형 멤버 변수와 연결• int

Page 77: Visual C++

77

Control 형 멤버 변수 MFC 에는 모든 컨트롤들이 클래스로 구성 컨트롤을 Control 형 멤버 변수와 연결하여 제어 모든 컨트롤 클래스의 기반 클래스는 CWnd

Page 78: Visual C++

78

CWnd 클래스

Create• 윈도우를 생성

ShowWindow• SW_SHOW ,SW_HIDE

EnableWindow• 윈도우를 활성화 시키거나 비활성화 시킴

SetWindowPos• 윈도우의 크기와 위치를 변경

SetWindowText• 윈도우의 메인 텍스트를 변경

Page 79: Visual C++

79

CEdit 클래스

GetSel• 선택된 부분의 문자열을 얻어옴

SetSel• 특정 부분을 선택 영역으로 설정

ReplaceSel• 선택된 부분의 텍스트를 지정한 텍스트로 치환

GetLineCount• 편집 박스의 텍스트의 줄 수 반환

GetLine• 지정된 라인의 텍스트를 얻어옴

Page 80: Visual C++

80

CButton 클래스

푸시 버튼 , 체크 박스 버튼 , 라디오 버튼 GetCheck

• 버튼이 눌려진 상태를 얻어옴 SetCheck

• 버튼의 눌려짐 상태를 설정

Page 81: Visual C++

81

CScrollBar 클래스

GetScrollRange• 스크롤바 컨트롤의 증감범위 반환

SetScrollRange• 스크롤바 컨트롤의 증감범위 설정

GetScrollPos• 스크롤바 컨트롤에 현재 설정된 값 반환

SetScrollPos• 스크롤바 컨트롤에 값 설정

Page 82: Visual C++

82

CListBox 클래스와 CComboBox 클래스

GetCount • 컨트롤에 들어있는 총 문자열의 수를 반환

GetCurSel, SetCurSel• 선택된 문자열의 인덱스 반환하거나 설정• 인덱스는 0 부터 시작

AddString, InsertString• 문자열을 추가

DeleteString,ResetContent• 문자열을 삭제

Dir

Page 83: Visual C++

83

컨트롤의 제어 WM_INITDIALOG 메시지 (OnInitDialog 메시지 핸들러 함수 )

• 컨트롤의 초기화 루틴은 여기 들어간다 . 통지 (NOTIFICATION) 메시지

• 통지 메시지는 컨트롤에 발생한 사건을 알려주기 위해 그 컨트롤을 품고 있는 부모 윈도우인 다이얼로그 박스로 메시지를 보냄

통지 메시지의 전달• 통지 메시지는 다이얼로그로 전달이 된다 .

Page 84: Visual C++

84

Notification Message

Button• BN_CLICKED, BN_DBLCLK

Edit Box• EN_CHANGE, EN_SETFOCUS, EN_KILLFOCUS

List Box• LBN_DBLCLK, LBN_SELCHANGE, LBN_SETFOCUS,

LBN_KILLFOCUS Combo Box

• CBN_DBLCLK, CBN_SELCHANGE, CBN_SETFOCUS, CBN_KILLFOCUS, CBN_EDITCHAGE

Page 85: Visual C++

85

모달리스 다이얼로그 박스

모달 다이얼로그 박스• 다이얼로그 박스가 출력되어 있는 동안에는 그 다이얼로그

박스가 프로그램의 모든 제어권을 독점 모달리스 다이얼로그 박스

• 다이얼로그 박스가 프로그램의 제어권을 독점하지 않음

모달 모달리스

생성 방법 DoModal 함수 Create 함수

종료 방법 EndDialog 함수 DestroyWindow 함수

인스턴스 선언 지역 변수로 선언 동적으로 할당

Page 86: Visual C++

86

생성 방법 Modal Dialog

• DoModal 함수로 생성• 다이얼로그 박스가 종료되면 각각 IDOK 또는 IDCANCEL

Modaless Dialog• Create 멤버 함수를 호출하여 생성• 모달리스 다이얼로그 박스를 생성시킨 후 바로 리턴

Page 87: Visual C++

87

종료 방법 Modal Dialog

• EndDialog 함수 호출• OnOK 멤버 함수에서는 EndDialog(IDOK) 가 호출• OnCancel 멤버 함수에서는 EndDialog(IDCANCEL) 가 호출

Modaless Dialog• EndDialog 함수를 호출 금지• DestroyWindow 함수를 이용하여 종료• OnOK 함수나 OnCancel 함수를 오버라이딩시 CDialog 클래스의

OnOK 함수나 OnCancel 함수가 호출되지 않도록 주의

Page 88: Visual C++

88

인스턴스 생성

class CModalessDlg; // CModalessDlg 클래스를 사용할 것임을 선언

class CMainFrame : public CFrameWnd

{

//…

CModalessDlg *m_pDlg;

//…

}

 

#include “ModalessDlg.h”

void CMainFrame::OnModaless()

{

m_pDlg = new CModalessDlg;

m_pDlg->Create(this);

}

#include “ModalDlg.h”

 

void CMainFrame::OnModal()

{

CModalDlg dlg;

dlg.DoModal();

}

Page 89: Visual C++

89

class CModalessDlg : public CDialog

{

BOOL Create(CWnd* pParentWnd);

BOOL CModalessDlg::Create(CWnd* pParentWnd)

{

return CDialog::Create(IDD, pParentWnd);

}

void CModalessDlg::OnClose()

{

DestroyWindow();

}

void CModalessDlg::PostNcDestroy()

{

((CMainFrame *)AfxGetMainWnd())->m_pDlg = NULL;

delete this;

}

Page 90: Visual C++

90

class CMainFrame : public CFrameWnd

{

CModalessDlg *m_pDlg;

};

void CMainFrame::OnModaless()

{

if(m_pDlg != NULL) {

// 다이얼로그 박스가 이미 출력되어 있는 경우

m_pDlg->SetFocus();

}

else{

// 다이얼로그 박스가 출력되어 있지 않은 경우

m_pDlg = new CModalessDlg;

m_pDlg->Create(this);

m_pDlg->ShowWindow(SW_SHOW);

}

}

Page 91: Visual C++

91

다이얼로그 박스 기반 어플리케이션

Page 92: Visual C++

92

다이얼로그 박스 기반 어플리케이션 CWinApp 파생 클래스와 CDialog 파생 클래스 만으로 구성

BOOL CDlgAppApp::InitInstance()

{

//…

CDlgAppDlg dlg;

m_pMainWnd = &dlg;

int nResponse = dlg.DoModal();

//…

return FALSE;

}

Page 93: Visual C++

93

5. 사용자 인터페이스

Page 94: Visual C++

94

메인 프레임 윈도우에 메뉴 표시  BOOL CCmdUIApp::InitInstance( )

{

//…

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CCmdUIDoc),

RUNTIME_CLASS(CCmdUIView),

RUNTIME_CLASS(CMainFrame));

AddDocTemplate(pDocTemplate);

//…

}

Page 95: Visual C++

95

다이얼로그 박스에 메뉴 표시

Page 96: Visual C++

96

컨텍스트 메뉴

void CContextMenuView::OnContextMenu(CWnd* pWnd, CPoint point)

{

CMenu muTemp, *pContextMenu;

 

muTemp.LoadMenu(IDR_MAINFRAME);

pContextMenu = muTemp.GetSubMenu(0);

pContextMenu->TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, AfxGetMainWnd());

}

BOOL TrackPopupMenu(UINT nFlags, int x,int y ,CWnd* pWnd ,LPCRECT lp

Rect = NULL); nFlag - TPM_CENTERALIGN,TPM_LEFTALIGN,TPM_RIGHTALIGN , TPM_LE

FTBUTTON , TPM_RIGHTBUTTON x , y – 컨텍스트 메뉴가 표시될 좌표 pWnd – 메뉴를 소유할 윈도우 lpRect – 클릭하면 컨텍스트 메뉴를 사라지게 할 영역

Page 97: Visual C++

97

단축키 정의 Resource Accelerator

Page 98: Visual C++

98

단축키가 정의된 커맨드의 메뉴 캡션 “ 새 파일 (&N)\tCtrl+N” , “\t” 뒤에 씌여진 문자열은 메뉴의 우측에 정렬 &N 은 사용자가 alt 키를 사용하여 메뉴접근시의 단축키

Page 99: Visual C++

99

사용자 인터페이스 갱신 핸들러

ON_UPDATE_COMMAND_UI 는 사용자 인터페이스의 갱신에 관련된 작업을 수행하기 위한 매크로

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)

ON_UPDATE_COMMAND_UI (ID_RED, OnUpdateColor)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

void CMainFrame::OnUpdateColor(CCmdUI* pCmdUI)

{

 

}

Page 100: Visual C++

100

ON_UPDATE_COMMAND_UI_RANGE 매크로

ID_RED 부터 ID_YELLOW 까지 커맨드 ID 를 갖는 사용자 인터페이스의 갱신에 대 한 모든 제어는 OnUpdateColor 함수에서 일괄 처리

ON_UPDATE_COMMAND_UI_RANGE 는 ClassWizard 에 서 지원하지 않음

BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)//{{AFX_MSG_MAP(CMainFrame)//}}AFX_MSG_MAP 단축키 정의 ON_UPDATE_COMMAND_UI_RANGE(ID_RED, ID_YELLOW,

OnUpdateColor)END_MESSAGE_MAP() void CMainFrame::OnUpdateColor(CCmdUI* pCmdUI) { }

Page 101: Visual C++

101

CCmdUI 클래스

CCmdUI 클래스는 사용자 인터페이스 갱신과 관련된 기능을 담당하는 클래스

m_nID : command ID

멤버 함수 기능

Enable BOOL 형 인자를 받아, 사용자 인터페이스를 활성화

또는 비활성화 시킵니다.

SetText 사용자 인터페이스의 텍스트를 변경시켜 줍니다.

SetCheck int 형 인자를 받아, 체크 표시를 하거나 체크 표시를

없앱니다.

SetRadio SetCheck 함수와 비슷한 기능을 하나, 체크 표시를 점

으로 찍어 줍니다.

Page 102: Visual C++

102

CCmdUI::Enable 함수 메뉴를 활성화 / 비활성화 시킴

BEGIN_MESSAGE_MAP(CCmdUIView, CView)…ON_UPDATE_COMMAND_UI(ID_BEGIN, OnUpdateBegin)ON_UPDATE_COMMAND_UI(ID_END, OnUpdateEnd)

END_MESSAGE_MAP()void CCmdUIView::OnUpdateBegin(CCmdUI *pCmdUI){

pCmdUI->Enable(!m_bStart);}void CCmdUIView::OnUpdateEnd(CCmdUI *pCmdUI){

pCmdUI->Enable(m_bStart);}

Page 103: Visual C++

103

CCmdUI::SetText 함수

메뉴의 캡션 바꾸기

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)//{{AFX_MSG_MAP(CMainFrame)ON_COMMAND(IDM_BEGINEND, OnBeginend)ON_UPDATE_COMMAND_UI(IDM_BEGINEND,

OnUpdateBeginend)//}}AFX_MSG_MAP

END_MESSAGE_MAP() void CMainFrame::OnUpdateBeginend(CCmdUI* pCmdUI) {

if(m_bStart) pCmdUI->SetText(" 작업 중단 (&E)");else pCmdUI->SetText(" 작업 시작 (&S)");

}

Page 104: Visual C++

104

CCmdUI::SetCheck 함수void CMainFrame::OnColorRed() {

m_nColorCheck = LOWORD(GetCurrentMessage()->wParam);}void CMainFrame::OnColorBlue() {

m_nColorCheck = LOWORD(GetCurrentMessage()->wParam);}void CMainFrame::OnUpdateColorRed(CCmdUI* pCmdUI) {

if (pCmdUI->m_nID == m_nColorCheck)pCmdUI->SetCheck(TRUE);

elsepCmdUI->SetCheck(FALSE);

}void CMainFrame::OnUpdateColorBlue(CCmdUI* pCmdUI) {

if (pCmdUI->m_nID == m_nColorCheck)pCmdUI->SetCheck(TRUE);

elsepCmdUI->SetCheck(FALSE);

}

Page 105: Visual C++

105

CCmdUI::SetCheck 함수

메뉴에 체크표시

class CMainFrame : public CFrameWnd{

//…UINT m_nColorCheck;//…

} CMainFrame::CMainFrame(){

m_nColorCheck = IDM_REDCHECK;} BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)ON_COMMAND_RANGE(IDM_REDCHECK, IDM_BLUECHECK, OnColorCheck)//}}AFX_MSG_MAP

END_MESSAGE_MAP() void CMainFrame::OnColorCheck(UINT nID) {

m_nColorCheck = nID; }

Page 106: Visual C++

106

CCmdUI::SetCheck 함수

일괄 처리 ON_UPDATE_COMMAND_UI_RANGE 매크로를 이용

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)//{{AFX_MSG_MAP(CMainFrame)ON_COMMAND_RANGE(IDM_REDCHECK, ON_UPDATE_COMMAND_UI_RANGE(IDM_REDCHECK,IDM_BLUECHECK, OnUpdateColorCheck)//}}AFX_MSG_MAP

END_MESSAGE_MAP() void CMainFrame::OnUpdateColorCheck(CCmdUI* pCmdUI) {

pCmdUI->SetCheck(m_nColorCheck == pCmdUI->m_nID); }

Page 107: Visual C++

107

CCmdUI::SetRadio 함수

SetCheck 와 동일

void CMainFrame::OnUpdateColorRadio(CCmdUI* pCmdUI)

{

pCmdUI->SetRadio(m_nColorRadio == pCmdUI->m_nID);

}

Page 108: Visual C++

108

툴바 생성

CToolBar 클래스 인스턴스 생성 Create, LoadToolBar 함수 호출

class CMainFrame : public CFrameWnd{

//…CToolBar m_wndToolBar;//…

}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)return -1;

m_wndToolBar.Create(this);m_wndToolBar.LoadToolBar(IDR_MAINFRAME);return 0;

}

Page 109: Visual C++

109

툴바 스타일 변경

툴바가 생성된 후 SetBarStyle() 멤버 함수를 호출 m_wndToolBar.GetBarStyle( ) 로 현재 설정되어 있는 스타일에

추가 가능m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |

CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

• CBRS_FLOAT_MULTI – 여러개의 툴바를 도킹• CBRS_SIZE_DYNAMIC – 사이즈 변환가능• CBRS_TOOLTIPS – 툴팁 도움말 표시• CBRS_FLYBY – 상태바에 도움말 표시• CBRS_GRIPPER – Gripper 추가

Page 110: Visual C++

110

플로팅 툴바 만들기

프레임 윈도우에서 분리될 수 있는 툴바 툴바와 프레임 윈도우 양쪽에서 모두 EnableDocking 함수를

호출 EnableDocking 함수로 도킹 스타일을 설정

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){

//…m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(&m_wndToolBar);return 0;

}

도킹 스타일• CBRS_ALIGN_TOP, CBRS_ALIGN_BOTTOM, CBRS_ALIGN_LEFT , CBR

S_ALIGN_RIGHT , CBRS_ALIGN_ANY

Page 111: Visual C++

111

텍스트가 표시된 툴바 만들기

SetButtonText int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

m_wndToolBar.SetButtonText(0, " 새파일 ");

m_wndToolBar.SetSizes(CSize(48, 32), CSize(16, 15));

return 0;

}

CreateEx 함수로 툴바를 생성시키면서 스타일을 설정m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | C

BRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC)

Page 112: Visual C++

112

다이얼로그 바 버튼 외의 다른 컨트롤들을 많이 사용해야 한다면 툴바보다

다이얼로그 바를 사용 컴포넌트 갤러리를 이용하여 다이얼로그 바 만들기

• Project – Add to project – Components and controls

Page 113: Visual C++

113

상태바

클래스 인스턴스 생성class CMainFrame : public CFrameWnd

{

//…

CStatusBar m_wndStatusBar;

//…

}

Create 로 생성후 SetIndicators 함수로 상태바를 팬으로 분할

프레임 윈도우

ID_SEPARATOR

ID_INDICATOR_CAPS

ID_INDICATOR_NUM

CAP SCRLNUM

ID_INDICATOR_SCRL

Page 114: Visual C++

114

상태바

static UINT indicators[] ={ID_SEPARATOR, // status line indicator

ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL,};

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

if (!m_wndStatusBar.Create(this) ||

!m_wndStatusBar.SetIndicators(indicators,

sizeof(indicators)/sizeof(UINT)))

{

TRACE0("Failed to create status bar\n");

return -1; // fail to create

}

m_wndStatusBar.SetPaneInfo(1, ID_SEPARATOR, SBPS_NOBORDERS, 200);

return 0;

}

Page 115: Visual C++

115

상태바 제어하기

팬 추가 • indicators 배열에 ID_SEPARATOR 를 하나 더 추가

팬 정보 변경m_wndStatusBar.SetPaneInfo(1, ID_SEPARATOR,SBPS_NORMAL, 200); • Index- 몇 번째 팬에 대한 정보를 설정할 것인지를 결정• nID - 팬에 어떤 정보를 표시할 지를 결정• nStyle - 팬의 스타일을 결정

SBPS_NOBORDERS,SBPS_POPOUT,SBPS_DISABLED,SBPS_STRETCH,SBPS_NORMAL

• cxWidth - 팬의 너비를 설정 상태바에 문자열 표시

• BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );

Page 116: Visual C++

116

실습 상태바에 현재 마우스의 위치 표시

Page 117: Visual C++

117

메시지 박스

int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK,

UINT nIDHelp = 0 ); 메시지 박스 스타일

• MB_ABORTRETRYIGNORE , MB_OK,MB_OKCANCEL,MB_RETRYCANCEL,MB_YESNO,MB_YESNOCANCEL

출력될 버튼 스타일

메시지 박스 스타일 출력되는 아이콘

MB_ICONEXCLAMATION

MB_ICONINFORMATION

MB_ICONQUESTION

MB_ICONSTOP

Page 118: Visual C++

118

메시지 박스 디폴트 버튼 설정

• MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON3 모달리티 설정

• MB_APPLMODAL • MB_SYSTEMMODAL

리턴값• IDABORT• IDCANCEL• IDIGNORE• IDNO• IDOK• IDRETRY• IDYES

Page 119: Visual C++

119

마우스커서 WM_SETCURSOR 메시지

• 마우스 커서가 윈도우 사이를 넘나들 때마다 발생 커서 로드

• HCURSOR CWinApp::LoadStandardCursor( LPCTSTR lpszCursorName ); • HCURSOR CWinApp::LoadCursor( LPCTSTR lpszResourceName ) const;• HCURSOR CWinApp::LoadCursor( UINT nIDResource ) const;

커서 설정• SetCursor 함수를 호출BOOL CCursorView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) {

HCURSOR hCursor;hCursor = AfxGetApp()->LoadStandardCursor(IDC_CROSS);SetCursor(hCursor);return TRUE;

} 주의 !) 기반클래스의 SetCursor 함수 호출 금지 !

Page 120: Visual C++

120

마우스커서 표준 커서 사용예

BOOL CCursorView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) {

HCURSOR hCursor;hCursor = AfxGetApp()->LoadStandardCursor(IDC_CROSS);SetCursor(hCursor);return TRUE;

}

모래시계 커서void Function( ){

BeginWaitCursor( );// 여기에 시간이 걸리는 작업을 넣습니다 .EndWaitCursor( );

}

Page 121: Visual C++

121

6. Control

Page 122: Visual C++

122

기본 트롤들

Control Type WNDCLASS MFC Class Buttons "BUTTON“ CButton List boxes "LISTBOX" CListBox Edit controls "EDIT" CEdit Combo boxes "COMBOBOX" CComboBox Scroll bars “SCROLLBAR“ CScrollBar Static controls "STATIC" CStatic

Page 123: Visual C++

123

Button

버튼의 생성CButton m_wndPushButton;m_wndPushButton.Create (_T ("Start"), WS_CHILD ¦ WS_VISIBLE ¦ B

S_PUSHBUTTON, rect, this, IDC_BUTTON);

Page 124: Visual C++

124

Button Style

BS_PUSHBUTTON - Creates a standard push button control BS_DEFPUSHBUTTON - Creates a default push button; used in dialog

boxes to identify the push button that's clicked if Enter is pressed BS_CHECKBOX - Creates a check box control BS_AUTOCHECKBOX - Creates a check box control that checks and u

nchecks itself when clicked BS_3STATE - Creates a three-state check box control BS_AUTO3STATE - Creates a three-state check box control that cycles

through three states—checked, unchecked, and indeterminate—when clicked

BS_RADIOBUTTON - Creates a radio button control BS_AUTORADIOBUTTON - Creates a radio button control that, when cli

cked, checks itself and unchecks other radio buttons in the group BS_GROUPBOX - Creates a group box control

Page 125: Visual C++

125

Push Button

BS_PUSHBUTTON 으로 설정 버튼 클릭시 WM_COMMAND 메시지 생성해서

부모윈도우에게 보냄 Notificatin 으로 BN_CLICKED 가 보내짐 BN_CLICKED 처리 메시지맵

ON_BN_CLICKED (IDC_BUTTON, OnButtonClicked) void CMainWindow::OnButtonClicked (){ MessageBox (_T ("I've been clicked!"));}

Page 126: Visual C++

126

Check Box

BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE, BS_AUTO3STATE 중 한가지 스타일로 생성

m_wndCheckBox.SetCheck (BST_CHECKED); // Check

m_wndCheckBox.SetCheck (BST_UNCHECKED); // Uncheck

//----------------------------------------------------------------------------------

void CMainWindow::OnCheckBoxClicked ()

{

m_wndCheckBox.SetCheck (m_wndCheckBox.GetCheck () ==

BST_CHECKED ? BST_UNCHECKED : BST_CHECKED);

}

//----------------------------------------------------------------------------------

m_wndCheckBox.SetCheck (BST_INDETERMINATE);

Page 127: Visual C++

127

Radio Buttons

BS_RADIOBUTTON 이나 BS_AUTORADIOBUTTON 스타일로 생성

BS_AUTORADIOBUTTON 은 자동으로 체크 BS_RADIOBUTTON 은 체크 상태를 수동으로 설정 (BN_CLICKE

D 에서 처리 ) SetCheck() , GetCheck() 사용 기본상태는 체크되지 않음

void CMainWindow::OnRadioButton1Clicked ()

{ //1 번 버튼을 눌렀을때 나머지 버튼을 Unchecked 상태로 만듦

m_wndRadioButton1.SetCheck (BST_CHECKED);

m_wndRadioButton2.SetCheck (BST_UNCHECKED);

m_wndRadioButton3.SetCheck (BST_UNCHECKED);

m_wndRadioButton4.SetCheck (BST_UNCHECKED);

}

Page 128: Visual C++

128

Radio button 그룹화

1. 버튼을 순서대로 하나씩 생성2. 첫번째 버튼에 WS_GROUP 속성 추가3. 다음번 WS_GROUP 을 가진 컨트롤 이전까지의 컨트롤들이

하나의 그룹

m_wndRadioButton1.Create (_T ("COM1"), WS_CHILD ¦ WS_VISIBLE ¦

WS_GROUP ¦ BS_AUTORADIOBUTTON, rect1, this, IDC_COM1);

m_wndRadioButton2.Create (_T ("COM2"), WS_CHILD ¦ WS_VISIBLE ¦

BS_AUTORADIOBUTTON, rect2, this, IDC_COM2);

m_wndRadioButton1.SetCheck (BST_CHECKED);

m_wndCheckBox.Create (_T ("Save settings on exit"),

WS_CHILD ¦ WS_VISIBLE ¦ WS_GROUP ¦ BS_AUTOCHECKBOX,

rectCheckBox, this, IDC_SAVESETTINGS);

Page 129: Visual C++

129

Group Box

BS_GROUPBOX 로 생성 부모에게 어떤 메시지도 보내지 않음 단지 시각적 효과만 제공

Page 130: Visual C++

130

CListBox

리스트박스 생성m_wndListBox.Create (WS_CHILD ¦ WS_VISIBLE ¦ LBS_STANDARD, rec

t, this, IDC_LISTBOX); LBS_STANDARD : WS_BORDER | WS_VSCROLL | LBS_NOTIFY | LB

S_SORT 목록 추가

m_wndListBox.AddString (string); m_wndListBox.InsertString (3, string);

목록 개수 반환CListBox::GetCount

목록 삭제CListBox::DeleteString

Page 131: Visual C++

131

CListBox

항목 선택

다중 항목 선택• GetCaretIndex

// In CMainWindow's message map

ON_LBN_DBLCLK (IDC_LISTBOX, OnItemDoubleClicked)

void CMainWindow::OnItemDoubleClicked ()

{

CString string;

int nIndex = m_wndListBox.GetCurSel ();

m_wndListBox.GetText (nIndex, string);

MessageBox (string);

}

Page 132: Visual C++

132

CStatic

Static 컨트롤 생성m_wndStatic.Create (_T ("Name"), WS_CHILD ¦ WS_VISIBLE ¦ SS_LE

FT, rect, this, IDC_STATIC); SS_LEFT : rect 영역안에서 왼쪽 정렬 기본적으로 사각형 왼쪽 위로 정렬 가운데 정렬은 SS_CENT

ERIMAGE Bitmap 출력

m_ctrlStatic.Create (_T (""), WS_CHILD | WS_VISIBLE | SS_BITMAP | SS_SUNKEN, rect , this, IDC_STATIC1);

HINSTANCE hInstance = AfxGetInstanceHandle();

HBITMAP hBitmap = LoadBitmap(hInstance ,MAKEINTRESOURCE(IDB_BITMAP1));

m_ctrlStatic.SetBitmap(hBitmap);

Page 133: Visual C++

133

CEdit

텍스트 편집에 사용 복사 , 잘라내기 , 붙여넣기 기능 지원 Edit 컨트롤 생성

m_wndEdit.Create (WS_CHILD ¦ WS_VISIBLE ¦ WS_BORDER ¦ ES_AUTOHSCROLL, rect, this, IDC_EDIT);

WS_BORDER : 컨트롤 주위에 경계선 추가 ES_AUTOHSCROLL : 수평방향으로 자동 이동 Multiline Edit 컨트롤 생성

m_wndEdit.Create (WS_CHILD ¦ WS_VISIBLE ¦ WS_BORDER ¦ WS_HSCROLL ¦ WS_VSCROLL ¦ ES_MULTILINE, rect, this, IDC_EDIT);

Page 134: Visual C++

134

7. MDI (Multiple Document Interface)

Page 135: Visual C++

135

분할윈도우 동적 분할 윈도우 (Dynamic Split Window)

• 프로그램이 실행 중에 윈도우를 분할 가능• 같은 데이터를 같은 방식으로 보여주되 , 스크롤바를 이용하여

서로 다른 부분을 디스플레이 정적 분할 윈도우 (Static Split Window)

• 윈도우가 분할된 상태로 프로그램이 시작되고 , 프로그램 실행 중에 분할된 윈도우 병합불가능

• 이용하면 같은 데이터라도 완전히 방식으로 표현가능

Page 136: Visual C++

136

동적 분할 윈도우 구현 Step 1: CSplitterWnd 클래스의 인스턴스 선언

• CSplitterWnd m_wndSplitter; Step 2: OnCreateClient 함수 재정의

Step 3: 모든 View 를 갱신• View 클래스에서 UpdateAllViews(NULL); 호출

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext){ if (!m_wndSplitter.Create(this, 2, 2, CSize(10, 10), pContext)) { TRACE0(" 분할 윈도우 생성에 실패 하였습니다 .\n"); return FALSE; // failed to create } return TRUE;}

Page 137: Visual C++

137

SDI vs. MDI

Page 138: Visual C++

138

SDI vs. MDI

CMDIFrameWnd 와 CMDIChildWnd 클래스는 CFrameWnd 클래스에서 상속 프레임윈도우의 기능 가짐

CMDIFrameWnd 클래스에는 CMDIChildWnd 클래스를 관리 CMDIChildWnd 클래스에는 CMDIFrameWnd 의 안쪽에

들어가서 클래스의 관리를 받음

CWnd

CFrameWnd

CMDIFrameWnd

CMDIChildWnd

Page 139: Visual C++

139

SDI 를 MDI 로 변환

1. 자식 프레임 윈도우 추가 • CMDIChildWnd 에서 상속 받은 CChildFrame 클래스를 추가

2. 메인 프레임 윈도우의 기반 클래스 변경 3. 도큐먼트 , 프레임 윈도우 , 뷰 등록

1. CSingleDocTemplate->CMultiDocTemplate 으로 변경2. RUNTIME_CLASS(CMainFrame)-> RUNTIME_CLASS(CChildFrame)

으로 변경4. AddDocTemplate 함수다음에 메인 프레임 생성

5. 메인 프레임 윈도우의 생성자 함수를 public 으로 변경

CMainFrame* pMainFrame = new CMainFrame;if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE;m_pMainWnd = pMainFrame;

Page 140: Visual C++

140

MDI 를 SDI 로 변환

1. 자식 프레임 윈도우 삭제 2. 메인 프레임 윈도우의 기반 클래스 변경3. 도큐먼트 , 프레임 윈도우 , 뷰 등록4. 메인 프레임 생성5. 메인 프레임 윈도우에 동적 생성기능 추가

• MainFrame 에 있는 DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC 을 DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE 로 변환

Page 141: Visual C++

141

모든 뷰의 화면 갱신

void CMyClass::OnUpdateAllViews( ){ CWinApp *pApp = AfxGetApp( ); POSITION posTemplate = pApp-> GetFirstDocTemplatePosition(); while(posTemplate) { CDocTemplate *pTemplate = pApp->GetNextDocTemplate(posTemplate); POSITION posDoc = pTemplate->GetFirstDocPosition( ) while(posDoc) { CDocument *pDoc = pTemplate->GetNextDoc(posDoc); POSITION posView = pDoc->GetFirstViewPosition( ); while(posView) {

CView *pView = pDoc->GetNextView(posView);pView->Invalidate( );

} } }}

Page 142: Visual C++

142

파일 메뉴 처리

ID _F ILE_N EW

ID _FILE_O PEN

ID _FILE_SAVE

ID _FILE_SAVE_AS

Page 143: Visual C++

143

파일 메뉴 처리ID _F ILE_N EW

ID _FILE_O PEN

ID _FILE_SAVE

ID _FILE_SAVE_AS

C W inApp 클래스 C D ocum ent 클래스

새 로 운 도 큐 먼 트 생 성

OnF ileN ew ( ) 커 맨 드 핸 들 러 함 수

CDocument 의 멤 버 함 수OnN ew Document( ) 호 출

새 로 운 인 스 턴 스 생 성 됨

OnN ew Document( ) 호 출 됨

OnF ileOpen( ) 커 맨 드 핸 들 러 함 수

새 로 운 도 큐 먼 트 생 성

CDocument 의 멤 버 함 수OnOpenDocument( ) 호 출

파 일 명 을 입 력 받 음

새 로 운 인 스 턴 스 생 성 됨

OnOpenDocument( ) 호 출 됨

OnOpenDocument( ) 함 수 의 인 자 로 넘 겨 받 음

OnF ileS ave( ) 커 맨 드 핸 들 러 함 수

CDocument 의 멤 버 함 수OnS aveDocument( ) 호 출

:처 음 저 장 하 는 경 우 파 일 명 을 입 력 받 음

OnS aveDocument( ) 호 출 됨

OnS aveDocument( ) 함 수 의 인 자 로 넘 겨 받 음

S er ialize( ) 함 수 호 출

S er ialize( ) 함 수 호 출

OnF ileS aveA s( ) 커 맨 드 핸 들 러 함 수

OnF ileS ave( ) 함 수 와 같 은 동 작

Page 144: Visual C++

144

Serialize

void CMyDoc::Serialize(CArchive& ar){

if (ar.IsStoring()){

// 저장하기ar << n;

}else{

// 읽어오기 ar >> n;

}}

Page 145: Visual C++

145

다중 도큐먼트 타입 MDI

Page 146: Visual C++

146

Document Template

BOOL CDrawApp::InitInstance(){

// …CMultiDocTemplate* pDocTemplate;pDocTemplate = new CMultiDocTemplate(

IDR_DRAWTYPE,RUNTIME_CLASS(CDrawDoc),RUNTIME_CLASS(CChildFrame), RUNTIME_CLASS(CDrawView));

AddDocTemplate(pDocTemplate);

pDocTemplate = new CMultiDocTemplate(IDR_TEXTTYPE,RUNTIME_CLASS(CTextDoc),RUNTIME_CLASS(CTextFrame),RUNTIME_CLASS(CTextView));

AddDocTemplate(pDocTemplate);// …

}

Page 147: Visual C++

147

Document Template

도큐먼트와 연결된 문자열의 항목에 따른 의미

항목 IDR_DrawTYPE 의 예 용도

1 설정되어 있지 않음 단일 도큐먼트 프로그램의 타이틀 바에 표시하는

문자열

2 Text 새로 생성된 도큐먼트의 디폴트 파일명

3 Text 새로 생성될 도큐먼트의 종류를 물어보는 대화상자

에 출력될 문자열

4 Text Files (*.txt) 열기 대화상자의 [파일 형식] Combo Box 컨트롤에

추가될 필터 이름

5 . Text 확장자

6 Text.Document 레지스트리에 저장되는 도큐먼트 유형 ID

7 Text Document 레지스트리에 저장되는 도큐먼트 유형 이름

Page 148: Visual C++

148

도큐먼트 인스턴스 관리

C W inA pp

C M u ltiD ocTem p la te C D ocum ent C V iew

C M u ltiD ocTem p la te

C D ocum ent

C D ocum ent

C D ocum ent

C V iew

C V iew

C V iew

C V iew

C V iew

Page 149: Visual C++

149

OnFileNew

void CDrawApp::OnFileNew()

{

POSITION pos = GetFirstDocTemplatePosition( );

CDocTemplate *pTemplate;

for(int i=0 ; i<N ; i++)

pTemplate = GetNextDocTemplate(pos);

pTemplate->OpenDocumentFile(NULL);

}

Page 150: Visual C++

150

OnFileOpen

Page 151: Visual C++

151

OnFileOpen

void CDrawApp::OnFileOpen() {

char szFilter[] = "Draw 파일 (*.drw), Text 파일 (*.txt) | *.drw;*.txt | 모든파일 (*.*)|*.*||";

CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, szFilter);if(dlg.DoModal( ) == IDOK)

OpenDocumentFile(dlg.GetPathName());}

if(dlg.DoModal( ) == IDOK)for(POSITION pos = dlg.GetStartPosition( ); pos != NULL ; )

OpenDocumentFile(dlg.GetNextPathName(pos));

Page 152: Visual C++

152

Additional Function of CDocument

OnCloseDocument : Called to close the document. OnNewDocument : Called to create a new document. OnOpenDocument : Called to open an existing document. OnSaveDocument : Called to save the document to disk.

Page 153: Visual C++

153

Additional Function of CDocument

IsModified: Indicates whether the document has been modified since it was last saved.

SetModifiedFlag: Sets a flag indicating that you have modified the document since it was last saved.

SetPathName: Sets the path of the data file used by the document.

SetTitle: Sets the document's title.

Page 154: Visual C++

154

Additional Function of CView

OnActivateView: Called when a view is activated.

OnActivateFrame: Called when the frame window containing the view is activated or deactivated.

OnDraw: Called to render an image of the document for screen display, printing, or print preview. Implementation required.

OnBeginPrinting, OnEndPrinting, OnEndPrintPreview, OnPreparePrinting, OnPrint

Page 155: Visual C++

155

CDocument & CView Interaction

GetFirstViewPosition, GetNextView

GetDocument

POSITION pos = GetFirstViewPosition();

while (pos != NULL)

{

CView* pView = GetNextView(pos);

pView->Invalidate();

}

Page 156: Visual C++

156

CDocument & CView Interaction

Documentvoid UpdateAllViews( CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL );

View 1

virtual void OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint );

View 2

virtual void OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint );

Page 157: Visual C++

157

드래그 앤 드롭에 의한 파일 열기

BOOL CDrawApp::InitInstance()

{

//…

CMainFrame* pMainFrame = new CMainFrame;

if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

return FALSE;

m_pMainWnd = pMainFrame;

 

// Enable drag/drop open

m_pMainWnd->DragAcceptFiles();

//…

}

Page 158: Visual C++

158

8. Serialization

Page 159: Visual C++

159

데이터 저장 및 읽어오기 CObject 클래스에는 데이터를 저장하고 읽어오는 Serialize

함수가 존재 CObject 를 상속받은 클래스는 Serialize 함수를 이용하여

멤버변수의 값을 읽고 저장가능 Serialize 함수를 오버로딩하여 사용

Page 160: Visual C++

160

Serialize 함수의 호출 CDocument 파생 클래스는 CObject 클래스의 Serialize

함수를 오버라이딩하고 있슴 CDocument 파생 클래스에서 Serialize 함수를 오버라이딩

하면 멤버 변수를 디스크에 저장하거나 읽어올 수 있슴

Page 161: Visual C++

161

어플리케이션 프레임 워크의 파일 메뉴 처리 기능 ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_SAVE, ID_FILE_SAVE_AS

는 자동으로 처리 CWinApp 에서 전처리를 하고 CDocument 클래스로 넘긴다 .

ID _F ILE_N EW

ID _FILE_O PEN

ID _FILE_SAVE

ID _FILE_SAVE_AS

Page 162: Visual C++

162

파일 메뉴 처리ID _F ILE_N EW

ID _FILE_O PEN

ID _FILE_SAVE

ID _FILE_SAVE_AS

C W inApp 클래스 C D ocum ent 클래스

새 로 운 도 큐 먼 트 생 성

OnF ileN ew ( ) 커 맨 드 핸 들 러 함 수

CDocument 의 멤 버 함 수OnN ew Document( ) 호 출

새 로 운 인 스 턴 스 생 성 됨

OnN ew Document( ) 호 출 됨

OnF ileOpen( ) 커 맨 드 핸 들 러 함 수

새 로 운 도 큐 먼 트 생 성

CDocument 의 멤 버 함 수OnOpenDocument( ) 호 출

파 일 명 을 입 력 받 음

새 로 운 인 스 턴 스 생 성 됨

OnOpenDocument( ) 호 출 됨

OnOpenDocument( ) 함 수 의 인 자 로 넘 겨 받 음

OnF ileS ave( ) 커 맨 드 핸 들 러 함 수

CDocument 의 멤 버 함 수OnS aveDocument( ) 호 출

:처 음 저 장 하 는 경 우 파 일 명 을 입 력 받 음

OnS aveDocument( ) 호 출 됨

OnS aveDocument( ) 함 수 의 인 자 로 넘 겨 받 음

S er ialize( ) 함 수 호 출

S er ialize( ) 함 수 호 출

OnF ileS aveA s( ) 커 맨 드 핸 들 러 함 수

OnF ileS ave( ) 함 수 와 같 은 동 작

Page 163: Visual C++

163

Serialize

CDocument 파생 클래스에는 Serialize 함수가 미리 오버라이딩 된다 .

void CDrawCrossDoc::Serialize(CArchive& ar){

if (ar.IsStoring()){

// TODO: add storing code herear << n1 << n2;

}else{

// TODO: add loading code herear >> n1 >> n2;

}}

Page 164: Visual C++

164

CArchive 클래스

CDocument 클래스와 CFile 클래스를 연결해 주기 위한 클래스• CFile 는 파일을 관리하는 클래스

OnOpenDocument 함수와 OnSaveDocument 함수가 CArchive 오브젝트와 CFile 오브젝트를 연결

IsStoring() : 읽기상태 또는 저장상태를 판별C D ocum ent

C Archive

C FileC M em File C SocketF ile

Seria lize

네 트 워 크디 스 크

메 모 리

Page 165: Visual C++

165

데이터 저장 및 읽어오기

방법 CDocument 클래스의 OnOpenDocument 함수와 OnSaveDo

cument 함수를 오버라이딩하여 각각 데이터를 읽어오는 루틴과 저장하는 루틴을 삽입

CDocument 클래스의 Serialize 함수를 오버라이딩 해서 데이터를 읽어오는 루틴과 저장하는 루틴을 함께 구현

Page 166: Visual C++

166

OnOpenDocument 와 OnSaveDocument 를 사용

BOOL CDrawCrossDoc::OnOpenDocument(LPCTSTR lpszPathName) {

if (!CDocument::OnOpenDocument(lpszPathName))return FALSE;

// TODO: Add your specialized creation code here

return TRUE;} BOOL CDrawCrossDoc::OnSaveDocument(LPCTSTR lpszPathName) {

// TODO: Add your specialized code here and/or call the base class

return CDocument::OnSaveDocument(lpszPathName);}

Page 167: Visual C++

167

Serialize 함수를 사용void CDrawCrossDoc::Serialize(CArchive& ar){

int i;if (ar.IsStoring()){

ar << m_nCount; for(i = 0 ; i <= m_nCount ; i++) {

ar << m_ptData[i];}

}else{ ar >> m_nCount;

for(i = 0 ; i <= m_nCount ; i++) {ar >> m_ptData[i];

}}

}

Page 168: Visual C++

168

9. Collection Class

Page 169: Visual C++

169

CObList Construction and Tail Access

CObList::CObList( int nBlockSize = 10 );• nBlockSize - The memory-allocation granularity for extending the list.

POSITION AddTail( CObject* newElement );• Adds a new element or list of elements to the tail of this list. The list can be empty

before the operation.

class CAge : public CObject

{

int m_years;

public:

CAge( int age=0 ) { m_years = age; }

};

CObList list;

list.AddTail( new CAge( 21 ) );

list.AddTail( new CAge( 40 ) ); // List now contains (21, 40).

Page 170: Visual C++

170

CObList Iteration

POSITION CObList::GetHeadPosition()• Gets the position of the head element of this list.

CObject* CObList::GetNext( POSITION& rPosition )• Gets the list element identified by rPosition, then sets rPosition to

the POSITION value of the next entry in the list. CObject* GetAt( POSITION position ) const

• GetAt retrieves the CObject pointer associated with a given position

for( pos = list.GetHeadPosition(); pos != NULL; )

{

list.GetNext( pos );

}

Page 171: Visual C++

171

CObList Removal

void CObList::RemoveAll()• Removes all the elements from this list and frees the associated

CObList memory. It is your responsibility to delete the objects themselves.

CObList list;CAge* pa1;CAge* pa2;ASSERT( list.IsEmpty()); // Yes it is.list.AddHead( pa1 = new CAge( 21 ) );list.AddHead( pa2 = new CAge( 40 ) ); // List now contains (40, 21).ASSERT( !list.IsEmpty()); // No it isn't.list.RemoveAll(); // CAge's aren't destroyed.ASSERT( list.IsEmpty()); // Yes it is.delete pa1; // Now delete the CAge objects.delete pa2;

Page 172: Visual C++

172

10. 고급그래픽

Page 173: Visual C++

173

비트맵 그래픽 비트맵 그래픽 vs 벡터 그래픽 비트맵

• 작은 점들의 2 차원 배열을 이용하여 영상정보를 표현 벡터 그래픽

• 선 , 면 , 호 , 원 , 곡선 , 다각형 등 그래픽스의 구성요소가 되는 객체의 조합으로 영상정보를 표현

사각형 원

키 포인트

픽셀

0

30

50

80

100

120

30

50

80

100

120

140

50

80

100

120

140

180

80

100

120

140

180

200

100

120

140

180

200

220

120

140

180

200

220

240

Page 174: Visual C++

174

Bitmap GDI Object

비트맵 GDI 오브젝트• 윈도우에서는 비트맵을 하나의 GDI 오브젝트로 채택 • CBitmap 클래스 cf) CPen , CBrush

그래픽 함수들은 GDI 오브젝트를 참조하여 그래픽 작업 수행 비트맵 GDI 오브젝트를 참조하는 그래픽 함수

• BitBlt Bit Block Transfer 의 약자 임의의 DC 에서 다른 DC 로 비트맵 블록을 전송

• StretchBlt 임의이 DC 에서 다른 DC 로 비트맵 블록을 전송하되 , 확대

또는 축소를 해서 전송• cf) 다른 그래픽함수와 달리 DC 가 2 개가 필요

Page 175: Visual C++

175

비트맵을 출력시키는 전체 과정

윈도우

(x, y)nWidth

nHeight

MemDCWinDC

BitBlt

(xSrc, ySrc)

CBitmap

SelectObject

Resource

LoadBitmap

Page 176: Visual C++

176

화면 DC 와 메모리 DC 만들기 비트맵이 출력될 화면 윈도우의 DC

• CClientDC WinDC(this); 메모리에 만들어진 DC

• CDC MemDC; 메모리 상에 존재하는 MemDC 로부터 화면 윈도우로부터

얻어진 WinDC 로 비트맵 블록을 전송

Page 177: Visual C++

177

화면 DC 와 호환성을 갖는 메모리 DC 만들기 비트맵 블록 전송을 위하여는 DC 간에 호환성을 가져야 한다 . MemDC.CreateCompatibleDC(&WinDC);

• MemDC 와 WinDC 는 호환성을 갖게 되어 서로 비트맵 블록 전송이 가능

Page 178: Visual C++

178

비트맵 읽어오기 비트맵 데이터를 읽어오고 , 관리하는 기능은 CBitmap

클래스가 수행 리소스에 저장되어 있는 비트맵 데이터 로드

CBitmap bitmap;

bitmap.LoadBitmap(IDB_BITMAP1);

비트맵을 DC 에 선택 • CBitmap *pOldBitmap = (CBitmap )MemDC.SelectObject(&bitmap);

Page 179: Visual C++

179

비트맵 블록 전송 BOOL CDC::BitBlt(int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int

xSrc, int ySrc, DWORD dwRop )

Ex) WinDC.BitBlt(100, 200, 20, 30, &MemDC, 30, 40, SRCCOPY);

인자 의미

x 화면에 출력할 x 좌표

y 화면에 출력할 y좌표

nWidth 화면에 출력할 그림의 폭

nHeight 화면에 출력할 그림의 높이

pSrcDC 비트맵 블록을 전송할 소스 DC 의 포인터

xSrc 소스 비트맵에서 전송을 시작할 x 좌표

ySrc 소스 비트맵에서 전송을 시작할 y좌표

dwRop 래스터 오퍼레이션 코드

Page 180: Visual C++

180

Bitmap 출력void CMyWnd::DrawBitmap( ){

CClientDC WinDC(this); // 윈도우 DC 를 얻음CDC MemDC; // 메모리 DC 를 만듦

 // MemDC 를 WinDC 와 호환성 있게 만들어 줌MemDC.CreateCompatibleDC(&WinDC);

 // 리소스에서 비트맵을 읽어옴CBitmap bitmap;bitmap.LoadBitmap(IDB_BITMAP1);

 // 비트맵을 DC 에 선택CBitmap *pOldBitmap = (CBitmap *)MemDC.SelectObject(&bitmap);

 // 비트맵 블록을 전송WinDC.BitBlt(100, 200, 20, 30, &MemDC, 30, 40, SRCCOPY);

 // DC 복원MemDC. SelectObject(pOldBitmap);

}

Page 181: Visual C++

181

비트맵의 확대 / 축소 void CBMPView::OnDraw(CDC* pDC){

// 호환성 있는 메모리 DC 를 생성CDC MemDC;MemDC.CreateCompatibleDC(pDC);// 리소스에서 비트맵을 읽어 들여 DC 에 선택CBitmap bitmap;bitmap. LoadBitmap(IDB_MAN);CBitmap *pOldBitmap = (CBitmap *)MemDC.SelectObject(&bitmap);// 비트맵 블록 전송pDC->BitBlt(50, 50, 32, 32, &MemDC, 0, 0, SRCCOPY);// 상하좌우로 뒤집어 출력pDC->StretchBlt(100, 50, 32, 32, &MemDC, 32, 32, -32, -32, SRCCOPY);// 2 배 확대하여 출력pDC->StretchBlt(150, 50, 64, 64, &MemDC, 0, 0, 32, 32, SRCCOPY);// DC 복원MemDC.SelectObject(pOldBitmap);

}

Page 182: Visual C++

182

배경과 합성

마스크이미지와 배경이미지를 AND 연산

비트맵과 OR 연산

Page 183: Visual C++

183

배경과 합성static int nAnimate;CClientDC dc(this); CDC MemDC; // 호환성 있는 메모리 DC 를 생성MemDC.CreateCompatibleDC(&dc);CBitmap bmpMask, bmpMan, bmpBack; // 리소스에서 비트맵 읽기bmpMask.LoadBitmap(IDB_MASK);bmpMan.LoadBitmap(IDB_MAN);bmpBack.LoadBitmap(IDB_BACK); CBitmap *pOldBitmap = (CBitmap *)MemDC.SelectObject(&bmpBack); // 배경 다시 그리기dc.BitBlt(50, 50, 32, 32, &MemDC, 50, 50, SRCCOPY); MemDC.SelectObject(&bmpMask); // 마스크 그리기dc.BitBlt(50, 50, 32, 32, &MemDC, 32*nAnimate, 0, SRCAND); MemDC.SelectObject(&bmpMan); // 아이콘 그림 그리기dc.BitBlt(50, 50, 32, 32, &MemDC, 32*nAnimate, 0, SRCPAINT);

if(++nAnimate > 3) nAnimate = 0; // 애니메이션 카운터를 증가시킴MemDC.SelectObject(pOldBitmap);

Page 184: Visual C++

184

메모리 비트맵 화면에는 보이지 않고 , 메모리 상에만 존재 하는 비트맵 고속 그래픽 출력을 위한 버퍼 로 사용 ( 더블버퍼링 )

• 여러 출력 함수를 호출하면 그려지는 과정이 드러나면서 화면이 깜박거려 보임

비트맵을 블록 단위로 전송하는 것은 아주 고속으로 수행

Page 185: Visual C++

185

메모리 비트맵에 도형 그려 출력// 화면 DC 와 호환성 있는 메모리 DC 를 만듦CDC BufferDC;BufferDC.CreateCompatibleDC(pDC);

// 화면 DC 와 호환성 있는 메모리 비트맵을 만듦CBitmap bmpBuffer;bmpBuffer.CreateCompatibleBitmap(pDC, 200, 200); // 메모리 DC 에 메모리 비트맵을 선택CBitmap *pOldBitmap = (CBitmap *)BufferDC.SelectObject(&bmpBuffer);

// 메모리 DC 에 그림을 그림BufferDC.Rectangle(0, 0, 200, 200);BufferDC.Rectangle(10, 10, 100, 100);BufferDC.Ellipse(70, 70, 180, 180);

// 메모리 비트맵에 그려진 내용을 화면으로 전송pDC->BitBlt(0, 0, 200, 200, &BufferDC, 0, 0, SRCCOPY);

// DC 복원BufferDC.SelectObject(pOldBitmap);

Page 186: Visual C++

186

11. 고급 컨트롤 제어

Page 187: Visual C++

187

컨트롤 서브클래싱

어떤 윈도우에 보내지는 메시지를 그 윈도우가 받기 전에 다른 윈도우에서 가로채어 처리하는 프로그래밍 테크닉

서브클래싱에 의한 기능 수정 컨트롤의 기능 중 수정하고자 하는 기능이 있으면

서브클래싱을 이용 컨트롤의 서브클래싱

• 다이얼로그 템플릿을 이용하여 생성되는 원래 컨트롤 클래스를 그대로 두고 , 그 컨트롤로 가는 메시지를 가로채어 컨트롤의 동작을 변경

• BOOL SubclassDlgItem(UINT nID, CWnd *pWnd) nID : 서브클래싱하고자 하는 컨트롤의 다이얼로그

템플릿에서의 ID pWnd : 컨트롤의 부모 윈도우의 포인터

• 실제 프로그래밍을 할 때는 SubclassDlgItem 함수를 직접 호출해주지 않아도 됨

Page 188: Visual C++

188

컨트롤 서브클래싱

구현할 기능

숫자 이외의 다른 문자를 입력하면 경고음이 출력

Page 189: Visual C++

189

컨트롤 서브클래싱

새로운 기능을 구현할 CEdit 파생 클래스

Page 190: Visual C++

190

컨트롤 서브클래싱

WM_CHAR 메시지를 처리 백 스페이스 키나 숫자키가 눌리면 원래의 동작을 그대로 수행 다른 키가 눌렸을 때는 경고음을 출력

void CNumEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

if((nChar>='0' && nChar<='9') || (nChar==VK_BACK))

CEdit::OnChar(nChar, nRepCnt, nFlags);

else

MessageBeep(MB_ICONASTERISK);

}

Page 191: Visual C++

191

Control 형 멤버 변수 연결 다이얼로그 박스에 올라가 있는 편집 상자 컨트롤의 메시지를

가로채서 동작하도록 서브클래싱

Page 192: Visual C++

192

컨트롤과 서브클래싱 클래스를 연결

#include "NumEdit.h"

#include "CharEdit.h"

 

class CEditDlg : public CDialog

{

//…

//{{AFX_DATA(CSubclassDlg)

enum { IDD = IDD_SUBCLASSING };

CNumEdit m_ctrlNumEdit;

CCharEdit m_ctrlCharEdit;

//}}AFX_DATA

//…

}

void CEditDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CSubclassDlg)

DDX_Control(pDX, IDC_EDIT1, m_ctrlNumEdit);

DDX_Control(pDX, IDC_EDIT2, m_ctrlCharEdit);

//}}AFX_DATA_MAP

}

Page 193: Visual C++

193

프로퍼티시트 프로퍼티 시트 (Property Sheet)

• 여러 개의 탭으로 이루어진 페이지들을 함께 가지고 있는 일종의 다이얼로그 박스

Property Sheet

Property Page Page 2 Page 3

확인 취소 적용

Page 194: Visual C++

194

프로퍼티 시트와 프로퍼티 페이지 클래스 CProprtyPage 클래스가 CDialog 클래스에서 상속 CPropertySheet 클래스는 CDialog 에서 상속을 받지 않음

CWnd

CPropertySheet

CDialog

CPropertyPage

Page 195: Visual C++

195

프로퍼티 페이지 만들기 다이얼로그 템플릿 디자인

Page 196: Visual C++

196

프로퍼티 페이지 만들기 프로퍼티 페이지 클래스 만들기

Page 197: Visual C++

197

프로퍼티 시트 만들기 프로퍼티 시트 클래스 만들기

Page 198: Visual C++

198

프로퍼티 시트에 프로퍼티 페이지 등록 프로퍼티 시트에 프로퍼티 페이지를 등록하려면 프로퍼티 시트

클래스에 프로퍼티 페이지의 인스턴스가 있어야 함

#include "page1.h"

#include "page2.h"

#include "page3.h"

 

class CSheetDlg : public CPropertySheet

{

//…

CPage1 m_page1;

CPage2 m_page2;

CPage3 m_page3;

//…

}

Page 199: Visual C++

199

프로퍼티 시트에 프로퍼티 페이지 등록 CPropertySheet 파생 클래스의 생성자 함수에서 CPropertyShe

et 클래스의 멤버 함수 AddPage 를 호출CSheetDlg::CSheetDlg(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)

:CPropertySheet(nIDCaption, pParentWnd, iSelectPage)

{

AddPage(&m_page1);

AddPage(&m_page2);

AddPage(&m_page3);

}

CSheetDlg::CSheetDlg(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)

:CPropertySheet(pszCaption, pParentWnd, iSelectPage)

{

AddPage(&m_page1);

AddPage(&m_page2);

AddPage(&m_page3);

}

Page 200: Visual C++

200

프로퍼티 시트를 다이얼로그 박스처럼 출력하기 DoModal 함수를 호출하면 프로퍼티 시트가 다이얼로그

박스처럼 화면에 출력

프로퍼티 시트의 타이틀 바에 출력될 문자열

#include “SheetDlg.h”

void CPropertyView::OnPropertysheet()

{

CSheetDlg dlg(IDS_SHEET);

dlg.DoModal();

}

Page 201: Visual C++

201

위저드 형식 다이얼로그 박스 만들기

위저드 형식으로 옵션 변경

void CPropertyView::OnWizard() {

CSheetDlg dlg(IDS_SHEET);dlg.SetWizardMode( );if(dlg.DoModal() == ID_WIZFINISH){

AfxMessageBox(dlg.UserInput());}

}

Page 202: Visual C++

202

각각의 CPropertyPage 파생 클래스에 대해 ClassWizard 를 이용하여 OnSetActive 함수를 오버라이딩 BOOL CPage1::OnSetActive()

{

((CPropertySheet *)GetParent())-> SetWizardButtons(PSWIZB_NEXT);

  return CPropertyPage::OnSetActive();

}

BOOL CPage2::OnSetActive()

{

((CPropertySheet *)GetParent())-> SetWizardButtons(PSWIZB_BACK|PSWIZB_NEXT); 

return CPropertyPage::OnSetActive();

}

BOOL CPage3::OnSetActive()

{

((CPropertySheet *)GetParent())->SetWizardButtons(PSWIZB_BACK|PSWIZB_FINISH);

return CPropertyPage::OnSetActive();

}

Button 설정

Page 203: Visual C++

203

12. 고급 사용자 인터페이스

Page 204: Visual C++

204

메뉴 메인 메뉴얻기

• CMenu* CWnd::GetMenu( ) const; 팝업 메뉴 ( 서브 메뉴 ) 얻기

• CMenu* CMenu::GetSubMenu( int nPos ) const;

사용법

CMenu*pMainMenu = GetMenu( );

CMenu *pPopupMenu = pMainMenu->GetSubMenu(2);

Page 205: Visual C++

205

메뉴 제어 메뉴 항목 추가

• AppendMenu(MF_STRING, ID_FILE_NEW, “ 새 파일 (&N)”); Separator 추가

• AppendMenu(MF_SEPARATOR) 팝업 메뉴 추가

CMenu menuPopup;

menuPopup.CreateMenu();

menuPopup.AppendMenu((MF_STRING, ID_FILE_NEW, “ 새 파일 (&N)”);

menuPopup.AppendMenu(MF_SEPARATOR)

menuPopup.AppendMenu((MF_STRING, ID_FILE_OPEN, “ 열기 (&O)”);

CMenu*pMainMenu = GetMenu( );

CMenu *pPopupMenu = pMainMenu->GetSubMenu(2);

pPopupMenu->AppendMenu(MF_POPUP, (UINT)menuPopup, “ 팝업 (&P)”);

menuPopup.Detach( );

Page 206: Visual C++

206

메뉴 항목 변경 커맨트 ID 를 이용한 메뉴 항목 변경

• ModifyMenu(IDM_EXPAND, MF_STRING | MF_BYCOMMAND,

IDM_SHRINK, “ 축소 (&S)”);

메뉴 항목의 위치를 이용한 메뉴 항목 변경 • ModifyMenu(5, MF_STRING | MF_BYPOSITION, IDM_SHRINK,

“ 축소 (&S)”); 메뉴 항목 삭제

• pPopupMenu->DeleteMenu(2, MF_BYPOSITION);• pPopupMenu->DeleteMenu(ID_FILE_NEW, MF_BYCOMMAND);

Page 207: Visual C++

207

다이나믹 메뉴 메뉴 확장 명령 처리

void CMainFrame::OnExpand()

{

CMenu *pMenu = GetMenu()->GetSubMenu(1);

  pMenu->ModifyMenu(IDM_EXPAND, MF_STRING|MF_BYCOMMAND, IDM_SHRINK, " 메뉴 축소 (&S)");

  pMenu->AppendMenu(MF_SEPARATOR);

pMenu->AppendMenu(MF_STRING, ID_FILE_NEW, " 새 파일 (&N)");

pMenu->AppendMenu(MF_STRING, ID_FILE_OPEN, " 열기 (&O)...");

pMenu->AppendMenu(MF_STRING, ID_FILE_SAVE, " 저장 (&S)");

}

Page 208: Visual C++

208

다이나믹 메뉴 메뉴 축소

• resource symbol 에서 IDM_SHRINK 추가

void CMainFrame::OnShrink()

{

CMenu *pMenu = GetMenu()->GetSubMenu(1);

  Menu->ModifyMenu(IDM_SHRINK, MF_STRING|MF_BYCOMMAND, IDM_EXPAND, " 메뉴 확장 (&E)");

  pMenu->DeleteMenu(1, MF_BYPOSITION);

pMenu->DeleteMenu(ID_FILE_NEW, MF_BYCOMMAND);

pMenu->DeleteMenu(ID_FILE_OPEN, MF_BYCOMMAND);

pMenu->DeleteMenu(ID_FILE_SAVE, MF_BYCOMMAND);

}

Page 209: Visual C++

209

시스템 메뉴 시스템 메뉴가 선택되면 WM_SYSCOMMAND 메시지가 발생 OnSysCommand 메시지 핸들러 함수

• afx_msg void OnSysCommand( UINT nID, LPARAM lParam ); nID : SC_CLOSE, SC_HSCROLL, SC_MAXIMIZE, SC_MINIMIZE, SC_

MOVE, SC_NEXTWINDOW, SC_PREVWINDOW, SC_RESTORE, SC_SCREENSAVE, SC_SIZE, SC_TASKLIST, SC_VSCROLL

void CChildFrame::OnSysCommand(UINT nID, LPARAM lParam){ if( nID != SC_CLOSE) CMDIChildWnd::OnSysCommand(nID, lParam);}

Page 210: Visual C++

210

시스템 메뉴 편집

BOOL CSysMenuDlg::OnInitDialog()

{

CMenu* pSysMenu = GetSystemMenu(FALSE);

if (pSysMenu != NULL)

{

CString strAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX);

if (!strAboutMenu.IsEmpty())

{

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

}

}

}

Page 211: Visual C++

211

영역 선택을 위한 트래커

CRectTracker 클래스의 인스턴스 생성 선택 영역 초기화 및 스타일 설정

class CTrackerDoc : public CDocument

{

CRectTracker m_tracker;

};

CTrackerDoc::CTrackerDoc()

{

m_tracker.m_rect.left = 100;

m_tracker.m_rect.top = 100;

m_tracker.m_rect.right = 200;

m_tracker.m_rect.bottom = 200;

m_tracker.m_nStyle = CRectTracker::hatchedBorder|CRectTracker::resizeOutside;

}

void CTrackerView::OnDraw(CDC* pDC){

pDoc->m_tracker.Draw(pDC); // 트래커 표시

}

Page 212: Visual C++

212

트래커 동작

HitTest(CPoint point)• 트래커의 외부가 클릭되면 – 1 리턴• 트래커의 8 개의 핸들 중 하나가 클릭되면 0 부터 7 까지의 값

리턴• 트래커의 내부가 클릭되면 8 리턴

void CTrackerView::OnLButtonDown(UINT nFlags, CPoint point)

{

CTrackerDoc* pDoc = GetDocument();

  if (pDoc->m_tracker.HitTest(point) < 0)

// 마우스를 드래그 하여 새로운 영역을 선택

pDoc->m_tracker.TrackRubberBand(this, point);

else // 이미 선택되어 있는 영역을 변형

pDoc->m_tracker.Track(this, point);

Invalidate();

  CView::OnLButtonDown(nFlags, point);

}

Page 213: Visual C++

213

13. 파일 입출력

Page 214: Visual C++

214

CFile 클래스 – 파일 열기

파일 열고 닫기

파일 접근 모드

CFile file;file.Open(_T(“File.txt”), CFile::modeReadWrite);// … 파일에 데이터를 읽거나 쓰는 작업을 수행file.Close( );

접근 모드 설명

CFile::modeRead 파일을 읽기만 할 수 있습니다 .

CFile::modeWrite 파일에 쓰기만 할 수 있습니다 .

CFile::modeReadWrite 읽고 쓰기를 모두 할 수 있습니다 .

CFile::modeCreate 파일을 새로이 생성합니다 .

CFile::modeNoTruncate 기존에 있는 파일에 데이터를 기존의 파일을 덮어쓰지 않고 ,

맨 뒤에 추가해 줍니다 .

Page 215: Visual C++

215

CFile 클래스

파일 공유 모드

공유 모드 설명

CFile::shareDenyNone 공유하도록 파일을 엽니다 .

CFile::shareDenyRead 다른 프로그램의 읽기 접근을 거부합니다 .

CFile::shareDenyWrite 다른 프로그램의 쓰기 접근을 거부합니다 .

CFile::shareExclusive 다른 프로그램의 읽기 , 쓰기를 모두 거부합니다 . (기본값 )

file.Open(_T(“File.txt”), CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);

Page 216: Visual C++

216

CFile 클래스 – 데이터 입출력

파일에 데이터 쓰기

파일에서 데이터 읽기

int buffer[1000];CFile file;file.Open(_(“File.dat”, CFile::modeCreate | CFile::modeWrite);file.Write(buffer, 1000 * sizeof(int));file.Close( );

CFile file;file.Open(_T(“File.dat”), CFile::modeRead);int nLength = file.GetLength( );int *buffer = new BYTE [nLength];file.Read(buffer, nLength);file.Close( );

Page 217: Visual C++

217

CFile 클래스 - 에러 처리

에러의 가능성• 지정한 파일이 디스크에 존재하지 않음• 다른 프로그램에서 파일을 사용• 디스크가 모두 차서 쓸 공간 부족void main(){ TRY{ int buffer[1000]; CFile file; file.Open(_T("File.dat"), CFile::modeCreate | CFile::modeWrite); file.Write(buffer, 1000 * sizeof(int)); file.Close( ); } CATCH(CFileException, e){ e->ReportError( ); } END_CATCH}

Page 218: Visual C++

218

CFile 클래스

기타 파일 처리 함수

멤버 함수 설명

GetFilePath 파일의 전체 경로명을 반환합니다 .

GetFileName 파일 이름을 반환합니다 .

GetFileTit le 확장자를 제외한 파일 이름을 반환합니다 .

GetStatus 파일이 생성된 시간 , 최종 변경된 시간 , 크기 , 속성 등 파일의 상태를

얻습니다 .

SetStatus 파일의 상태를 지정합니다 .

Remove 파일을 지웁니다 .

Rename 파일의 이름을 바꿉니다 .

Page 219: Visual C++

219

CArchive 클래스

CDocument 클래스와 CFile 클래스를 연결해 주기 위한 클래스

C D ocum ent

C Archive

C F ileC M em File C SocketF ile

Seria lize

네 트 워 크디 스 크

메 모 리

Page 220: Visual C++

220

CArchive 클래스와 CFile 클래스 연결

쓰기모드 생성

읽기 모드 생성

CFile file;file.Open(_T("File.dat"), CFile::modeCreate | CFile::modeWrite);CArchive ar(&file, CArchive::store);ar << data;

CFile file;file.Open(_T("File.dat"), CFile::modeRead);CArchive ar(&file, CArchive::load);ar >> data;

Page 221: Visual C++

221

CArchive 클래스를 이용하여 읽고 쓰기

데이터 입출력

입출력 연산자 오버로딩

텍스트 입출력

double pi = 3.141592653;ar.Write(&pi, sizeof(double));ar.Read(&pi, sizeof(double));

double pi = 3.141592653;ar << pi;ar >> pi;

double pi = 3.141592653;CString str;str.Format(“%f\n”, pi);ar.WriteString(str);ar.ReadString(str);

Page 222: Visual C++

222

CFileDialog 클래스

CFileDialog 클래스의 인스턴스를 선언하고 , DoModal 함수를 호출

char szFilter[] = "Image (*.BMP, *.GIF, *.JPG)|*.BMP;*.GIF;*.JPG |All Files(*.*)|*.*||";CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, szFilter);if(IDOK == dlg.DoModal()){ CString strPathName = dlg.GetPathName();}

Page 223: Visual C++

223

CFileDialog 클래스

CFileDialog(BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, LPCTSTR lpszFileName = NULL, DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR l pszFilter = NULL, CWnd *pParentWnd = NULL)• bOpenFileDialog – TRUE 는 대화상자 타이틀 바에 “열기”라고

출력되고 , FALSE 는 “다른 이름으로 저장” 출력• lpszDefExt - 기본 확장자• lpszFileName – 대화상자의 “파일 이름” 에디터 컨트롤에 출력될

파일명을 지정• dwFlags – 속성 설정• lpszFilter - 출력될 파일들을 확장자로 필터링• pParentWnd - 대화상자의 부모 윈도우를 지정

Page 224: Visual C++

224

CFileDialog 클래스 속성

파일 대화상자에 지정할 수 있는 속성 플래그

플래그 의미

OFN_EXPLORER 윈도우 탐색기 스타일로 출력합니다 .

OFN_ARROWMULTISELECT 파일을 한번에 여러 개 선택할 수 있습니다 .

OFN_CREATEPROMPT 존재하지 않는 파일명을 입력했을 경우 새로 생성하

겠냐는 메시지 박스를 출력합니다 .

OFN_FILEMUSTEXIST 존재하지 않는 파일명을 입력할 수 없도록 합니다 .

OFN_HIDEREADONLY 읽기 전용 파일은 출력하지 않습니다 .

OFN_LONGNAMES 긴 파일 이름 포맷을 지원하도록 합니다 .

OFN_OVERWRITEPROMPT 존재하는 파일명을 입력했을 경우 덮어쓰겠냐는 메

시지 박스를 출력합니다 .

OFN_PATHMUSTEXIST 이미 존재하는 디렉터리명만을 입력할 수 있습니다 .

Page 225: Visual C++

225

CFileDialog 클래스의 멤버 함수

다음 멤버 함수들을 호출하여 사용자의 입력 결과를 참조

함수 반환값

CString GetPathName 선택된 파일의 절대 경로

CString GetFileName 선택된 파일의 파일명과 확장자

CString GetFileExt 선택된 파일의 확장자

CString GetFIleTitle 선택된 파일의 파일명

BOOL GetReadOnlyPref 읽기 전용 여부

POSITION GetStartPosition

CString GetNextPathName

다중 선택의 경우

Page 226: Visual C++

226

Serialize

CFileDialog CFile CArchive 클래스로 이어지는 Serialize 파일 직접 제어

void CMyDoc::OnFileExport( ){ char szFilter[] = "Text File(*.txt)|*.txt|All Files(*.*)|*.*||"; CFileDialog dlg(FALSE, NULL, NULL, OFN_HIDEREADONLY, szFilter); if(IDOK == dlg.DoModal()) { CFile file; file.Open( dlg.GetPathName(), CFile::modeCreate | CFile::modeWrite); CArchive ar(&file, CArchive::store); ar << data1; ar << data2; }}

Page 227: Visual C++

227

Serialize 가능한 클래스 만들기

1. CObject 클래스로부터 직접 또는 간접적으로 상속을 받습니다 .2. 생성자 함수를 만들어 줍니다 .3. 헤더 파일에 DECLARE_SERIAL 매크로를 적어 줍니다 .4. 소스 파일에 IMPLEMENT_SERIAL 매크로를 적어 줍니다 .5. Serialize 함수를 재정의 해서 데이터를 저장하는 루틴을

넣어줍니다 .

Page 228: Visual C++

228

데이터 형식 << 나 >> 연산자로 CArchive 에 저장하고 읽어올 수 있는

데이터 형

저장하고 읽어올 수 있는 데이터 형식

기본 데이터 BYTE, W ORD, LONG, DW ORD, float, double, int, UINT, short, char

MFC 클래스 CSize, CPoint, CRect, CString, CTime, CTimeSpan, COleVarient,

COleCurrency, COleDataeTime, COleDateTimeSpan

Page 229: Visual C++

229

Serialize

Point.h

class CPoint3D : public CObject{public: DECLARE_SERIAL(CPoint3D) int m_x, m_y, m_z; CPoint3D(); CPoint3D(int x, int y, int z); void Serialize(CArchive& ar);};

Page 230: Visual C++

230

Cont’d

Point.cpp

#include "Point3D.h"IMPLEMENT_SERIAL(CPoint3D, CObject, 1 VERSIONABLE_SCHEMA)CPoint3D::CPoint3D( ){ m_x = m_y = m_z = 0;}CPoint3D::CPoint3D(int x, int y, int z){ m_x = x; m_y = y; m_z = z;}void CPoint3D::Serialize(CArchive& ar){ CObject::Serialize(ar); if(ar.IsStoring()) ar << m_x << m_y << m_z; else ar >> m_x >> m_y >> m_z;}

Page 231: Visual C++

231

Cont’d

main.cpp

void main(){ // 쓰기 TRY { CPoint3D point(10, 20, 30); CFile file; file.Open(_T("File.dat"), File::modeCreate | CFile::modeWrite); CArchive ar(&file, CArchive::store); ar << &point; } CATCH(CFileException, e) { e->ReportError(); } END_CATCH

Page 232: Visual C++

232

Cont’d

// 읽기 TRY { CPoint3D point; CFile file; file.Open(_T("File.dat"), File::modeRead); CArchive ar(&file, CArchive::load);

ar >> &point; TRACE("(%d, %d, %d)\n", point.m_x, point.m_y, point.m_z); } CATCH(CFileException, e) { e->ReportError(); } END_CATCH}

Page 233: Visual C++

233

버전관리 IMPLEMENT_SERIAL 매크로에서 버전을 숫자로 지정하고 VERSI

ONALBLE_SCHEMA 속성 지정• IMPLEMENT_SERIAL (CLine, CObject, 2 ¦ VERSIONABLE_SCHEMA)

CArchive::GetObjectSchema () • 저장된 버전을 리턴

주의 : CLine 클래스의 Serialize 함수를 명시적으로 호출하지 말고 >>, << 연산자를 사용하여야 함

CLine* pLine = new CLine (CPoint (0, 0), CPoint (100, 50));

ar << pLine;

CLine line (CPoint (0, 0), CPoint (100, 50));

ar << line; //ERROR!

Page 234: Visual C++

234

버전에 따른 로딩방법void CLine::Serialize (CArchive& ar)

{

CObject::Serialize (ar);

if (ar.IsStoring ())

ar << m_ptFrom << m_ptTo << m_clrLine;

else {

UINT nSchema = ar.GetObjectSchema ();

switch (nSchema) {

case 1: // Version 1 CLine

case 2: // Version 2 CLine

default: // Unknown version

AfxThrowArchiveException (CArchiveException::badSchema);

break;

}

}

}

Page 235: Visual C++

235

14. MFC Internals

Page 236: Visual C++

236

RTTI (Run-Time Type Information)

런타임시에 객체의 클래스 이름 얻기

class CObject{public:

virtual char* GetClassName() const { return NULL;}};

class CMyClass : public CObject{public:

static char s_lpszClassName[];virtual char* GetClassName() const { return s_lpszClassName;}

};

char CMyClass::s_lpszClassName[] = "CMyClass";

Page 237: Visual C++

237

MFC CRuntimeClass 구조체

MFC 에서는 CRuntimeClass 구조체가 앞 장에서의 static 멤버 s_lpszClassName 을 대신한다 .

DECLARE_DYNAMIC/IMPLEMENT_DYMANIC 매크로를 삽입하면 CRuntimeClass 구조체가 static 형의 class<class_name> 라는 이름을 가진 멤버변수 추가• ex) CMyClass static CRuntimeClass classCMyClass;

struct CRuntimeClass{

char m_lpszClassName[21];int m_nObjectSize;CObject* (*pfnCreateObject)();CObject* CreateObject();

};

Page 238: Visual C++

238

Run-time 시에 이름얻기

RUNTIME_CLASS 매크로• 클래스의 static 객체인 CRuntimeClass 에 대한 포인터는 RUNT

IME_CLASS 매크로로 얻어온다

GetRuntimeClass 함수는 클래스의 static 형인 CRuntimeClass 클래스 객체에 대한 포인터를 리턴

객체로부터 클래스 이름의 문자열을 얻으려면 가상함수인 virtual CObject::GetRuntimeClass() 를 호출

#define RUNTIME_CLASS(class_name) (&class_name::class##class_name)// 사용예ASSERT(RUNTIME_CLASS(CMyClass)->m_lpszClassName == "CMyClass";

ASSERT(pMyObject->GetRuntimeClass()->m_lpszClassName == "CMyClass");

virtual CRuntimeClass* GetRuntimeClass() const { return &classCMyClass; }

Page 239: Visual C++

239

동적생성

CreateObject 함수로 객체를 동적으로 생성

간접적으로 객체 생성하기

DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE 를 사용하면 동적 생성기능을 추가

static CObject* CMyClass::CreateObject() { return new CMyClass; }

CObject* CRuntimeClass::CreateObject() { return (*pfnCreateObject)(); }

CRuntimeClass* pRTC = RUNTIME_CLASS(CMyObject);

CMyClass* pMyObject = (CMyClass*)pRTC->CreateObjet();

Page 240: Visual C++

240

CObject Features

Run-time class information Dynamic creation Serialization Run-time object diagnostics

Page 241: Visual C++

241

Run-time Class Information

CObject 를 상속받고 DECLARE_DYNAMIC 매크로와 IMPLEMENT_DYNAMIC 매크로를 사용하면 run-time 시에 클래스의 정보를 얻을 수 있다 .

// MyClass.hclass CMyClass : public Object{

DECLARE_DYNAMIC(CMyClass);public:

CMyClass();};//MyClass.cppIMPLEMENT_DYNAMIC(CMyClass,CObject)DemoRTCI(){

CObject* pObject = new CMyClass;if (pObject->IsKindOf(RUNTIME_CLASS(CMyClass))){

CMyClass* pMyObject = (MyClass*) pObject;}

}

Page 242: Visual C++

242

Dynamic Creation

DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE 매크로를 사용하면 RTCI 기능과 함께 동적생성기능도 추가

Document/View 에서의 동적생성기능

CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CMyClass);CObject* pObject = pRuntimeClass->CreateObject();ASSERT(pObject->IsKindOf(RUNTIME_CLASS(CMyClass));

CMultiDocTemplate* pDocTemplate;pDocTemplate = new CMultiDocTemplate(

IDR_MAINFRAME,RUNTIME_CLASS(CLineDrawDoc),RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(CLineDrawView));

AddDocTemplate(pDocTemplate);

Page 243: Visual C++

243

Inside Document/View Architecture

CWindApp 클래스 내의 CDocManager 클래스가 CDocTemplate 을 관리• CDocManager* m_pDocManager;

CWinApp 의 도큐먼트 템플릿 관리 함수들은 CDocManager 의 함수들을 연결• AddDocTemplate(), GetFirstDocTemplatePosition(), GetNextDocTe

mplate(), OnFileNew(), OnFileOpen(), OpenDocumentFile(), SaveAllModified() ...

void CWinApp::AddDocTemplate(CDocTemplate* pTemplate){

if (m_pDocManager == NULL)m_pDocManager = new CDocManager;

m_pDocManager->AddDoTemplate(pTemplate);}

Page 244: Visual C++

244

Function Call Flow Chart

CWinApp::OnFileNew()

CDocTemplate::CreateNewFrame()

CDocTemplate::OpenDocumentFile()

CDocTemplate::CreateNewDocument()

WM_CREATE

CFrameWnd::OnCreateClient()

CFrameWnd::CreateView()

CMyDocument::OnOpenDocument()

CWinApp::OnFileOpen()

CDocManager::OnFileOpen() CDocManager::OnFileNew()

WM_INITIALUPDATE 메시지 발생