visual c++
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 PresentationTRANSCRIPT
1
Visual C++
2
0. C++ Review
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
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
5
Why MFC?
이해가 쉬움 • 연관된 함수와 데이타를 “
클래스”를 이용하여 그룹화하였음
코드의 재사용성 향상 소프트웨어 개발의 용이성
• 애플리케이션 프레임워크 (application framework) 제공
• 멤버 함수 나열• 코드 삽입의 용이성
응용프로그램
MFC
SDK API
운영체제
6
1. Hello, MFC
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
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
9
AFX Classes
어플리케이션 프로그램을 구성하는 오브젝트 단위로 분할 분리된 오브젝트는 철저하게 역할을 분담 프레임 윈도우와 뷰를 분리 도큐먼트와 뷰를 분리
C F ram eWnd C View C D oc um ent
( ) 윈 도 우 의 프 레 임 틀 을 관 리 데 이 터 를 보 여 주 는 윈 도 우 , 데 이 터 를 저 장 처 리( )눈 에 는 안 보 임
C WinApp
, ( )위 의 세 오 브 젝 트 를 묶 어 주 고 프 로 그 램 을 구 동 시 킴 눈 에 는 안 보 임
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 프 로 퍼 티 페 이 지 클 래 스
11
나머지 클래스들 그래픽 관련 클래스 자료 구조 클래스 파일 및 데이터베이스 관련 클래스 인터넷 관련 클래스 OLE 관련 클래스 에러 처리 및 디버깅을 위한 클래스
12
Hello, MFC
The Hello window program
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 ()};
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);}
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 기 반 클 래 스 파 생 클 래 스
16
CWinApp 클래스
CWinApp 클래스의 역할• 프로그램의 시작과 종료를 담당• 프로그램이 시작될 때 , 메인 프레임 윈도우를 생성• 무한루프를 돌면서 메시지를 뿌려줌• WM_QUIT 메시지를 만나면 무한루프를 빠져 나옴• 프로그램을 전체를 대표하는 기능들을 수행
CMyApp 클래스의 인스턴스가 유일하게 전역변수로 선언
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 ( )
상속
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 // ……};
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;}
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 다른 방식으로 처리됨
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 ; ..... }}
차 례 로 꺼 내 서 처 리 함
메 시 지
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);// 여기에 수행 하고자 하는 기능을 넣으면 됩니다 .
}
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 함수 오버라이딩
24
CFrameWnd 클래스
일반적인 윈도우로서의 역할• 프레임 윈도우도 일종의 윈도우
프레임 윈도우로서의 고유한 역할• 윈도우의 크기 , 위치 , 상태 등의 조절에 관한 일과 같은
윈도우로서의 역할 • 툴바와 상태바를 다는 것은 CFrameWnd 클래스에서 상속을 받은
파생 클래스에서 추가• OnCreate 함수를 오버라이딩 하고 , 그 함수 안에다가 툴바와
상태바를 생성시켜 메다는 기능을 추가• 오버라이딩 된 OnCreate 함수에서 기반 클래스의 OnCreate
함수를 반드시 호출
int CMyWnd::OnCreate(LPCREATESTRUCT lpCreateStruct){ CWnd::OnCreate(lpCreateStruct); // 여기에 수행 하고자 하는 기능을 넣으면 됩니다 .}
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()};
26
AFX 전체구조CF rameW nd
CW inA pp
CDocument
CV iew
CM y A pp ( )클 래 스 의 인 스 턴 스 전 역 변 수
protected/pr ivate 멤 버
멤 버 함 수
멤 버 변 수
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};
28
CView 클래스
GetDocument()• 도큐먼트 오브젝트의 포인터를 얻는 함수
OnDraw()• 각각 도큐먼트에서 데이터를 가져와 그리는 기능을 수행하는
함수 OnXXXPrinting()
• 프린터 출력에 관한 함수
29
CDocument 클래스
CDocument 클래스의 역할• 파일로부터 데이터를 읽어오는 기능 (“ 파일” 메뉴의 “열기” 기능 )• 파일에 데이터를 저장하는 기능 (“ 파일” 메뉴의 “저장” 기능 )• 새로운 데이터를 만드는 기능 (“ 파일” 메뉴의 “새 파일” 기능 )• 작업 중인 데이터를 닫는 기능 (“ 파일” 메뉴의 “닫기” 기능 )• 데이터가 변경된 사실을 뷰 오브젝트에 알리는 기능
// MyDoc.hclass CMyDoc : public CDocument{protected: // create from serialization only CMyDoc();// Overrides public: virtual BOOL OnNewDocument();// Implementationpublic: virtual ~CMyDoc();};
30
Framework 클래스간 상호참조
CFrameWnd
CDocument CView
GetActiveDocument
GetFirstViewPositionGetNextView
GetParentFrame
GetActiveView
GetDocument
AfxGetApp
AfxGetMainWnd
31
Framework 클래스간 상호참조 전역함수
• CWinApp* AfxGetApp( ) CWinApp 파생 클래스의 인스턴스 포인터를 반환 프로그램 상의 어디에서든 참조 가능
• CWnd* AfxGetMainWnd( ) 메인 프레임 클래스의 인스턴스 포인터를 반환 프로그램 상의 어디에서든 참조 가능
프레임 윈도우 클래스에서 도큐먼트 / 뷰 참조• virtual CDocument* GetActiveDocument( )
프레임 윈도우 클래스에서 도큐먼트 클래스를 참조• CView* GetActiveView( ) const
현재 프레임 윈도우와 연결된 뷰 클래스의 인스턴스 포인터를 반환
32
Framework 클래스간 상호참조 프레임 윈도우 클래스에서 도큐먼트 / 뷰 참조
• virtual CDocument* GetActiveDocument( ) 현재 프레임 윈도우와 연결된 도큐먼트 클래스의 인스턴스 포인터를
반환• CView* GetActiveView( ) const
함수는 현재 프레임 윈도우와 연결된 뷰 클래스의 인스턴스 포인터를 반환
뷰 클래스에서 프레임 윈도우 / 도큐먼트 참조• CFrameWnd* GetParentFrame( ) const
뷰 클래스에서 그 뷰를 둘러싸고 있는 프레임 윈도우를 참조• CDocument* GetDocument( ) const
뷰 클래스에서 그 뷰와 연결된 도큐먼트 클래스를 참조
33
Framework 클래스간 상호참조 도큐먼트 클래스에서 뷰 참조
• CDocument::GetFirstViewPosition, GetNextView 하나의 도큐먼트에 여러 개의 뷰가 결합 도큐먼트에는 이와 연결된 뷰가 연결 리스트 구조로 관리
도큐먼트 클래스에서 프레임 윈도우 참조 • SDI : AfxGetMainWnd 함수를 호출• MDI : 뷰를 거쳐서 참조
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
pView->UpdateWindow();
}
34
메시지를 이용한 통신 CWnd::SendMessage
• 메시지가 메시지 큐를 거치지 않음 CWnd::PostMessage
• 메시지를 메시지 큐에 넣어줌
CWinApp 클래스나 CDocument 파생 클래스에서는 XxxxMessage 함수 호출 불가능
AfxGetMainWnd( )->XxxxMessage( …, …, …)
35
실습 “Hello MFC” 프로그램 작성
• Project->Win32 Application• Project menu->settings(alt+F7)->general->Use MFC in a Shared D
LL Menu 달기 System 메뉴없애기 Minimize,Maximize 버튼 없애기 초기 윈도우 크기 , 위치 바꾸기
36
2. Menu
37
Menu 편집 메뉴 항목을 선택하고 , ID 와 Caption 을 편집
선택된 메뉴 항목
ID선택된 메뉴 항목의
메뉴에 실제 출력될 문자열
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 ();
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 ();
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);
}
41
Command Message
프로그램 실행 중에 메뉴가 선택되면 , WM_COMMAND 라는 윈도우 메시지가 발생
어떤 메뉴가 눌렸는지를 구별하기 위해 메뉴의 ID 가 추가적인 정보로 전달
만일 OnCommand 라는 메시지 핸들러에서 처리를 하면 할 일이 너무 많아짐
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 거 의 모 든 클 래 스 의 기 반 클 래 스
커 맨 드 메 세 지 를 받 는 기 능
프 로 그 램 을 구 동 시 키 는 기 능
데 이 터 를 저 장 하 고 처 리 하 는 기 능
( )윈 도 우 에 관 련 된 기 능 눈 에 보 이 는 오 브 젝 트
( ) 프 로 그 램 윈 도 우 프 레 임 외 곽 을 관 리 하 는 기 능
데 이 터 를 보 여 주 는 윈 도 우 관 리 하 는 기 능
43
Command Message 처리 프로그램의 데이터를 처리하는 기능 CDocument 파생
클래스 데이터를 화면에 표시하는 방법 CView 파생 클래스 프로그램의 시작과 종료에 관련된 커맨드 CWinApp 파생
클래스 프레임 윈도우의 제어에 관계된 커맨드를 처리 CFrameWnd
파생 클래스
CView 파생 클래스
CDocum ent 파생 클래스
CFram eW nd 파생 클래스
CW inApp 파생 클래스
W M_COMMAND 메시지 전달 순서
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;
}
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;
}
46
3. Graphic Device Interface
47
GDI
그래픽 디바이스 인터페이스 (GDI: Graphic Device Interface)• 그래픽 기능과 관련해서 윈도우 운영체제가 어플리케이션
프로그램에 제공하는 모든 기능 디바이스 컨텍스트 (DC: Device Context)
• 그래픽에 필요한 모든 옵션을 한곳에 모아둔 구조체 GDI 오브젝트 (GDI Object)
• 독립적으로 저장되는 각 범주의 그래픽 옵션 범주 GDI 오브젝트 기본값
선 그리기 옵션 펜 (Pen) 1 픽셀 굵기의 검은색 실선
영역의 내부를 채우
는 옵션 브러시 ( Brush) 단일 흰색 브러시
글꼴 옵션 글꼴 (Font) 시스템 글꼴
비트맵 옵션 비트맵 (Bitmap) 없음
팔레트 옵션 팔레트 (Palette) 없음
영역 옵션 영역 (Region) 없음
48
그래픽 관련 MFC 클래스 CDC 클래스
• GDI 오브젝트를 통해 그래픽에 관련된 옵션을 저장 • 모든 그래픽 함수들은 CDC 클래스의 멤버 함수
• 하위 클래스 CClientDC CWindowDC CPaintDC CMetaFileDC
CDC *pDC = GetDC();
pDC->Rectangle(10, 10, 100, 100);
ReleaseDC(pDC);
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);
50
GDI 오브젝트 클래스 그래픽 옵션을 바꿔 주려면 새로운 설정을 갖는 GDI 오브젝트
클래스를 생성한 후에 이것을 DC 에 넣고 , 이 DC 를 이용하여 그림을 그림
GDI 오브젝트 MFC 클래스
펜 CPen
브러시 ( 붓) CBrush
글꼴 CFont
비트맵 CBitmap
팔레트 CPalette
영역 CRgn
51
펜과 브러시 펜과 브러시를 이용한 그래픽
• 현재 DC 에 설정되어 있는 펜을 이용하여 경계선을 그림• 폐곡선일 경우 안쪽을 현재 DC 에 설정되어 있는 브러시로 채움
함수 그리기 기능
MoveTo, LineTo 선
Rectangle, FillRect, FrameRect, Draw3dRect 사각형
Ellipse 타원
Pie 파이
Arc, ArcTo, AngleArc, Chord 호
Polygon 다각형
PolyDraw, PolyBezier, PolyBezierTo 베지어 곡선
FrameRgn 영역의 경계선
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
어떤 문제가 존재 ?
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);
54
내장 (Stock) GDI 오브젝트 자주 쓰이는 스타일의 GDI 오브젝트는 윈도우 운영체제가
내장 GetStockObject 함수 사용
내장 오브젝트는 항상 메모리에 상주
CClientDC dc;
dc.SelectObject( GetStockObject(WHITE_PEN) );
55
실습 튀는 공 예제 프로그램
56
레스터 오퍼레이션
새로 그릴 그림과 기존에 그려져 있는 그림을 합성 int SetROP2( int nDrawMode )
• R2_COPYPEN 새로이 그려지는 그림으로 화면에 덮어 그림
• R2_XORPEN 배경을 깨뜨리지 않고 , 배경 위에서 움직이는 그림을 그릴 때 사용 똑같은 그림을 두 번 그려주면 원래 있던 바탕색이 복원
바탕색 출력되는 색
흰색 새로 그려진 색이 반전되어 출력됩니다.
검정색 새로 그려진 색이 그대로 출력됩니다.
임의의 색 새로 그려진 색과 바탕색이 XOR 연산되어 출력되는데,
이 값은 바탕색과 새로 그려진 색 양쪽과 모두 무관한
엉뚱한 색이 됩니다.
57
실습 마우스를 드래그 해서 선을 그릴 수 있는 프로그램
58
4. Dialog Box and Controls
59
다이얼로그 박스 프로그램 수행 도중 사용자의 입력이 필요할 때 다이얼로그
박스 출력 다이얼로그 박스는 사용자로부터 입력 받은 데이터를 메인
루틴에 넘기고 소멸 다이얼로그 템플릿
• 다이얼로그 박스가 생성될 때 사용될 다이얼로그 박스의 모양에 대한 설계도
• 리소스 파일에 저장
60
다이얼로그 박스 속성 설정 Caption: 항목에는 다이얼로그 박스의 타이틀 Font : 다이얼로그에서 사용하는 글꼴 설정 Styles : 다이얼로그 박스의 스타일 설정
61
다이얼로그 박스 클래스 CWnd 클래스 상속
• CWnd 클래스에 있는 윈도우를 제어 기능 함수와 윈도우 메시지 핸들러 함수를 모두 이용
CDialog 클래스를 상속을 받아서 사용• cf) 컨트롤은 MFC 클래스를 그대로 사용
CObject
CWnd
CDialog
62
다이얼로그 박스 만들기 (1/2)
CDialog 파생 클래스 만들기
class CNameDlg : public CDialog
{
//…
enum { IDD = IDD_DIALOG1 };
//…
};
63
다이얼로그 박스 만들기 (2/2)
CDialog 파생 클래스의 인스턴스 만들어 사용하기 사용자의 입력을 받는 일은 다이얼로그 박스에 일임
#include “NameDlg.h”
void CDlgTestView::OnDialog( )
{
CNameDlg dlg; // CDialog 파생 클래스의 인스턴스를 생성
dlg.DoModal( ); // CDialog 클래스의 멤버 함수를 호출
// 다이얼로그 박스에서 입력 받은 값을 이용하는 루틴…
}
64
CDialog 클래스의 기능
다이얼로그 박스와 컨트롤의 생성 메시지 핸들러 함수 커맨드 메시지 핸들러 함수 다이얼로그 박스는 확인 (OK) 버튼과 취소 (Cancel) 버튼과
각각의 메시지 핸들러를 가지고 있슴 #include “NameDlg.h”
void CDlgTestView::OnDialog( )
{
CNameDlg dlg;
if( dlg.DoModal( ) == IDOK)
{
// OK 버튼이 눌렸을 때만 실행되는 부분
// 다이얼로그 박스에서 입력 받은 값을 이용하는 루틴…
}
}
65
CDialog 파생 클래스에 추가해야 하는 기능
사용자가 컨트롤에 입력한 내용을 관리• 사용자의 입력 내용을 컨트롤로부터 획득
컨트롤 자체를 하나의 윈도우로 보고 제어• Show/Hide• 활성화 / 비활성화
66
Value 형 멤버변수 컨트롤에 입력된 값과 연결된 CDialog 파생 클래스의 멤버
변수 MFC 는 컨트롤과 변수를 연결하여 컨트롤에 입력된 값을
변수에 저장 변수에 설정된 값을 컨트롤에 입력하는 것을 자동으로 수행
다이얼로그 박스
홍길동
28
:이름
:나이
OK Cancel
CString m_strName
int m_nAge
CDialog ÆÄ»ý Ŭ·¡½º
Value Çü ¸â¹ö º¯¼ö
67
컨트롤과 Value 형 멤버 변수 연결 다이얼로그 템플릿에서 Value 형 멤버 변수와 연결시키려는
컨트롤을 선택 [Ctrl] 키를 누른 상태에서 마우스 버튼을 더블 클릭
변수형을 선택
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
}
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)
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
}
71
받을 문자열의 최대 길이를 지정
72
유효한 입력의 범위 설정 유효한 입력의 범위를 최대값 (Maximum Value) 과 최소값 (Mini
mum Value) 으로 설정
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
}
74
UpdateData 함수의 동작 과정
UpdateData(TRUE)1. DoDataExchang 함수가 호출2. DDV_ 로 시작되는 함수들이 호출3. DDX_ 로 시작하는 함수들이 호출
UpdateData(FALSE)1. DoDataExchang 함수가 호출 2. DDX_ 로 시작하는 함수들이 호출
75
컨트롤에 따른 Value 형 멤버 변수 편집 박스 컨트롤 CStiring,int,UINT,long,DWORD,float,double,B
YTE,short,BOOL,COleDateTime,COleCurrency 리스트 박스 컨트롤과 콤보 박스 컨트롤
• CString 체크 박스 컨트롤
• BOOL
76
컨트롤에 따른 Value 형 멤버 변수 라디오 버튼 컨트롤
• Group 속성을 가진 라디오 버튼 컨트롤에서부터 다음 Group 속성을 가진 라디오 버튼 컨트롤까지가 하나의 범주
• Group 속성을 가진 컨트롤이 대표로 Value 형 멤버 변수와 연결• int
77
Control 형 멤버 변수 MFC 에는 모든 컨트롤들이 클래스로 구성 컨트롤을 Control 형 멤버 변수와 연결하여 제어 모든 컨트롤 클래스의 기반 클래스는 CWnd
78
CWnd 클래스
Create• 윈도우를 생성
ShowWindow• SW_SHOW ,SW_HIDE
EnableWindow• 윈도우를 활성화 시키거나 비활성화 시킴
SetWindowPos• 윈도우의 크기와 위치를 변경
SetWindowText• 윈도우의 메인 텍스트를 변경
79
CEdit 클래스
GetSel• 선택된 부분의 문자열을 얻어옴
SetSel• 특정 부분을 선택 영역으로 설정
ReplaceSel• 선택된 부분의 텍스트를 지정한 텍스트로 치환
GetLineCount• 편집 박스의 텍스트의 줄 수 반환
GetLine• 지정된 라인의 텍스트를 얻어옴
80
CButton 클래스
푸시 버튼 , 체크 박스 버튼 , 라디오 버튼 GetCheck
• 버튼이 눌려진 상태를 얻어옴 SetCheck
• 버튼의 눌려짐 상태를 설정
81
CScrollBar 클래스
GetScrollRange• 스크롤바 컨트롤의 증감범위 반환
SetScrollRange• 스크롤바 컨트롤의 증감범위 설정
GetScrollPos• 스크롤바 컨트롤에 현재 설정된 값 반환
SetScrollPos• 스크롤바 컨트롤에 값 설정
82
CListBox 클래스와 CComboBox 클래스
GetCount • 컨트롤에 들어있는 총 문자열의 수를 반환
GetCurSel, SetCurSel• 선택된 문자열의 인덱스 반환하거나 설정• 인덱스는 0 부터 시작
AddString, InsertString• 문자열을 추가
DeleteString,ResetContent• 문자열을 삭제
Dir
83
컨트롤의 제어 WM_INITDIALOG 메시지 (OnInitDialog 메시지 핸들러 함수 )
• 컨트롤의 초기화 루틴은 여기 들어간다 . 통지 (NOTIFICATION) 메시지
• 통지 메시지는 컨트롤에 발생한 사건을 알려주기 위해 그 컨트롤을 품고 있는 부모 윈도우인 다이얼로그 박스로 메시지를 보냄
통지 메시지의 전달• 통지 메시지는 다이얼로그로 전달이 된다 .
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
85
모달리스 다이얼로그 박스
모달 다이얼로그 박스• 다이얼로그 박스가 출력되어 있는 동안에는 그 다이얼로그
박스가 프로그램의 모든 제어권을 독점 모달리스 다이얼로그 박스
• 다이얼로그 박스가 프로그램의 제어권을 독점하지 않음
모달 모달리스
생성 방법 DoModal 함수 Create 함수
종료 방법 EndDialog 함수 DestroyWindow 함수
인스턴스 선언 지역 변수로 선언 동적으로 할당
86
생성 방법 Modal Dialog
• DoModal 함수로 생성• 다이얼로그 박스가 종료되면 각각 IDOK 또는 IDCANCEL
Modaless Dialog• Create 멤버 함수를 호출하여 생성• 모달리스 다이얼로그 박스를 생성시킨 후 바로 리턴
87
종료 방법 Modal Dialog
• EndDialog 함수 호출• OnOK 멤버 함수에서는 EndDialog(IDOK) 가 호출• OnCancel 멤버 함수에서는 EndDialog(IDCANCEL) 가 호출
Modaless Dialog• EndDialog 함수를 호출 금지• DestroyWindow 함수를 이용하여 종료• OnOK 함수나 OnCancel 함수를 오버라이딩시 CDialog 클래스의
OnOK 함수나 OnCancel 함수가 호출되지 않도록 주의
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();
}
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;
}
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);
}
}
91
다이얼로그 박스 기반 어플리케이션
92
다이얼로그 박스 기반 어플리케이션 CWinApp 파생 클래스와 CDialog 파생 클래스 만으로 구성
BOOL CDlgAppApp::InitInstance()
{
//…
CDlgAppDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
//…
return FALSE;
}
93
5. 사용자 인터페이스
94
메인 프레임 윈도우에 메뉴 표시 BOOL CCmdUIApp::InitInstance( )
{
//…
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CCmdUIDoc),
RUNTIME_CLASS(CCmdUIView),
RUNTIME_CLASS(CMainFrame));
AddDocTemplate(pDocTemplate);
//…
}
95
다이얼로그 박스에 메뉴 표시
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 – 클릭하면 컨텍스트 메뉴를 사라지게 할 영역
97
단축키 정의 Resource Accelerator
98
단축키가 정의된 커맨드의 메뉴 캡션 “ 새 파일 (&N)\tCtrl+N” , “\t” 뒤에 씌여진 문자열은 메뉴의 우측에 정렬 &N 은 사용자가 alt 키를 사용하여 메뉴접근시의 단축키
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)
{
}
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) { }
101
CCmdUI 클래스
CCmdUI 클래스는 사용자 인터페이스 갱신과 관련된 기능을 담당하는 클래스
m_nID : command ID
멤버 함수 기능
Enable BOOL 형 인자를 받아, 사용자 인터페이스를 활성화
또는 비활성화 시킵니다.
SetText 사용자 인터페이스의 텍스트를 변경시켜 줍니다.
SetCheck int 형 인자를 받아, 체크 표시를 하거나 체크 표시를
없앱니다.
SetRadio SetCheck 함수와 비슷한 기능을 하나, 체크 표시를 점
으로 찍어 줍니다.
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);}
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)");
}
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);
}
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; }
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); }
107
CCmdUI::SetRadio 함수
SetCheck 와 동일
void CMainFrame::OnUpdateColorRadio(CCmdUI* pCmdUI)
{
pCmdUI->SetRadio(m_nColorRadio == pCmdUI->m_nID);
}
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;
}
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 추가
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
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)
112
다이얼로그 바 버튼 외의 다른 컨트롤들을 많이 사용해야 한다면 툴바보다
다이얼로그 바를 사용 컴포넌트 갤러리를 이용하여 다이얼로그 바 만들기
• Project – Add to project – Components and controls
113
상태바
클래스 인스턴스 생성class CMainFrame : public CFrameWnd
{
//…
CStatusBar m_wndStatusBar;
//…
}
Create 로 생성후 SetIndicators 함수로 상태바를 팬으로 분할
프레임 윈도우
ID_SEPARATOR
ID_INDICATOR_CAPS
ID_INDICATOR_NUM
CAP SCRLNUM
ID_INDICATOR_SCRL
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;
}
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 );
116
실습 상태바에 현재 마우스의 위치 표시
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
118
메시지 박스 디폴트 버튼 설정
• MB_DEFBUTTON1, MB_DEFBUTTON2, MB_DEFBUTTON3 모달리티 설정
• MB_APPLMODAL • MB_SYSTEMMODAL
리턴값• IDABORT• IDCANCEL• IDIGNORE• IDNO• IDOK• IDRETRY• IDYES
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 함수 호출 금지 !
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( );
}
121
6. Control
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
123
Button
버튼의 생성CButton m_wndPushButton;m_wndPushButton.Create (_T ("Start"), WS_CHILD ¦ WS_VISIBLE ¦ B
S_PUSHBUTTON, rect, this, IDC_BUTTON);
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
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!"));}
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);
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);
}
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);
129
Group Box
BS_GROUPBOX 로 생성 부모에게 어떤 메시지도 보내지 않음 단지 시각적 효과만 제공
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
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);
}
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);
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);
134
7. MDI (Multiple Document Interface)
135
분할윈도우 동적 분할 윈도우 (Dynamic Split Window)
• 프로그램이 실행 중에 윈도우를 분할 가능• 같은 데이터를 같은 방식으로 보여주되 , 스크롤바를 이용하여
서로 다른 부분을 디스플레이 정적 분할 윈도우 (Static Split Window)
• 윈도우가 분할된 상태로 프로그램이 시작되고 , 프로그램 실행 중에 분할된 윈도우 병합불가능
• 이용하면 같은 데이터라도 완전히 방식으로 표현가능
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;}
137
SDI vs. MDI
138
SDI vs. MDI
CMDIFrameWnd 와 CMDIChildWnd 클래스는 CFrameWnd 클래스에서 상속 프레임윈도우의 기능 가짐
CMDIFrameWnd 클래스에는 CMDIChildWnd 클래스를 관리 CMDIChildWnd 클래스에는 CMDIFrameWnd 의 안쪽에
들어가서 클래스의 관리를 받음
CWnd
CFrameWnd
CMDIFrameWnd
CMDIChildWnd
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;
140
MDI 를 SDI 로 변환
1. 자식 프레임 윈도우 삭제 2. 메인 프레임 윈도우의 기반 클래스 변경3. 도큐먼트 , 프레임 윈도우 , 뷰 등록4. 메인 프레임 생성5. 메인 프레임 윈도우에 동적 생성기능 추가
• MainFrame 에 있는 DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC 을 DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE 로 변환
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( );
} } }}
142
파일 메뉴 처리
ID _F ILE_N EW
ID _FILE_O PEN
ID _FILE_SAVE
ID _FILE_SAVE_AS
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( ) 함 수 와 같 은 동 작
144
Serialize
void CMyDoc::Serialize(CArchive& ar){
if (ar.IsStoring()){
// 저장하기ar << n;
}else{
// 읽어오기 ar >> n;
}}
145
다중 도큐먼트 타입 MDI
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);// …
}
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 레지스트리에 저장되는 도큐먼트 유형 이름
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
149
OnFileNew
void CDrawApp::OnFileNew()
{
POSITION pos = GetFirstDocTemplatePosition( );
CDocTemplate *pTemplate;
for(int i=0 ; i<N ; i++)
pTemplate = GetNextDocTemplate(pos);
pTemplate->OpenDocumentFile(NULL);
}
150
OnFileOpen
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));
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.
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.
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
155
CDocument & CView Interaction
GetFirstViewPosition, GetNextView
GetDocument
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CView* pView = GetNextView(pos);
pView->Invalidate();
}
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 );
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();
//…
}
158
8. Serialization
159
데이터 저장 및 읽어오기 CObject 클래스에는 데이터를 저장하고 읽어오는 Serialize
함수가 존재 CObject 를 상속받은 클래스는 Serialize 함수를 이용하여
멤버변수의 값을 읽고 저장가능 Serialize 함수를 오버로딩하여 사용
160
Serialize 함수의 호출 CDocument 파생 클래스는 CObject 클래스의 Serialize
함수를 오버라이딩하고 있슴 CDocument 파생 클래스에서 Serialize 함수를 오버라이딩
하면 멤버 변수를 디스크에 저장하거나 읽어올 수 있슴
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
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( ) 함 수 와 같 은 동 작
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;
}}
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
네 트 워 크디 스 크
메 모 리
165
데이터 저장 및 읽어오기
방법 CDocument 클래스의 OnOpenDocument 함수와 OnSaveDo
cument 함수를 오버라이딩하여 각각 데이터를 읽어오는 루틴과 저장하는 루틴을 삽입
CDocument 클래스의 Serialize 함수를 오버라이딩 해서 데이터를 읽어오는 루틴과 저장하는 루틴을 함께 구현
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);}
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];
}}
}
168
9. Collection Class
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).
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 );
}
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;
172
10. 고급그래픽
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
174
Bitmap GDI Object
비트맵 GDI 오브젝트• 윈도우에서는 비트맵을 하나의 GDI 오브젝트로 채택 • CBitmap 클래스 cf) CPen , CBrush
그래픽 함수들은 GDI 오브젝트를 참조하여 그래픽 작업 수행 비트맵 GDI 오브젝트를 참조하는 그래픽 함수
• BitBlt Bit Block Transfer 의 약자 임의의 DC 에서 다른 DC 로 비트맵 블록을 전송
• StretchBlt 임의이 DC 에서 다른 DC 로 비트맵 블록을 전송하되 , 확대
또는 축소를 해서 전송• cf) 다른 그래픽함수와 달리 DC 가 2 개가 필요
175
비트맵을 출력시키는 전체 과정
윈도우
(x, y)nWidth
nHeight
MemDCWinDC
BitBlt
(xSrc, ySrc)
CBitmap
SelectObject
Resource
LoadBitmap
176
화면 DC 와 메모리 DC 만들기 비트맵이 출력될 화면 윈도우의 DC
• CClientDC WinDC(this); 메모리에 만들어진 DC
• CDC MemDC; 메모리 상에 존재하는 MemDC 로부터 화면 윈도우로부터
얻어진 WinDC 로 비트맵 블록을 전송
177
화면 DC 와 호환성을 갖는 메모리 DC 만들기 비트맵 블록 전송을 위하여는 DC 간에 호환성을 가져야 한다 . MemDC.CreateCompatibleDC(&WinDC);
• MemDC 와 WinDC 는 호환성을 갖게 되어 서로 비트맵 블록 전송이 가능
178
비트맵 읽어오기 비트맵 데이터를 읽어오고 , 관리하는 기능은 CBitmap
클래스가 수행 리소스에 저장되어 있는 비트맵 데이터 로드
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
비트맵을 DC 에 선택 • CBitmap *pOldBitmap = (CBitmap )MemDC.SelectObject(&bitmap);
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 래스터 오퍼레이션 코드
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);
}
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);
}
182
배경과 합성
마스크이미지와 배경이미지를 AND 연산
비트맵과 OR 연산
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);
184
메모리 비트맵 화면에는 보이지 않고 , 메모리 상에만 존재 하는 비트맵 고속 그래픽 출력을 위한 버퍼 로 사용 ( 더블버퍼링 )
• 여러 출력 함수를 호출하면 그려지는 과정이 드러나면서 화면이 깜박거려 보임
비트맵을 블록 단위로 전송하는 것은 아주 고속으로 수행
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);
186
11. 고급 컨트롤 제어
187
컨트롤 서브클래싱
어떤 윈도우에 보내지는 메시지를 그 윈도우가 받기 전에 다른 윈도우에서 가로채어 처리하는 프로그래밍 테크닉
서브클래싱에 의한 기능 수정 컨트롤의 기능 중 수정하고자 하는 기능이 있으면
서브클래싱을 이용 컨트롤의 서브클래싱
• 다이얼로그 템플릿을 이용하여 생성되는 원래 컨트롤 클래스를 그대로 두고 , 그 컨트롤로 가는 메시지를 가로채어 컨트롤의 동작을 변경
• BOOL SubclassDlgItem(UINT nID, CWnd *pWnd) nID : 서브클래싱하고자 하는 컨트롤의 다이얼로그
템플릿에서의 ID pWnd : 컨트롤의 부모 윈도우의 포인터
• 실제 프로그래밍을 할 때는 SubclassDlgItem 함수를 직접 호출해주지 않아도 됨
188
컨트롤 서브클래싱
구현할 기능
숫자 이외의 다른 문자를 입력하면 경고음이 출력
189
컨트롤 서브클래싱
새로운 기능을 구현할 CEdit 파생 클래스
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);
}
191
Control 형 멤버 변수 연결 다이얼로그 박스에 올라가 있는 편집 상자 컨트롤의 메시지를
가로채서 동작하도록 서브클래싱
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
}
193
프로퍼티시트 프로퍼티 시트 (Property Sheet)
• 여러 개의 탭으로 이루어진 페이지들을 함께 가지고 있는 일종의 다이얼로그 박스
Property Sheet
Property Page Page 2 Page 3
확인 취소 적용
194
프로퍼티 시트와 프로퍼티 페이지 클래스 CProprtyPage 클래스가 CDialog 클래스에서 상속 CPropertySheet 클래스는 CDialog 에서 상속을 받지 않음
CWnd
CPropertySheet
CDialog
CPropertyPage
195
프로퍼티 페이지 만들기 다이얼로그 템플릿 디자인
196
프로퍼티 페이지 만들기 프로퍼티 페이지 클래스 만들기
197
프로퍼티 시트 만들기 프로퍼티 시트 클래스 만들기
198
프로퍼티 시트에 프로퍼티 페이지 등록 프로퍼티 시트에 프로퍼티 페이지를 등록하려면 프로퍼티 시트
클래스에 프로퍼티 페이지의 인스턴스가 있어야 함
#include "page1.h"
#include "page2.h"
#include "page3.h"
class CSheetDlg : public CPropertySheet
{
//…
CPage1 m_page1;
CPage2 m_page2;
CPage3 m_page3;
//…
}
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);
}
200
프로퍼티 시트를 다이얼로그 박스처럼 출력하기 DoModal 함수를 호출하면 프로퍼티 시트가 다이얼로그
박스처럼 화면에 출력
프로퍼티 시트의 타이틀 바에 출력될 문자열
#include “SheetDlg.h”
void CPropertyView::OnPropertysheet()
{
CSheetDlg dlg(IDS_SHEET);
dlg.DoModal();
}
201
위저드 형식 다이얼로그 박스 만들기
위저드 형식으로 옵션 변경
void CPropertyView::OnWizard() {
CSheetDlg dlg(IDS_SHEET);dlg.SetWizardMode( );if(dlg.DoModal() == ID_WIZFINISH){
AfxMessageBox(dlg.UserInput());}
}
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 설정
203
12. 고급 사용자 인터페이스
204
메뉴 메인 메뉴얻기
• CMenu* CWnd::GetMenu( ) const; 팝업 메뉴 ( 서브 메뉴 ) 얻기
• CMenu* CMenu::GetSubMenu( int nPos ) const;
사용법
CMenu*pMainMenu = GetMenu( );
CMenu *pPopupMenu = pMainMenu->GetSubMenu(2);
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( );
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);
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)");
}
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);
}
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);}
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);
}
}
}
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); // 트래커 표시
}
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);
}
213
13. 파일 입출력
214
CFile 클래스 – 파일 열기
파일 열고 닫기
파일 접근 모드
CFile file;file.Open(_T(“File.txt”), CFile::modeReadWrite);// … 파일에 데이터를 읽거나 쓰는 작업을 수행file.Close( );
접근 모드 설명
CFile::modeRead 파일을 읽기만 할 수 있습니다 .
CFile::modeWrite 파일에 쓰기만 할 수 있습니다 .
CFile::modeReadWrite 읽고 쓰기를 모두 할 수 있습니다 .
CFile::modeCreate 파일을 새로이 생성합니다 .
CFile::modeNoTruncate 기존에 있는 파일에 데이터를 기존의 파일을 덮어쓰지 않고 ,
맨 뒤에 추가해 줍니다 .
215
CFile 클래스
파일 공유 모드
공유 모드 설명
CFile::shareDenyNone 공유하도록 파일을 엽니다 .
CFile::shareDenyRead 다른 프로그램의 읽기 접근을 거부합니다 .
CFile::shareDenyWrite 다른 프로그램의 쓰기 접근을 거부합니다 .
CFile::shareExclusive 다른 프로그램의 읽기 , 쓰기를 모두 거부합니다 . (기본값 )
file.Open(_T(“File.txt”), CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate);
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( );
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}
218
CFile 클래스
기타 파일 처리 함수
멤버 함수 설명
GetFilePath 파일의 전체 경로명을 반환합니다 .
GetFileName 파일 이름을 반환합니다 .
GetFileTit le 확장자를 제외한 파일 이름을 반환합니다 .
GetStatus 파일이 생성된 시간 , 최종 변경된 시간 , 크기 , 속성 등 파일의 상태를
얻습니다 .
SetStatus 파일의 상태를 지정합니다 .
Remove 파일을 지웁니다 .
Rename 파일의 이름을 바꿉니다 .
219
CArchive 클래스
CDocument 클래스와 CFile 클래스를 연결해 주기 위한 클래스
C D ocum ent
C Archive
C F ileC M em File C SocketF ile
Seria lize
네 트 워 크디 스 크
메 모 리
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;
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);
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();}
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 - 대화상자의 부모 윈도우를 지정
224
CFileDialog 클래스 속성
파일 대화상자에 지정할 수 있는 속성 플래그
플래그 의미
OFN_EXPLORER 윈도우 탐색기 스타일로 출력합니다 .
OFN_ARROWMULTISELECT 파일을 한번에 여러 개 선택할 수 있습니다 .
OFN_CREATEPROMPT 존재하지 않는 파일명을 입력했을 경우 새로 생성하
겠냐는 메시지 박스를 출력합니다 .
OFN_FILEMUSTEXIST 존재하지 않는 파일명을 입력할 수 없도록 합니다 .
OFN_HIDEREADONLY 읽기 전용 파일은 출력하지 않습니다 .
OFN_LONGNAMES 긴 파일 이름 포맷을 지원하도록 합니다 .
OFN_OVERWRITEPROMPT 존재하는 파일명을 입력했을 경우 덮어쓰겠냐는 메
시지 박스를 출력합니다 .
OFN_PATHMUSTEXIST 이미 존재하는 디렉터리명만을 입력할 수 있습니다 .
225
CFileDialog 클래스의 멤버 함수
다음 멤버 함수들을 호출하여 사용자의 입력 결과를 참조
함수 반환값
CString GetPathName 선택된 파일의 절대 경로
CString GetFileName 선택된 파일의 파일명과 확장자
CString GetFileExt 선택된 파일의 확장자
CString GetFIleTitle 선택된 파일의 파일명
BOOL GetReadOnlyPref 읽기 전용 여부
POSITION GetStartPosition
CString GetNextPathName
다중 선택의 경우
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; }}
227
Serialize 가능한 클래스 만들기
1. CObject 클래스로부터 직접 또는 간접적으로 상속을 받습니다 .2. 생성자 함수를 만들어 줍니다 .3. 헤더 파일에 DECLARE_SERIAL 매크로를 적어 줍니다 .4. 소스 파일에 IMPLEMENT_SERIAL 매크로를 적어 줍니다 .5. Serialize 함수를 재정의 해서 데이터를 저장하는 루틴을
넣어줍니다 .
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
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);};
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;}
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
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}
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!
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;
}
}
}
235
14. MFC Internals
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";
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();
};
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; }
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();
240
CObject Features
Run-time class information Dynamic creation Serialization Run-time object diagnostics
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;}
}
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);
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);}
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 메시지 발생