Transcript Part 1
ISLab ICE HUFS Windows Programming 박상원 [email protected] 한국외국어대학교 정보통신공학과 ISLab ICE HUFS 서론 목차 • 객체지향이란? • MFC의 역사 • MFC를 위한 C++의 기초 ISLab ICE HUFS MFC Tutorial 3 객체지향 개념의 등장 배경 • 프로그래밍 언어의 발전 – 기계어 -> 어셈블리어 -> 고급언어 • 함수 기반 프로그래밍 – 1970년대 - 1980년대 • 소프트웨어의 위기 – 생산성 향상의 한계 • 객체지향 개념의 등장 – 1980년대 ISLab ICE HUFS MFC Tutorial 4 객체지향이란? 메시지 객체 메쏘드 호출 이벤트 ISLab ICE HUFS MFC Tutorial 5 객체지향의 핵심 내용(1) • 객체란 – 데이타(자료구조; 상태변수)와 오퍼레이터(함수)가 하나로 묶여있는 형태 • 추상 데이타 타입(ADT;abstract data type) – 클래스를 이용하여 표현 • 계승(inheritance) – 동적 바인딩(dynamic binding) – cf) Static binding • 다형성(polymorphism) – Overloading : 동일한 함수의 이름 사용 가능 – Overriding : 상위 클래스에서 정의된 함수를 하위 클래스에서 재 정의 – Template : 타입을 인자로 하여 새로운 타입을 생성 ISLab ICE HUFS MFC Tutorial 6 MFC를 위한 C++의 기초 • • • • 클래스 계승 생성자 및 소멸자 Virtual Function을 이용한 동적 바인딩 ISLab ICE HUFS MFC Tutorial 7 클래스란? • 객체를 기술할 수 있는 수단을 제공 – 자료 구조 (member data) – 오퍼레이션 (member function) 모델링 실세계 컴퓨터세계 ISLab ICE HUFS MFC Tutorial 8 클래스의 계승(1) • 계승을 통한 코드의 재 사용 가능 – 생산성 향상 • 이름 충돌(name conflict) 발생 • 다중 계승의 문제점 – virtual base class로 계승 ISLab ICE HUFS MFC Tutorial 9 클래스의 계승(2) class B : virtual public A { ... }; A int x; class C : virtual public A { ... }; B int y; C int z; D int z; ISLab ICE HUFS MFC Tutorial 10 생성자(1) • 생성자(constructor) 호출 – 메모리 할당과 생성자는 별개 – 메모리 할당 • new : 힙(heap)에 객체 생성 • 지역변수 : 스택(stack)에 객체 생성 • 전역변수 : 프로그램 코드 영역에 객체 생성 – 생성자는 메모리 할당이 끝난 객체의 각 데이타 부분을 초기화하 는 역할 ISLab ICE HUFS MFC Tutorial 11 생성자(2) A::A(int n) : m_nNo(n) { } A int m_nNo B::B(int i) : A( i ) { ptr = new char[ i ]; } B char* ptr A* pA = new B(3); 3 500 500 힙/스택/코드 영역 힙 (heap) 영역 ISLab ICE HUFS MFC Tutorial 12 소멸자(1) • 소멸자(destructor)의 virtual 함수화 – 소멸자는 객체 자체의 메모리 영역을 없애는 것이 아님 – 그 객체가 new 등을 이용하여 실행중에 만든 객체를 메모리에서 없애는 역할을 한다. ISLab ICE HUFS MFC Tutorial 13 소멸자(2) A* ptr = new A; delete ptr; ptr = new B(3); delete ptr; <- 문제 발생. A의 소멸자만 불린다. 3 500 500 접근못하는 메모리 (garbage) 힙/스택/코드 영역 힙 (heap) 영역 ISLab ICE HUFS MFC Tutorial 14 Virtual Function(1) • 동적 바인딩(dynamic binding) – 프로그램의 수행 중에 실제 수행할 함수를 결정 – vitual function table(hidden pointer) • 정적 바인딩(static binding) ISLab ICE HUFS MFC Tutorial 15 Virtual Function(2) DrawObj int a DrawObj* p_obj; virtual Draw() p_obj = new Point; p_obj->Draw(); Point p_obj = new Line; p_obj->Draw(); p_obj = new PolyLine; p_obj->Draw(); Line int x, y Point start, end virtual Draw() virtual Draw() virtual Calc() PolyLine Point[5] pt virtual Draw() ISLab ICE HUFS MFC Tutorial 16 Virtual Function - 메모리 구조 p_obj = new DrawObj; p_obj->Draw(); p_obj = new PolyLine; p_obj->Draw(); vtbl 50 vtbl 180 int a int a Point start 50 100 350 430 180 550 430 250 DrawObj::Draw 350 Line::Draw Point end p_obj = new Line; p_obj->Draw(); Point[0] pt Point[1] pt vtbl 100 int a Point start Point end pointer of virtual function table Point[2] pt Point[3] pt 250 virtual function table 430 Point[4] pt Line::Calc 550 PolyLine::Draw MFC Tutorial Code 영역 ISLab ICE HUFS 17 Virtual Function 사용 예 CObList list; DrawObj* p_obj; p_obj = new Line; list.AddTail(p_obj); p_obj = new Point; list.AddTail(p_obj); . . . . POSITION pos = list.GetHeadPosition(); while(pos != NULL) { p_obj = (DrawObj*)list.GetNext(pos); p_obj->Draw(); } List Line Point Line PolyLine Point ISLab ICE HUFS MFC Tutorial 18 ISLab ICE HUFS MFC 기초 목차 • • • • • SDK와 MFC의 비교 MFC 클래스 종류 AppWizard를 이용한 프로젝트 생성 Develop Studio 사용법 Hungarian 표기법 ISLab ICE HUFS MFC Tutorial 20 Windows API • Applicatoin Programming Interface • Windows System Calls • Windows 3.1 – Win16 API • Windows 95/NT – Win32 API • C 라이브러리 ISLab ICE HUFS MFC Tutorial 21 SDK 프로그래밍 • SDK(Software Development Kit) – 윈도우 프로그래밍을 위한 여러 가지 툴과 라이브러리로 구성되 어 있는 마이크로소프트에 의해 발표된 소프트웨어 패키지 – 윈도우 프로그래밍시 호출하여 사용할 수 있는 함수들이 포함 (윈도우 API) – C 라이브러리 ISLab ICE HUFS MFC Tutorial 22 메시지와 메시지 큐 • 메시지(message)? – 윈도우에서 발생하는 사건들의 표현 – 숫자 (winuser.h) • 메시지 큐(queue) – 하나의 프로그램에 하나씩 할당 윈도우에 사건이 발생하면 운영체제는 이를 메시지로 만들어 발생 순서대로 메시지 큐에 넣는다. ISLab ICE HUFS MFC Tutorial 23 메시지 루프, 윈도우 프로시저 • 메시지 루프 – 메시지 큐에서 메시지를 하나씩 꺼내어 거기에 맞게 처리 • 윈도우 프로시저 – 메시지의 실제 처리 운영체제 응용 프로그랭 메시지를 하나씩 읽어다가 이를 처리할 윈도우의 윈도우 프로시저를 호출한다. ISLab ICE HUFS MFC Tutorial 24 메시지에 의한 동작 • Message-driven operations 윈도우에 사건이 발생하면 운영체제는 이를 메시지로 만들어 발생 순서대로 메시지 큐에 넣는다. msg 메시지 큐 int WinMain(HINSTANCE ......) { . . . InitApplication(hInstance); InitInstance(hInstance); . . . . . . while(GetMessage(....)) { . . . DispatchMessage(. . .); } . . . } 함수 ISLab ICE HUFS MFC Tutorial 25 SDK 프로그램의 예 #include “windows.h” #include “generic.h” // SDK의 API와 각종 상수, 구조체가 정의된 헤더 화일 // 이 프로그램 내에서 사용할 상수가 정의되고 함수가 // 선언된 헤더 화일 HINSTANCE hInst; HWND hMainWnd; // 인스턴스 핸들을 기억해둔다. // 메인 윈도우 핸들을 기억해 둔다. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; if (!hPrevInstance) if (!InitApplication(hInstance)) return FALSE; // 윈도우 클래스를 등록한다. hInst = hInstance; // 인스턴스 핸들을 전역 변수에 기억해둔다. if (!InitInstance(hInstance, nCmdShow)) // 메인 윈도우를 생성한다. return FALSE; ISLab ICE HUFS MFC Tutorial 26 // 메시지 루프에 진입한다. while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); } ISLab ICE HUFS MFC Tutorial 27 InitApplication BOOL InitApplication(HINSTANCE hInstance) { WNDCLASS wc; // WNDCLASS는 윈도우 클래스의 등록에 필요한 구조체이다. wc.style = NULL; wc.lpfnWndProc=MainWndProc; // 윈도우의 윈도우 프로시저 이름을 지정한다 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; // 윈도우가 속한 인스턴스의 핸들을 지정한다. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);// 이 윈도우의 아이콘 지정 wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 이 윈도우의 커서 지정 wc.hbrBackground = GetStockObject(WHITE_BRUSH); // 배경색 지정 wc.lpszMenuName = “EX_Menu”; // 이 윈도우의 메뉴를 지정한다 wc.lpszClassName = “EX_WClass”; // 이 윈도우의 클래스 이름을 지정한다. return RegisterClass(&wc); // 이 윈도우 클래스를 등록한다. } ISLab ICE HUFS MFC Tutorial 28 InitInstance BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hMainWnd = hWnd = CreateWindow( “EX_WClass”, // 생성하려는 윈도우의 윈도우 클래스 이름 “EX Program”, // 윈도우의 타이틀을 지정한다. WS_OVERLAPPEDWINDOW, // 윈도우의 스타일을 지정한다. CW_USEDEFAULT, // 윈도우의 시작 X 좌표 CW_USEDEFAULT, // 윈도우의 시작 Y 좌표 CW_USEDEFAULT, // 윈도우의 폭 CW_USEDEFAULT, // 윈도우의 높이 NULL, // 부모 윈도우의 핸들 NULL, hInstance, // 이 윈도우가 속한 인스턴스의 핸들 NULL ); if (!hWnd) return FALSE; // 윈도우가 실패했으면 ShowWindow(hWnd, nCmdShow); // 메인 윈도우의 형태를 결정하고 WM_PAINT 발생 UpdateWindow(hWnd); // WM_PAINT 메시지를 바로 처리해버린다. return TRUE; } ISLab ICE HUFS MFC Tutorial 29 윈도우 스타일(1) WS_OVERLAPPED WS_SYSMENU WS_CAPTION WS_THICKFRAME WS_MINIMIZEBOX WS_MAXIMIZEBOX WS_CHILD WS_VISIBLE WS_BORDER WS_MAXIMIZE WS_MINIMIZE WS_HSCROLL WS_VSCROLL 겹쳐질 수 있는 윈도우를 생성한다. 윈도우에 시스템 메뉴를 붙인다. 윈도우에 타이틀바를 사용한다. 윈도우의 테두리선을 굵은선으로 한다. 축소 버튼을 윈도우 타이틀바 오른쪽에 붙인다. 확대 버튼을 윈도우 타이틀바 오른쪽에 붙인다. 다른 윈도우의 자식 윈도우로 생성한다. 윈도우의 생성과 동시에 윈도우를 보이게 한다. 윈도우에 테두리를 긋는다. 윈도우를 전체 화면 크기로 생성한다. 윈도우를 아이콘 모양으로 생성한다. 윈도우에 수평 스크롤바를 붙여 생성한다. 윈도우에 수직 스크롤바를 붙여 생성한다. ISLab ICE HUFS MFC Tutorial 30 윈도우 스타일(2) WS_POPUP WS_CLIPSIBLINGS WS_CLIPCHILDREN 팝업 윈도우를 생성한다. 이것은 WS_CHILD와 함께 사용될 수 없다. 같은 레벨의 자식 윈도우간에 겹치는 영역이 있을 때 각각의 자식 윈도우가 다른 겹치는 자식 윈도우 의 영역으로 넘어가지 못하도록 한다. 이 스타일을 주지 않았을 경우 자식 윈도우끼리 겹칠 때 이상하 게 그려지는 상황이 발생할 수 있다. 자식 윈도우가 차지하는 영역은 부모 윈도우의 영 역에서 제외된다. 부모 윈도우를 생성할 경우 주어 야 한다. #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION \ | WS_SYSMENU | WS_THICKFRAME \ | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) ISLab ICE HUFS MFC Tutorial 31 윈도우 프로시저 MainWndProc long APIENTRY MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_COMMAND: // 사용자가 메뉴 항목을 선택하면 발생하는 메시지 { case ID_FILE_EXIT: SendMessage(hWnd, WM_CLOSE, 0, 0); break; } case WM_PAINT: // 윈도우의 사용자 영역이 복구되어야 할 때 발생하는 메시지 { HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd, &ps); TextOut(hDC, 10, 10, “Hello, everybody”, 16); EndPaint(hWnd, &ps); break; } ISLab ICE HUFS MFC Tutorial 32 case WM_DESTROY: // 윈도우가 없어지기 직전에 발생하는 메시지 { PostQuitMessage(0); break; } default: // 처리하지 못한 메시지를 넘긴다. return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } ISLab ICE HUFS MFC Tutorial 33 generic.h & resource.h • generic.h #include “resource.h” int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int); BOOL InitApplication(HANDLE); BOOL InitInstance(HANDLE, int); long APIENTRY MainWndProc(HWND, UINT, WPARAM, LPARAM); • resource.h #define ID_FILE_EXIT 100 ISLab ICE HUFS MFC Tutorial 34 generic.rc #include "resource.h" // Menu #define APSTUDIO_READONLY_SYMBOLS #include "afxres.h" EX_Menu MENU DISCARDABLE BEGIN POPUP "File" BEGIN MENUITEM "Exit", ID_FILE_EXIT END END #undef APSTUDIO_READONLY_SYMBOLS // Korean resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_KOR) #ifdef _WIN32 #ifdef APSTUDIO_INVOKED LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT #pragma code_page(949) #endif //_WIN32 #endif // Korean resources #ifndef APSTUDIO_INVOKED // Generated from the TEXTINCLUDE 3 resource. #endif // not APSTUDIO_INVOKED ISLab ICE HUFS MFC Tutorial 35 핸들(Handle) • 무엇인가를 구별하기 위해 붙인 번호 – 예) 윈도우 핸들 (HWND) • 윈도우가 여러 개 존재할 경우 이를 구별하기 위해 윈도우마다 번호를 하나 씩 부여 • 핸들 타입 앞에는 H가 붙는다. • UINT로부터 재정의 – #define UINT HANDLE – #define HANDLE HWND ISLab ICE HUFS MFC Tutorial 36 타입 BOOL 참, 거짓을 나타내는 타입으로 int로부터 재정의 되었으며 TRUE, FALSE 값을 갖는다. LPSTR char 타입에 대한 포인터, 즉 char * 와 같다. Long Pointer to STRing을 나타낸다. LPCTSTR는 const char * 와 같다. HWND 윈도우들을 구별하기 위해 윈도우에 붙여지는 핸들 타입 HINSTANCE 인스턴스의 구별을 위해 인스턴스마다 부여되는 핸들 타입 UINT unsigned int에 해당. Win32에서는 4 바이트 HANDLE 모든 핸들 타입의 원조에 해당하는 타입. UINT로 부터 typedef 문을 이용해 재정의. H로 시작되는 모든 핸들 타입은 모두 이것으로부터 typedef 문으로 재정의 됨. WPARAM UINT로부터 재정의. 메시지에 수반되는 부가 정보를 나타냄. LPARAM LONG으로부터 재정의. 메시지에 수반되는 부가 정보 표시 ISLab ICE HUFS MFC Tutorial 37 주요 메시지(1) WM_CREATE 윈도우가 생성될 때 발생한다. 정확히 말하면 CreateWindow API가 호출되었을 때 발생한다. 이 메시지 처리부에서 초기화 작업을 수행하는 것이 일반적이다. 아직 윈도우가 보이지 않는다. WM_SIZE 윈도우의 크기가 변화하면 발생. 이 메시지가 발생하면 그 뒤에 WM_PAINT가 따라서 발생한다. WM_PAINT 윈도우의 사용자 영역이 가려졌다가 앞으로 나온다든가 해서 다시 그려질 일이 생기면 발생하는 메시지이다. InvalidateRect와 같은 API로 발생시키는 것도 가능하다. WM_COMMAND 사용자가 메뉴에서 명령을 선택하면 발생 WM_CLOSE 사용자가 윈도우의 시스템 메뉴에서 닫기(Close)를 택하면 발생. DefWindowProc 함수는 WM_CLOSE 메시지를 받으면 WM_DESTROY 메시지를 발생 ISLab ICE HUFS MFC Tutorial 38 주요 메시지(2) WM_DESTROY 윈도우가 없어지기 직전에 발생한다. 여기서는 앞 서 윈도우 프로시저의 실행중에 할당한 자원들이 있다면 이를 운영체제에 반환하는 역할을 수행함. 메인 윈도우의 WM_DESTROY 메시지 처리부에서 는 끝부분에서 PostQuitMessage 함수를 호출하는 것이 일반적이다. WM_QUIT PostQuitMessage 함수를 호출하면 이 메시지가 만 들어져 메시지 큐에 들어가게 된다. 메시지 루프에 서 이 메시지를 읽어가면 GetMessage 함수의 리턴 값이 FALSE가 되기 때문에 메시지 루프가 끝나게 되고 프로그램이 종료된다. ISLab ICE HUFS MFC Tutorial 39 MFC란 • 클래스 라이브러리 – 클래스의 집합 (함수의 집합이 아님) • 애플리케이션 프레임워크(application framework) – AppWizard – ClassWizard – Project Workspace ISLab ICE HUFS MFC Tutorial 40 MFC 구조 • MFC는 SDK API의 기능을 구분 하여 클래스 계층구조를 입힌 것 • 응용 프로그램은 SDK API를 직 접 부를 수 있음 • “Handle”은 분류의 기준이 됨 응용프로그램 MFC SDK API 운영체제 ISLab ICE HUFS MFC Tutorial 41 왜 MFC 인가? • 이해가 쉬움 – 연관된 함수와 데이타를 “클래스”를 이용하여 그룹화하였음 • 코드의 재사용성 향상 • 소프트웨어 개발의 용이성 – 애플리케이션 프레임워크(application framework) 제공 – 멤버 함수 나열 – 코드 삽입의 용이성 ISLab ICE HUFS MFC Tutorial 42 Handle을 이용한 분류 - SDK(1) RECT rc; GetClientRect(hWnd, &rc); MoveWinodw(hWnd, x, y, x2, y2, TRUE); ISLab ICE HUFS MFC Tutorial 43 Handle을 이용한 분류 - MFC(1) class CWnd : public CCmdTarget { HWND m_hWnd; ... BOOL GetClientRect(LPRECT lpRect); BOOL MoveWindow(int x,int y,int width,int height,BOOL bDraw=TRUE); ... } BOOL CWnd::GetClientRect(LPRECT lpRect) --> inline 함수를 이용하여 성능 저하를 막는다 { ::GetClientRect(m_hWnd, lpRect); } BOOL CWnd::MoveWindow(int x, int y, int width, int height, BOOL bDraw) { ::MoveWindow(m_hWnd, x, y, width, height); } ISLab ICE HUFS MFC Tutorial 44 Handle을 이용한 분류 - SDK(2) HDC hDC = GetDC(hWnd); Rectangle(hDC, 10, 10, 100, 100); TextOut(hDC, 10, 10, “Sample”, 6); ReleaseDC(hWnd, hDC); ISLab ICE HUFS MFC Tutorial 45 Handle을 이용한 분류 - MFC(2) class CDC : public CObject { HDC m_hDC; . . . . BOOL Rectangle(int x1, int y1, int x2, int y2); BOOL TextOut(int x, int y, LPSTR lpStr, int size); } BOOL CDC::Rectangle(int x1, int y1, int x2, int y2) { ::Rectangle(m_hDC, x1, y1, x2, y2); } BOOL CDC:: TextOut(int x, int y, LPSTR lpStr, int size) { ::TextOut(m_hDC, x, y, lpStr, size); } ISLab ICE HUFS MFC Tutorial 46 SDK - 자원 획득 및 반환 • SDK { HDC hDC; hDC = GetDC(hWnd); // 자원 획득 Rectangle(hDC,10,10,100,100); TextOut(hDC,10,10,“Sample”,6); ReleaseDC(hWnd, hDC); // 반드시 자원을 반환해야 한다. } ISLab ICE HUFS MFC Tutorial 47 C++의 장점(생성자/소멸자) - MFC { CClientDC dc(this); dc.Rectangle(10, 10, 100, 100); dc.TextOut(10,10,“Sample”,6); } // 소멸자 불림 CClientDC::CClientDC(CWnd* pWnd) { m_hWnd = pWnd->GetSafeHwnd(); m_hDC = ::GetDC(m_hWnd); } // 윈도우 핸들을 얻는다. // 윈도우의 Device Context를 얻음 CClientDC::~CClientDC() { ::ReleaseDC(m_hWnd, m_hDC); // Device Context를 해제한다. } ISLab ICE HUFS MFC Tutorial 48 C++의 장점 - 부재인자 • SDK int MessageBox(HWND hWnd, LPCSTR lpszText, LPCSTR lpszTitle, UNIT flag); InvalidateRect(HWND hWnd, LPCRECT lpRect, BOOL bErase); • MFC int AfxMessageBox(LPCSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0); void InvalidateRect(LPCRECT lpRect, BOOL bErase = TRUE); ISLab ICE HUFS MFC Tutorial 49 C++의 장점 - 중복 정의 • 함수 중복 정의(function overloading) BOOL Rectangle(int x1, int y1, int x2, int y2); BOOL Rectangle(LPCRECT lpRect); • 연산자 중복 정의(operator overloading) CRect a, b, c; c.left = a.left + b.left; c.right = a.right + b.right; c.top = a.top + b.top; c.bottom = a.bottom + b.bottom; c = a + b; ISLab ICE HUFS MFC Tutorial 50 MFC 클래스 종류 • • • • • 일반 목적의 클래스 윈도우 API 클래스 애플리케이션 프레임워크 클래스 고 수준 추상화 클래스 운영체제 확장 클래스 ISLab ICE HUFS MFC Tutorial 51 일반 목적의 클래스 • • CObject : 모든 클래스의 상위 클래스 예외 처리 클래스 – • 콜렉션(collection) 클래스 – – – • CFile, CStdioFile, CMemFile 시간 및 시간 간격(time span) 클래스 – • Cstring 파일 클래스 – • CByteArray, CWordArray, CDWordArray, CPtrArray, CObArray, CStringArray, CUintArray CObList, CPtrList, CStringList CMapPtrToWord, CMapPtrToPtr, CMapStringToOb, CMapStringToPtr, CMapStringToString, CMapWordToOb, CMapWordToPtr 동적 문자열 클래스 – • CException, CArchiveException, CFileException, CMemoryException, CNotSupportedException, COleException, CDBException, CResourceException, CUserException CTime, CTimeSpan 그외 – CPoint, CSize, CRect등 ISLab ICE HUFS MFC Tutorial 52 윈도우 API 클래스 (1) • 응용 프로그램에서 사용하는 클래스 – CCmdTarget, CCmdUI, CWinThread, CWinApp • 객체 동기화 관련 클래스 – CSyncObject, CCriticalSection, CSemaphore, CMutex, CEvent, CSingleLock, CMultiLock • 응용 프로그램 관련 클래스 – CCommandLineInfo, CWaitCursor • 메뉴 : Cmenu • CWnd : 모든 윈도우 클래스의 상위 클래스 – 프레임 윈도우(frame window) • CFrameWindow, CMDIFrameWindow, CMDIChildWnd – CWnd 계승 클래스 • CDialog, 콘트롤 클래스(CButton, CListBox, CEdit 등) ISLab ICE HUFS MFC Tutorial 53 윈도우 API 클래스 (2) • 다이얼로그 – • 다이얼로그 DDX/DDV – • CDataExchange 콘트롤 클래스 – – • CFileDialog, CColorDialog, CFontDialog, CPrintDialog, CFindReplaceDialog CButton, CBitmapButton, CComboBox, CEdit, CStatic, CScrollBar, CListBox, CCheckListBox, CVBControl CAnimateCtrl, CDragListBox, CHeaderCtrl, CHotKeyCtrl, CImageList, CListCtrl, CProgressCtrl, CRichEditCtrl, CSliderCtrl, CSpinButtonCtrl, CStatusBarCtrl, CTabCtrl, CToolBarCtrl, CToolTipCtrl, CTreeCtrl GDI 및 그림 관련 클래스 – – CPaintDC, CWindowDC, CClientDC, CMetaFileDC CGdiObject, CFont, CPen, CBrush, CBitmap, CPalette, CRgn ISLab ICE HUFS MFC Tutorial 54 애플리케이션 프레임워크 클래스 • 문서/뷰 관련 클래스 – CDocTemplate, CSingleDocTemplate, CMultiDocTemplate – CDocument, Cview • 문맥 지원 도움말(context-sensitive help) ISLab ICE HUFS MFC Tutorial 55 고 수준 추상화 클래스 • 확장된 뷰(enhanced view) – CScrollView, CFormView – 콘트롤 뷰 : CEditView, CListView, CRichEditView, CTreeView • 분리 윈도우 – CSplitterWnd • 콘트롤 바 – CControlBar – CToolBar, CStatusBar, CDialogBar ISLab ICE HUFS MFC Tutorial 56 운영체제 확장 클래스 (1) • OLE 지원 – OLE Document • CDocItem, COleServerItem, COleClientItem, COleDocument, COleLinkingDoc, COleServerDoc, COleIPFrameWnd – 클래스 팩토리(class factories) • COleObjectFactory, COleTemplateServer – 오토메이션(automation) – 통일된 데이타 전송 • COleDataSource, COleDataObject, COleDropSource, COleDropTarget – OLE 콘트롤 • COleControl, COlePropertyPage, COleControlModule, COleObjectFactoryEx, COleConnectionPoint, CPropExchange, CFontHolder, CPictureHolder ISLab ICE HUFS MFC Tutorial 57 운영체제 지원 클래스(2) • ODBC 지원 – CDatabase, CRecordset, CFiledExchange, CLongBinary, CRecordView • DAO 지원 – CDaoWorkspace, CDaoDatabase, CDaoRecordset, CDaoRecordView, CDaoQueryDef, CDaoTableDef, CDaoException, CDaoFiledExchange • MAPI 지원 • Winsock 지원 – CAsyncSocket, Csocket • 펜 윈도우 지원 – CHEdit, CBEdit – 제한 : 16 비트 환경 ISLab ICE HUFS MFC Tutorial 58 코드 재 사용 방법 Component Gallery AppWizard Custom AppWizard MFC 확장 응용 프로그램 MFC ISLab ICE HUFS MFC Tutorial 59 AppWizard를 통한 Project 생성(1) • Project 생성 (project 이름: Obedit) – New 메뉴 (MFC AppWizard (.exe) • Database, OLE 메뉴 – None • Multiple document 선택 ISLab ICE HUFS MFC Tutorial 60 AppWizard를 통한 Project 생성(2) • Advanced Options – File extension : obe – Main frame caption: Obedit – Doc type name: Obedit File type ID: Obedit.Document – File new name: Obedit File type name: Obedit Document Filter name: Obedit Files(*.obe) • MFC library 사용 방법 – As a shared DLL (MFC42.DLL 필요) • Base class 선택 – CObeditView 클래스의 상위 클래스로 CScrollView 선택 ISLab ICE HUFS MFC Tutorial 61 Developer Studio • Project Workspace – – – – 클래스 뷰(class view) 리소스 뷰(resource view, AppStudio 대신) 파일 뷰(file view) 인포 뷰(info view) • 작업 영역 – source code browser / wizard bar / resource editor – online help ISLab ICE HUFS MFC Tutorial 62 클래스 뷰/파일 뷰/리소스 뷰 ISLab ICE HUFS MFC Tutorial 63 클래스 뷰(class view) • 클래스에 함수 및 멤버 추가 – 클래스 이름에 마우스 커서를 위치 시킨 후 오른쪽 버튼을 클릭 – 멤버 함수 추가 – 멤버 변수 추가 • 특정 위치로 커서 이동 • 계승 관계 표시 ISLab ICE HUFS MFC Tutorial 64 파일 뷰(file view) • 프로젝트에 있는 화일들을 열거 • 프로젝트에서 화일 삭제 • (.net) 솔루션 탐색기 ISLab ICE HUFS MFC Tutorial 65 Hungarian 표기법 Type char BOOL int UINT WORD LONG DWORD * (pointer) FAR * LPSTR handle callback Prefix c b n n w l dw p lp lpsz h lpfn 예 cDirSeperator bIsSending nVariableCount nMyUnsignedInt wListID lAxisRatio dwPackedmessage pWnd lpWnd lpszFileName hWnd lpfnHookProc 비고 z는 NULL로 끝남을 의미 함수 포인터 ISLab ICE HUFS MFC Tutorial 66 Hungarian 표기법 - MFC 확장 Type CRect CPoint CSize CString CWnd CWnd * Prefix rect pt sz str Wnd pWnd 예 rectScroll ptMouseClick szRectangle strFind WndControl pWndDialog ISLab ICE HUFS MFC Tutorial 67 Hungarian 표기법 - Symbol Type 여러 리소스에서 공유 Dialog 리소스 Dialog 리소스 Help context ID (for context-sensitive help) 비트맵 리소스 커서 리소스 아이콘 리소스 menu, toolbar command Command help context Message box prompt Message box help context String 리소스 다이얼로그 템플릿의 control Prefix IDR_ IDD_ HIDD_ 예 IDR_MAINFRAME IDD_ABOUT HIDD_HELP_ABOUT 범위 1-0x6FFF 1-0x6FFF 0x2001- 0x26FF IDB_ IDC_ IDB_SMILEY IDC_HAND 1-0x6FFF 1-0x6FFF ID_ HID_ IDP_ HIDP_ IDS_ IDC_ ID_CIRCLE_TOOL 0x8000-0xDFFF HID_CIRCLE_TOOL 0x1800-0x1DFF IDP_FATALERROR8-0xDFFF HIDP_FATALERROR 0x3008-0x3DFF IDS_ERROR12 1-0x7FFF IDC_COMBO1 8-0xDFFF ISLab ICE HUFS MFC Tutorial 68 ISLab ICE HUFS MFC의 기본 구조 이해 MFC의 철학(1) • 예제 프로그램 컴파일 후 수행 – Open 메뉴 선택 • 화일 선택시 일반적인 절차에 대한 코딩 1 화일 오픈 다이얼로그 박스를 띄운다. 2 사용자의 입력을 받아 해당 화일을 연다. 만일 MDI 프로그램이면 자식 윈도우를 하나 연다. SDI 프로그램이라면 전에 갖고 있던 자료 구조를 해제한다. 3 화일을 프로그램의 정의에 맞게 해석하여 읽어들인다. 즉 화일의 내용을 메모리 상의 자료구조로 변환한다. 4 읽어들인 내용을 윈도에 그린다. 이 부분의 구현은 대개 윈도를 무효화 (invalidate)하여 이루어진다. ISLab ICE HUFS MFC Tutorial 70 MFC의 철학(2) • 실제 사용자가 해야 할 일 (3번) – 장점 • 에러의 가능성 감소 • 프로그래밍 시간 및 노력 감소 ISLab ICE HUFS MFC Tutorial 71 CDocument class CDocument : public CCmdTarget { ... void OnFileOpen(); // 파일오픈 명령을 실행하면 불려진다. BOOL GetOpenFileName(LPCTSTR); // 다이얼로그를 띄워 파일이름을 입력 // 화일 입출력을 담당하는 함수 (pure virtual function) virtual void Serialize(CFile cfile) = 0; CWnd* GetWindow(); // 현재 문서의 내용을 보여주는 윈도우 포인터를 리턴 ... } ISLab ICE HUFS MFC Tutorial 72 CDocument::OnFileOpen void CDocument::OnFileOpen() { CString szFileName; // CString은 문자배열에 해당하는 클래스 if (!GetOpenFileName(szFileName)) return; CFile cfile(szFileName); // cfile.Open(); // Serialize(cfile); // 화일의 cfile.Close(); // 화일을 CWnd* pWnd = GetWindow(); pWnd->Invalidate(NULL); // 다이얼로그 박스를 띄워 파일이름을 // 입력받는다. CFile은 MFC에서 화일 I/O를 담당 화일을 오픈한다. 내용을 읽어들인다(user가 작성) 닫는다. // 이 문서의 내용을 보여주는 윈도의 핸들을 // 얻어 그 내용을 그리도록 WN_PAINT 메시지 // 발생 } ISLab ICE HUFS MFC Tutorial 73 CMyDocument 클래스 // CDocument는 실제 바로 사용하지 못함(MFC class) // 계승하여 사용하여야 class CMyDocument : public CDocument { // My data structure int m_nNumOfObjects; Objects obj[100]; public: void Serialize(CFile cfile); // virtual function }; ISLab ICE HUFS MFC Tutorial 74 WinMain int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (!hPrevInstance) // 처음으로 실행되는 경우에는 InitApplication(hInstance); // 윈도우 클래스를 등록한다. InitInstance(hInstance); // 메인 윈도우를 생성한다. while(GetMessage(....)) // 메시지 루프 { .... DispatchMessage(...); // 메시지를 윈도우 프로시저로 나눔 } // 프로그램이 종료되기 전에 청소 작업을 행한다. .... return msg.wParam; } ISLab ICE HUFS MFC Tutorial 75 MFC의 WinMain • MFC\SRC\winmain.cpp • CWinApp 클래스에 존재 CWinApp::InitApplication CWinApp::InitInstance CWinApp::Run CWinApp::ExitInstance • • InitInstance, ExitInstance 만 override 하여 사용 가능 가상 함수의 중요성 ISLab ICE HUFS MFC Tutorial 76 SDI • • • • CObeditApp -> CWinApp CMainFrame -> CMDIFrameWnd CObeditDoc -> CDocument CObeditView -> CView ISLab ICE HUFS MFC Tutorial 77 MDI CObeditApp -> CWinApp CMainFrame -> CMDIFrameWnd CChildFrame -> CMDIChildWnd CObeditDoc -> CDocument CObeditView -> CView ISLab ICE HUFS MFC Tutorial 78 Document/View 구조 문서클래스 2. 그 내용을 반영한다. 뷰클래스 1. 사용자의 입력을 받는다 3. 윈도우로 출력한다. ISLab ICE HUFS MFC Tutorial 79 전체 구조 • CWinApp – 하나의 응용 프로그램을 가리키는 클래스 • CDocument – 응용 프로그램의 자료구조를 저장하는 클래스 • CView – 응용 프로그램의 모습을 화면에 출력하는 클래스 • 하나의 document에는 여러 개의 view가 연관될 수 있음 – 예) 탐색기, Visual C++ 에디터 창 ISLab ICE HUFS MFC Tutorial 80 CObeditApp 클래스 class CObeditApp : public CWinApp { public: CObeditApp(); //{{AFX_VIRTUAL(CObeditApp) public: virtual BOOL InitInstance(); //}}AFX_VIRTUAL // 프로그램의 초기화 //{{AFX_MSG(CObeditApp) afx_msg void OnAppAbout(); ... //}}AFX_MSG ISLab ICE HUFS MFC Tutorial 81 InitInstance 함수 BOOL CObeditApp:InitInstance() { .... LoadStdProfileSettings(); // 표준 INI 화일 option을 읽어들임 CMultiDocTemplate* pDocTemplate; pDocTemplate = new CMultiDocTemplate( IDR_OBEDITTYPE, RUNTIME_CLASS(CObeditDoc), RUNTIME_CLASS(CChildFrame), RUNTIME_CLASS(CObeditView)); AddDocTemplate(pDocTemplate); // View-Doc 등록 CMainFrame* pMainFrame = new CMainFrame; // main window 생성 if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; ISLab ICE HUFS MFC Tutorial 82 ... RegisterShellFileTypes(TRUE); // 화일의 icon, 확장자 등록 CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if (!ProcessShellCommand(cmdInfo)) return FALSE; pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); return TRUE; } ISLab ICE HUFS MFC Tutorial 83 Obedit.ini 화일 [Recent File List] File1=D:\obedit\step8\new.OBE File2=D:\obedit\step7\test4.OBE ISLab ICE HUFS MFC Tutorial 84 레지스트리 작업 • • INI 파일 기록 및 읽기 – UINT GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault); – CString GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = NULL); – BOOL WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue); – BOOL WriteProfileString( LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue ); 레지스트리에 읽기 및 쓰기 – void SetRegistryKey( LPCTSTR lpszRegistryKey ); – void SetRegistryKey( UINT nIDRegistryKey ); ISLab ICE HUFS MFC Tutorial 85 레지스트리 void CObeditApp::LoadStdProfileSettings() { // 나름대로 초기화 값을 읽어다 저장한다. // GetProfileInt... // CWinApp::LoadStdProfileSettings(); // 선조 함수 호출 } ISLab ICE HUFS MFC Tutorial 86 윈도우 생성 • WM_CREATE – OnCreate 함수 호출 ISLab ICE HUFS MFC Tutorial 87 CMainFrame 클래스 class CMainFrame : public CMDIFrameWnd { DECLARE_DYNAMIC(CMainFrame) .... protected: CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; protected: //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //}}AFX_MSG DECLARE_MESSAGE_MAP() // 메시지 맵 }; ISLab ICE HUFS MFC Tutorial 88 OnCreate 함수 ISLab ICE HUFS MFC Tutorial 89 MFC MDI 프로그램의 윈도우 구조 MDI 메인 윈도우 타이틀 파일 편집 타이틀 MDI 클라이언트 윈도우 MDI 자식 윈도우 뷰 윈도우 ISLab ICE HUFS MFC Tutorial 90 CObeditView 클래스 class CObeditView : public CView { .... public: CObeditDoc* GetDocument(); // 뷰에 연결된 문서객 체의 포인터 반환 .... //{{AFX_VIRTUAL(CObeditView) public: virtual void OnDraw(CDC* pDC); // WM_PAINT가 왔 을 때 실행 virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); //}}AFX_VIRTUAL .... ISLab ICE HUFS MFC Tutorial 91 주요 CView 멤버함수 GetDocument 뷰와 연계된 문서 오브젝트에 대한 포인터를 돌려준다. AddDocTemplate 함수를 통해 m_pDocument 멤버는 MFC가 뷰를 생성할 때 알아서 초기화 OnInitialUpdate 뷰가 처음 만들어질 때 호출된다. OnDraw 뷰와 연계된 문서오브젝트의 내용을 윈도우 위에 그려준다. OnPrint 뷰와 연계된 문서오브젝트의 내용을 프린터로 출력 OnUpdate 문서오브젝트의 내용이 변경되었을 때 문서오브젝트 쪽에 불러준다. ISLab ICE HUFS MFC Tutorial 92 CObeditDoc 클래스 class CObeditDoc : public CDocument { .... //{{AFX_VIRTAUL(CObeditDoc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); // file I/O //}}AFX_VIRTUAL .... }; ISLab ICE HUFS MFC Tutorial 93 주요 CDocument 멤버 함수 IsModified 문서오브젝트의 내용이 마지막으로 저장된 후에 변경된 적이 있는지 알려준다. SetModifiedFlag 문서오브젝트의 내용이 변경되었음을 표시했다. UpdateAllViews 문서오브젝트의 내용이 바뀌었을 때 이 내용을 연계된 뷰에게 알려준다. 이 안에서는 뷰클래스의 OnUpdate 함수를 부른다. DeleteContent 문서오브텍트가 닫힐 때 불려진다. 이 때 문서오브젝트 의 청소 작업을 해야 한다. OnNewDocument 사용자가 File 메뉴의 New 명령을 수행하면 불린다. OnOpenDocument 사용자가 File 메뉴의 Open 명령을 수행하면 불린다. OnSaveDocument 사용자가 File 메뉴의 Save 명령을 수행하면 불린다. OnCloseDocument 사용자가 File 메뉴의 Close 명령을 수행하면 불린다. ISLab ICE HUFS MFC Tutorial 94 모든 뷰 수정 • Document class는 자신과 연관이 있는 view object를 리스트의 형태 로 관리 – CPtrList m_viewList • View에서 수정 • Document 수정 • UpdateAllViews 호출 ISLab ICE HUFS MFC Tutorial 95 UpdateAllViews View Document 자료구조에 변화가 생긴다. GetDocument 함수로 관련 이 변화를 관련된 모든 뷰에 문서 오브젝트를 알아낸다. 반영하기위해 UpdateAllViews 그 다음 데이터를 갱신한다. 함수를 호출한다. 각 뷰별로 화면을 다시 그린 UpdateAllViews 함수에서는 다. OnUpdate 함수를 호출한다. ISLab ICE HUFS MFC Tutorial 96 ISLab ICE HUFS UI 붙이기 메뉴 작성 File Object View New Line Toolbar Open Ellipse Status Bar Close Rectangle Color Bar Save -----------------Save As… Pen Attribute Zoom ---------Print Print Preview Print Setup… ---------Send Summary Info ---------Recent File ---------Exit Window Help New Window About Cascade Time Title Arrange Icons ISLab ICE HUFS MFC Tutorial 98 메뉴 리소스 작성 • 리소스 뷰에서 – IDR_MAINFRAME(child window가 없을 때) – IDR_OBEDITTYPE ISLab ICE HUFS MFC Tutorial 99 메뉴 작성 &Line &Ellipse &Rectangle ID_OBJECT_LINE ID_OBJECT_ELLIPSE ID_OBJECT_RECTANGLE &Pen Attribute ID_OBJECT_PENATTR &Color Bar &Zoom\tCtrl+Z 풍선 도움말 Draw a line\nLine Draw a ellipse\nEllipse Draw a rectangle\nRectangle Change the attribute of a pen\nPen ID_VIEW_COLORBAR Show or hide color palette ID_VIEW_ZOOM Set zoom ratio ID_SEPARATOR(분리자 메뉴) MEMU ID 단축키 ISLab ICE HUFS MFC Tutorial 100 단축키 작성 • 리소스 뷰의 Accelerator 이용 ISLab ICE HUFS MFC Tutorial 101 아이콘 변경 ISLab ICE HUFS MFC Tutorial 102 툴바의 수정 • 리소스 뷰에서 – IDR_MAINFRAME ISLab ICE HUFS MFC Tutorial 103 배율 설정 • 새로운 ToolBar 생성 ISLab ICE HUFS MFC Tutorial 104 MyToolBar.h 수정 Class CMyToolBar : public CToolBarCtrl -> CToolBar로 수정 (.net에서는 바로 선택) { // Construction public: CMyToolBar(); // Attributes . . . . ISLab ICE HUFS MFC Tutorial 105 MyToolBar.cpp 수정 BEGIN_MESSAGE_MAP(CMyToolBar, CToolBarCtrl) -> CToolBar로 수정 //{{AFX_MSG_MAP(CMyToolBar) // NOTE - the ClassWizard will add and remove mapping .. //}}AFX_MSG_MAP END_MESSAGE_MAP() ISLab ICE HUFS MFC Tutorial 106 MainFrm.h 수정 #include “MyToolBar.h” // 추가 class CMainFrame : public CMDIFrameWnd { DECLARE_DYNAMIC(CMainFrame) public: CMainFrame(); . . . . protected: CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; -> CMyToolBar m_wndToolBar로 수정 ISLab ICE HUFS MFC Tutorial 107 리소스 파일 • obedit.rc • 텍스트를 리소스 뷰에서 그래픽으로 나타냄 – 리소스 편집의 편리 ISLab ICE HUFS MFC Tutorial 108 Obedit.rc 수정 IDR_MAINFRAME TOOLBAR DISCARDABLE 16,15 BEGIN BUTTON ID_FILE_NEW BUTTON ID_FILE_OPEN BUTTON ID_FILE_SAVE SEPARATOR BUTTON ID_OBJECT_LINE BUTTON ID_OBJECT_ELLIPSE BUTTON ID_OBJECT_RECTANGLE SEPARATOR BUTTON ID_OBJECT_PENATTR BUTTON ID_FILE_PRINT BUTTON ID_APP_ABOUT SEPARATOR SEPARATOR // 12번째 스태택바 붙일 위치 (0부터 세어서) SEPARATOR SEPARATOR // 14번째 스태틱컨트롤을 붙일 위치 END ISLab ICE HUFS MFC Tutorial 109 MainFrame에 변수 추가 • CMainFrame에 멤버 추가 – CScrollBar – CStatic m_zoomScroll; m_zoomStatic ISLab ICE HUFS MFC Tutorial 110 CMainFrame::OnCreate 수정 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { . . . EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); CRect rect; 80 픽셀 // Scroll Bar 생성 m_wndToolBar.SetButtonInfo(12, ID_ZOOMSCROLL, TBBS_SEPARATOR, 80); m_wndToolBar.GetItemRect(12, &rect); rect.top = 3; if (!m_wndToolBar.m_zoomScroll.Create(WS_VISIBLE | SBS_HORZ | WS_TABSTOP, rect, &m_wndToolBar, ID_ZOOMSCROLL)) return -1; Resource Symbol로 등록 ISLab ICE HUFS MFC Tutorial 111 // 스태택 컨트롤 추가 m_wndToolBar.SetButtonInfo(14, ID_ZOOMSTATIC, TBBS_SEPARATOR, 60); m_wndToolBar.GetItemRect(14, &rect); rect.top = 6; if (!m_wndToolBar.m_zoomStatic.Create(“배율”, WS_VISIBLE | SS_LEFT | WS_TABSTOP, rect, &m_wndToolBar, ID_ZOOMSTATIC)) return -1; Resource Symbol로 등록 return 0; } ISLab ICE HUFS MFC Tutorial 112 리소스 심볼 등록 #define ID_ZOOMSCROLL 101 // 리소스 심볼을 등록하는 것과 왼쪽과 같이 // 정의하는 것은 동일한 효과임 심볼 등록 ISLab ICE HUFS MFC Tutorial 113 생성된 모습 ISLab ICE HUFS MFC Tutorial 114 CToolBar 클래스의 주요 함수 CommandToIndex 버튼 ID를 주면 툴바의 좌측부터 세어 그에 해당하는 인덱스를 준다. 0부터 센다. GetItemID CommandToIndex와는 반대로 버튼의 인덱스로부터 버튼 ID를 얻어준다. Create 툴바를 생성한다. EnableDocking 도커블 툴바로 동작할 수 있도록 설정하며 프로임 윈도우의 어느 곳에 붙을 수 있는지도 명시한다. GetBarStyle툴바의 스타일을 얻어온다. SetBarStyle 툴바의 스타일을 설정한다. GetButtonInfo 특정 버튼에 대한 정보를 얻어온다. SetButtonInfo 특정 버튼의 정보를 변경한다. GetCount 툴바 버튼의 총수를 얻어온다(SEPARATOR 포함). GetItemRect 버튼 ID를 주면 그 버튼의 툴바에서의 위치를 돌려준다. LoadBitmap 버튼 모양을 담고 있는 비트맵을 로드한다. SetHeight 툴바의 버튼 높이를 변경한다. SetSizes 툴바의 크기를 변경한다. ISLab ICE HUFS MFC Tutorial 115 상태바(Status Bar) • 생성 순서 – CStatusBar 오브젝트를 만든다. – CStatusBar 오브젝트의 Create 함수를 호출하여 상태바 윈도우를 생성 – SetIndicator 함수를 호출하여 각 텍스트 출력창과 스트링 ID를 연결시킨다. static UINT indicators[ ] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; ISLab ICE HUFS MFC Tutorial 116 클래스 위저드 클래스 이름 메뉴 가상함수 메시지 이미 만든 함수들 ISLab ICE HUFS MFC Tutorial 117 Pane 텍스트 수정 • SetWindowText 함수로 텍스트 갱신 • Command UI 핸들러의 SetText 함수 호출 void CMainFrame::OnUpdateIndicatorTime(CCmdUI* pCmdUI) { pCmdUI->SetText(“Pane에 출력”); } • SetPaneText 함수 이용 CStatusBar bar; bar.SetPaneText(0, “Pane에 출력”); ISLab ICE HUFS MFC Tutorial 118 상태바의 수정(1) • indicators 변수 수정(MainFrm.cpp) static UINT indicators [] = { ID_SEPARATOR, // status line indicator ID_SEPARATOR, // 추가 ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; ISLab ICE HUFS MFC Tutorial 119 상태바의 수정(2) • CMainFrame 클래스의 OnCreate 함수 수정 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... DockControlBar(&m_wndToolBar); m_wndStatusBar.SetPaneInfo(1,ID_INDICATOR_TIME,SBPS_NORMAL,60); return 0; } – 1은 상태바의 두 번째 창을 가리킨다. – 폭은 오른쪽부터 계산 – Resource Symbol을 이용하여 ID_INDICATOR_TIME 등록 ISLab ICE HUFS MFC Tutorial 120 시간 출력 • 클래스 위저드를 이용하여 명령 UI 갱신핸들러 생성 – View 메뉴의 ClassWizard 선택 • Object IDs: ID_INDICATOR TIME • Messages: UPDATE_COMMAND_UI – 함수 생성 (OnUpdateIndicatorTime) void CMainFrame::OnUpdateIndicatorTime(CCmdUI* pCmdUI) { char timebuf[12]; _strtime(timebuf); pCmdUI->SetText(timebuf); } • 이벤트 발생시 마다 매번 함수 호출 ISLab ICE HUFS MFC Tutorial 121 MFC의 주요 전역 함수 AfxGetApp AfxGetAppName AfxGetInstanceHandle AfxGetMainWnd GetCurrentMessage AfxSocketInit AfxBeginThread AfxEndThread AfxGetThread 프로그램을 대표하는 프로그램 오브젝트에 대한 포인터를 돌려준다. 프로그램의 이름을 돌려준다. 프로그램의 인스턴스 핸들을 돌려준다. 메인 프레임 윈도우 오브젝트에 대한 포인터를 돌려준다. 현재 처리 중인 메시지에 대한 메시지 스트럭처를 돌려준다. 메시지 핸들러 등에서 메시지 스트럭처 를 직접 접근하고 싶을 때 이용한다. 윈도우 소켓을 초기화하기 위해 부른다. 새로운 스레드를 시작한다. 현재의 스레드를 끝낸다. 현재 실행 중인 스레드에 대한 포인터 (CWinThread)를 돌려준다. ISLab ICE HUFS MFC Tutorial 122 컬러 바 클래스 생성 • 클래스 위저드에서 새로운 클래스 생성 – Add Class/New에서 CMyColorBar 클래스 생성 – 상위 클래스로 CToolBarCtrl을 선택 – MyColorBar.cpp, MyColorBar.h에서 CToolBarCtrl을 CToolBar로 수 정 – 정확한 색 선택: Image 메뉴의 Adjust Colors... 선택 후 숫자로 색 입력 ISLab ICE HUFS MFC Tutorial 123 툴바 리소스 생성 • 리소스 뷰에서 새로운 Toolbar 생성 – 버튼의 자료구조 (MyColorBar.cpp에 정의) COLORREF color[16] = { RGB( 0, 0, 0), RGB(192,192,192), RGB(255, 0, 0), RGB( 0,255, 0), RGB( 0, 0,255), RGB(128, 0, 0), RGB( 0,128, 0), RGB( 0, 0,128), }; RGB(255,255,255), RGB(128,128,128), RGB(255,255, 0), RGB( 0,255,255), RGB(255, 0,255), RGB(128,128, 0), RGB( 0,128,128), RGB(128, 0,128) ISLab ICE HUFS MFC Tutorial 124 색깔 선택 • Image 메뉴 – Adjust Colors... ISLab ICE HUFS MFC Tutorial 125 ColorBar 생성 #include “MyColorBar.h” class CMainFrame : public CMDIFrameWnd { DECLARE_DYNAMIC(CMainFrame) ... protected: CToolBar m_wndToolBar; CMyColorBar m_wndColorBar; ... }; ISLab ICE HUFS MFC Tutorial 126 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { .... m_wndStatusBar.SetPaneInfo(1,ID_INDICATOR_TIME,SBPS_NORMAL,60); if (!m_wndColorBar.Create(this,WS_CHILD | WS_VISIBLE | CBRS_SIZE_FIXED | CBRS_LEFT | CBRS_FLYBY, ID_COLORBAR) || !m_wndColorBar.LoadToolBar(IDR_MYCOLORBAR)) { return FALSE; } m_wndColorBar.SetColumns(2); m_wndColorBar.EnableDocking(CBRS_ALIGN_LEFT | CBRS_ALIGN_RIGHT); DockControlBar(&m_wndColorBar); return 0; } ISLab ICE HUFS MFC Tutorial 127 void CMyColorBar::SetColumns(UINT nColumn) { int nCount = GetToolBarCtrl().GetButtonCount(); for(int i = 0; i < nCount; i++) { UINT nStyle = GetButtonStyle(i); BOOL bWrap = (((i+1) % nColumn) == 0); if (bWrap) nStyle |= TBBS_WRAPPED; else nStyle &= ~TBBS_WRAPPED; SetButtonStyle(i, nStyle); } Invalidate(); GetParentFrmae()->RecalcLayout(); } ISLab ICE HUFS MFC Tutorial 128 ISLab ICE HUFS 도형 처리 추가 사용자 클래스 디자인 CDrawObject CLine CEllipse CRectangle ISLab ICE HUFS MFC Tutorial 130 사용자 클래스 class CDrawObject : public CObject { protected: CDrawObject(WORD objType, COLORREF crColor, int nPenStyle, int nPenWidth); public: COLORREF m_crColor; // 이 도형의 색상 int m_nPenStyle; // 도형 둘레를 긋는 선의 스타일. PS_SOLID, // PS_DOT,PS_DASH,PS_DASHDOT,PS_DASHDOTDOT // 등의 값이 가능하다. int m_nPenWidth; // 도형 둘레를 긋는 선의 폭 int m_rcRect; // 도형의 위치를 나타낸다. public: WORD m_wObjType; // 이 오브젝트의 타입을 가리킨다. 이 타입을 가리키는 // 값은 밑에 있는 enum ObjectType의 objectLine, // objectRectangle, objectEllipse 중의 하나가 // 될 수 있다. ISLab ICE HUFS MFC Tutorial 131 enum ObjectType { objectLine, objectEllipse, objectRectangle }; virtual virtual virtual virtual virtual virtual virtual virtual ~CDrawObject(); void DrawObject(CDC *pDC) = 0; // pure virtual function void SetStartPoint(CPoint pt) {m_rcRdct.TopLeft() = pt;} void SetEndPoint(CPoint pt) {m_rcRect.BottomRight()=pt;} CPoint& GetStartPoint() { return m_rcRect.TopLeft(); } CPoint& GetEndPoint() { return m_rcRect.BottomRight(); } void GetBoundingRect(CRect *pRect); void Serialize(CArchive& ar); #ifdef _DEBUG virtual void AssertValid() const; // 유효성 여부 검사 virtual void Dump(CDumpContext& dc) const; // 객체의 내용을 디버그 // 윈도우로 #endif }; ISLab ICE HUFS MFC Tutorial 132 class CLine : public CDrawObject { protected: DECLARE_SERIAL(CLine) public: CLine(); CLine(COLORREF crColor, int nPenStyle, int nPenWidth); virtual ~CLine(); virtual void DrawObject(CDC *pDC); virtual void Serialize(CArchive& ar); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif }; ISLab ICE HUFS MFC Tutorial 133 class CEllipse : public CDrawObject { protected: DECLARE_SERIAL(CEllipse) public: CEllipse(); CEllipse(COLORREF crColor, int nPenStyle, int nPenWidth); virtual ~CEllipse(); virtual void DrawObject(CDC* pDC); virtual void Serialize(CAarchive& ar); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif }; ISLab ICE HUFS MFC Tutorial 134 class CRectangle : public CDrawObject { protected: DECLARE_SERIAL(CRectangle) public: CRectangle(); CRectangle(COLORREF crColor, int nPenStyle, int nPenWidth); virtual ~CEllipse(); virtual void DrawObject(CDC* pDC); virtual void Serialize(CAarchive& ar); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif }; ISLab ICE HUFS MFC Tutorial 135 #include “stdafx.h” #include “DrawObj.h” CDrawObject::CDrawObject(WORD objType, COLORREF crColor, int nPenStyle, int nPenWidth) : m_wObjType(objType), m_crColor(crColor), m_nPenStyle(nPenStyle), m_nPenWidth(nPenWidth) { m_rcRect.SetRectEmpty(); } CDrawObject::~CDrawObject() { } void CDrawObject::GetBoundingRect(CRect* pRect) { pRect->left = min(m_rcRect.left, m_rcRect.right); pRect->right = max(m_rcRect.left, m_rcRect.right); pRect->top = min(m_rcRect.top, m_rcRect.bottom); pRect->bottom = max(m_rcRect.top, m_rcRect.bottom); pRect->InflateRect(m_nPenWidth, m_nPenWidth); } ISLab ICE HUFS MFC Tutorial 136 void CDrawObject::Serialize(CArchive& ar) { if (ar.IsStoring()) { } else { } } #ifdef _DEBUG void CDrawObject::AssertValid() const { CObject::AssertValid(); } void CDrawObject::Dump(CDumpContext& dc) const { CObject::Dump(dc); } #endif ISLab ICE HUFS MFC Tutorial 137 IMPLEMENT_SERIAL(CLine, CObject, 1) CLine::CLine() : CDrawObject(objectLine, RGB(0,0,0), PS_SOLID, 1) { } CLine::CLine(COLORREF crColor, int nPenStyle, int nPenWidth) : CDrawObject(objectLine, crColor, nPenStyle, nPenWidth) { } CLine::~CLine() { } void CLine::DrawObject(CDC* pDC) { CPen pen, *ppenOld; pen.CreatePen(m_nPenStyle, m_nPenWidth, m_crColor); ppenOld = pDC->SelectObject(&pen); pDC->MoveTo(m_rcRect.TopLeft()); pDC->LineTo(m_rcRect.BottomRight()); pDC->SelectObject(ppenOld); } ISLab ICE HUFS MFC Tutorial 138 void CLine::Serialize(CArchive& ar) { CDrawObject::Serialize(ar); if (ar.IsStoring()) { } else { } } #ifdef _DEBUG void CLine::AssertValid() const { CDrawObject::AssertValid(); } void CLine::Dump(CDumpContext& dc) const { CDrawObject::Dump(dc); } #endif ISLab ICE HUFS MFC Tutorial 139 IMPLEMENT_SERIAL(CEllipse, CObject, 1) CEllipse::CEllipse() : CDrawObject(objectEllipse,RGB(0,0,0),PS_SOLID,1) { } CEllipse::CEllipse(COLORREF crColor, int nPenStyle, int nPenWidth) : CDrawObject(objectEllipse, crColor, nPenStyle, nPenWidth) { } void CEllipse::DrawObject(CDC* pDC) { CBrush br, *pbrOld; CPen pen, *ppenOld; br.CreateSolidBrush(m_crColor); pen.CreatePen(m_nPenStyle, m_nPenWidth, m_crColor); pbrOld = pDC->SelectObject(&br); ppenOld = pDC->SelectObject(&pen); pDC->Ellipse(&m_rcRect); pDC->SelectObject(pbrOld); pDC->SelectObject(ppenOld); } ISLab ICE HUFS MFC Tutorial 140 CEllipse::~CEllipse() { } void CEllipse::Serialize(CArchive& ar) { CDrawObject::Serialize(ar); if (ar.IsStoring()) { } else { } } #ifdef _DEBUG void CEllipse::AssertValid() const { CDrawObject::AssertValid(); } void CEllipse::Dump(CDumpContext& dc) const { CDrawObject::Dump(dc); } #endif ISLab ICE HUFS MFC Tutorial 141 IMPLEMENT_SERIAL(CRectangle, CObject, 1) CRectangle::CRectangle() : CDrawObject(objectRectangle,RGB(0,0,0),PS_SOLD,1) { } CRectangle::CRectangle(COLORREF crColor,int nPenStyle,int nPenWidth) : CDrawObject(objectEllipse, crColor, nPenStyle, nPenWidth) { } void CRectangle::DrawObject(CDC* pDC) { CBrush br, *pbrOld; CPen pen, *ppenOld; br.CreateSolidBrush(m_crColor); pen.CreatePen(m_nPenStyle, m_nPenWidth, m_crColor); pbrOld = pDC->SelectObject(&br); ppenOld = pDC->SelectObject(&pen); pDC->Rectangle(&m_rcRect); pDC->SelectObject(pbrOld); pDC->SelectObject(ppenOld); } ISLab ICE HUFS MFC Tutorial 142 CRectangle::~CRectangle() { } void CRectangle::Serialize(CArchive& ar) { CDrawObject::Serialize(ar); if (ar.IsStoring()) { } else { } } #ifdef _DEBUG void CRectangle::AssertValid() const { CDrawObject::AssertValid(); } void CRectangle::Dump(CDumpContext& dc) const { CDrawObject::Dump(dc); } #endif ISLab ICE HUFS MFC Tutorial 143 윈도우 운영체제에서의 출력 응용 프로그램 WIN32 API GDI (Graphic Device Interface) 디바이스 드라이버 실제 출력 장치 ISLab ICE HUFS MFC Tutorial 144 DirectX • 윈도우 3.1의 그래픽 출력 속도 저하 극복을 위해 – 게임 (WinG) • DirectDraw – DirectX의 그래픽 부분 라이브러리 • DirectPlay – 네트워크 게임을 만드는데 사용할 수 있는 라이브러리 • DirectSound – 사운드 기능을 제공해 주는 라이브러리 • DirectInput – 조이스틱 등의 제어에 사용할 수 있는 라이브러리 ISLab ICE HUFS MFC Tutorial 145 디바이스 컨텍스트 • Device Context • 윈도우 운영체제에서 출력 대상을 지칭하는 것 • 논리적으로 볼 때 붓, 펜, 팔레트, 종이(비트맵), 폰트 등 의 그림을 그리기 위한 도구의 집합 • 장치와 문관하게 GDI 함수 호출 가능 • 붓과 펜은 DC 내에 하나씩 존재 • GetDC & ReleaseDC ISLab ICE HUFS MFC Tutorial 146 DC의 종류 • CClientDC – 윈도우의 클라이언트 영역 • CWindowDC – 윈도우 전체 디바이스 컨텍스트 – 윈도우의 경계선, 캡션 영역 등에도 그리기 가능 • CPaintDC – WM_PAINT 발생시에 사용 ISLab ICE HUFS MFC Tutorial 147 윈도우 운영체제에서의 출력 절차 출력할 장치의 디바이스 컨텍스트의 핸들을 얻는다. GDI로 앞에서 얻은 핸들에 출력을 행한다. 디바이스 컨텍스트를 제거한다. ISLab ICE HUFS MFC Tutorial 148 SDK에서의 붓과 펜의 변경 절차 1. 펜이나 붓을 생성한다(CreatePen, CreateSolidBrush). 2. 디바이스 컨텍스트를 얻는다(GetDC나 BeginPaint). 3. 2에서 얻은 디바이스149 컨텍스트의 드로잉 툴을 1에서 만든 드로잉 툴로 바꾼다(SelectObject). 교체하면서 원래 들어있던 펜이나 붓을 기억해야. 4. GDI를 이용해 출력 작업을 수행한다. 5. 3에서 기억해 놓았던 원래의 붓이나 펜을 원상복구 시킨다(SelectObject). 6. 디바이스 컨텍스트를 윈도우 운영체제로 반환한다. 7. 1에서 만든 펜이나 붓을 삭제한다(DeleteObject). ISLab ICE HUFS MFC Tutorial 149 CDC 클래스의 주요 함수(1) CreateCompatibleDC GetSafeHdc IsPrinting SetROP2 SetBkColor SetTextColor MoveTo, LineTo Arc, ArcTo PolyDraw PloyLine Polygon 인자로 주어진 DC와 같은 속성을 갖는 DC를 메모리에 만든다. 현재 오브젝트가 둘러싸고 있는 디바이스 컨텍스트 핸들을 돌려준다. 프린트 DC인지 아닌지의 여부를 돌려준다. 그리기모드를 변경하는데 사용된다. 글자출력 시의 배경색을 지정한다. 글자출력 시의 글자색을 지정한다. 직선을 긋는데 사용한다. 원호를 그리는데 사용한다. 직선과 베지어 스프라인을 연속적으로 그림 직선을 연속적으로 그리는데 사용 직선을 연속적으로 그리는데 처은 점과 마지막 점을 잇는다 ISLab ICE HUFS MFC Tutorial 150 CDC 클래스의 주요 함수(2) PolyBezier InvertRect DrawIcon Draw3dRect Ellipse Pie Rectangle RountRect SetPixel BitBlt TextOut DrawText 베이어 스프라인을 연속적으로 그리는데 사용 주어진 영역을 반전하는데 사용한다. 주어진 위치에 주어진 아이콘을 그려준다. 입체적인 사각형을 그리는데 사용한다. 타원(원 포함)을 그리는데 사용한다. 부채꼴을 그리는데 사용한다. 사각형을 그리는데 사용한다. 모서리가 둥근 사각형을 그리는데 사용한다. 점을 찍는데 사용한다. 한 디바이스 컨텍스트의 내용을 다른 디바이스 컨텍스트로 복사한다. 주어진 위치에 텍스트를 출력한다. 주어진 사각형 내에 텍스트를 출력한다. ISLab ICE HUFS MFC Tutorial 151 View 클래스 변경(1) #include “DrawObj.h” class CObeditView : public CScrollView { .... // Attributes public: CObeditDoc* GetDocument(); int m_nSelectedColorID; // 현재 컬러 팔레트에서 선택된 버튼의 인덱스 COLORREF m_crCurColor; // 컬러 팔레트에서 선택된 버튼에 해당하는 RGB 값 int m_nPenStyle; // 현재 선택된 펜 스타일 int m_nPenWidth; // 현재 선택된 펜의 굵기 CDrawObject* m_pCurDrawObject; // 현재 만들어지고 있는 도형 WORD m_wCurDrawObject; // 현재 선택된 도형이 무엇인지 나타낸다. .... }; ISLab ICE HUFS MFC Tutorial 152 View 클래스 변경(2) extern COLORREF color[16]; CObeditView::CObeditView() { m_nSelectedColorID = 0; // 디폴트로 선택되는 컬러 팔레트의 버튼은 첫번째 m_crCurColor = color[m_nSelectedColorID]; // 첫번째 버튼에 해당하는 색 m_nPenStyle = PS_SOLID; // 펜의 초기 스타일 m_nPenWidth = 1; m_pCurDrawObject = NULL; m_wCurDrawObject = CDrawObject::objectLine; } ISLab ICE HUFS MFC Tutorial 153 메뉴 선택 코드 추가 • 클래스 위저를 통한 메뉴 함수 구현 ISLab ICE HUFS MFC Tutorial 154 메뉴 선택 함수 void CObeditView::OnObjectLine() { m_wCurDrawObject = CDrawObject::objectLine; } void CObeditView::OnObjectRectangle() { m_wCurDrawObject = CDrawObject::objectRectangle; } void CObeditView::OnObjectEllipse() { m_wCurDrawObject = CDrawObject::objectEllipse; } ISLab ICE HUFS MFC Tutorial 155 메뉴의 UPDATE_COMMAND_UI void CObeditView::OnUpdateObjectLine(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_wCurDrawObject == CDrawObject::objectLine); } void CObeditView::OnUpdateObjectRectangle(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_wCurDrawObject == rawObject::objectRectangle); } void CObeditView::OnUpdateObjectRectangle(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_wCurDrawObject == DrawObject::objectRectangle); } ISLab ICE HUFS MFC Tutorial 156 칼라 메뉴 void CObeditView::OnPalettecolor1() { m_nSelectedColorID = 0; m_crCurColor = color[0]; } // 컬러 팔레트 메뉴 함수. 16번 반복 void CObeditView::OnUpdatecolor1(CCmdIO* pCmdUI) { pCmdUI->SetCheck(m_nSelectedColorID == 0); } ISLab ICE HUFS MFC Tutorial 157 Message Map • 기존 윈도우 프로시저를 대신 BEGIN_MESSAGE_MAP(CObeditView, CScrollView) //{{AFX_MSG_MAP(CObeditView) ON_COMMAND(ID_OBJECT_ELIIPSE, OnObjectEllipse) ON_UPDATE_COMMAND_UI(ID_OBJECT_ELLIPSE, OnUpdateObjectEllise) ON_COMMAND(ID_OBJECT_LINE, OnObjectLine) ON_UPDATE_COMMAND_UI(ID_OBJECT_LINE, OnUpdateObjectLine) ON_COMMAND(ID_OBJECT_RECTANGLE, OnObjectRectangle) ON_UPDATE_COMMAND_UI(ID_OBJECT_RECTANGLE, OnUpdateObjectRectangle) //}}AFX_MSG_MAP //Standard printing commands ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview) END_MESSAGE_MAP() ISLab ICE HUFS MFC Tutorial 158 윈도우의 입력 메시지 종류 • 하드웨어적인 이유로 발생하는 메시지 – 키보드 – 마우스 – 타이머 • 키보드 메시지나 마우스 메시지를 해석하여 발생하는 메시지 – 캐릭터 – 스크롤 바 – 메뉴 ISLab ICE HUFS MFC Tutorial 159 키보드 입력 메시지 • 종류 – WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP • 가상 키 코드 (virtual keycode) - lParam 비트 0 - 15 비트 16 - 23 비트 비트 비트 비트 비트 비트 24 25 - 26 27 - 28 29 30 31 키의 반복 횟수 키의 스캔 코드 (키보드 제조업체에 따라 다를 수 있다) 확장 키 여부 (1 : 확장키, 0 : 아님) 쓰이지 않음 윈도우 운영체제가 내부적으로 사용 컨텍스트 코드 (1 : Alt 키가 눌림, 0 : 안 눌림) 키의 이전 상태 (1 : 키가 눌려져 있었음, 0 : 아님) 키의 현재 전환 상태 (1 : 키가 떼어지는 것, 0 : 눌려지는 것) ISLab ICE HUFS MFC Tutorial 160 문자 입력 메시지 • 종류 – WM_CHAR, WM_SYSCHAR • 메시지 발생 순서 – 아스키 코드가 있을 때(SDK에서는 TranslateMessage 함수가 반 드시 불려야 WM_KEYDOWN --> WM_CHAR --> WM_KEYUP – 아스키 코드가 없을 때(예 : ENTER) WM_KEYDOWN --> WM_KEYUP • 인자 – wParam : 아스키 코드 – lParam : WM_KEYDOWN, WM_KEYUP에서와 같음 ISLab ICE HUFS MFC Tutorial 161 마우스 메시지의 처리 • 마우스 이벤트의 종류 – – – – – – – WM_LBUTTONDBLCLK WM_LBUTTONDOWN WM_LBUTTONUP WM_MOUSEMOVE WM_RBUTTONDBLCLK WM_RBUTTONDOWN WM_RBUTTONUP • 넘어오는 좌표 : Pixel 단위 ISLab ICE HUFS MFC Tutorial 162 마우스 메시지와 윈도우 t1에서 t2 사이에는 1번 윈도우로 마우스 메시지가 발생하고, t2와 t3 사이에는 2번 윈도우로 메시지가 발생한다. 1 t1 t2 t3 2 마우스 커서의 이동 자취 ISLab ICE HUFS MFC Tutorial 163 드래그시의 문제점 • SetCapture, ReleaseCapture 1. 드래그 시작 2. 윈도우 바깥으로 나가면 마우스 메시지가 이 윈도우에게로 발생하지 않는다. ISLab ICE HUFS MFC Tutorial 164 타이머 입력 메시지 • 종류 – WM_TIMER • 주기적으로 하고 싶은 일이 있을 때 사용되는 메시지 – 예) 워드프로세서에서 주기 저장, 테트리스 게임에서 적당 시간 간격으로 블록을 떨어뜨릴 때 • SetTimer, KillTimer ISLab ICE HUFS MFC Tutorial 165 타이머 설정 • CMainFrame 클래스의 OnCreate 함수에서 설정 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ... DockControlBar(&m_wndToolBar); m_wndStatusBar.SetPaneInfo(1,ID_INDICATOR_TIME,SBPS_NORMAL,60); SetTimer(1, 1000, NULL); return 0; } ISLab ICE HUFS MFC Tutorial 166 WM_TIMER 메시지 처리 함수 void CMainFrame::OnTimer(UINT nIDEvent) { // TODO: Add your message handler code here and/or call default char timebuf[12]; _strtime(timebuf); m_wndStatusBar.SetPaneText(1, timebuf, TRUE); CMDIFrameWnd::OnTimer(nIDEvent); } • CMainFrame이 아닌 다른 클래스에서 불릴때 void f() { ... ((CMainFrame*)AfxGetMainWnd())->UpdateTime(); // 다른 클래스에서 ... } ISLab ICE HUFS MFC Tutorial 167 타이머 해제 void CMainFrame::f() { ... SetTimer(1, 1000, NULL); SetTimer(2, 10000, lpFuction); ... } void CMainFrame::g() { ... KillTimer(1); KillTimer(2); ... } void lpFunction(HWND hWnd, UINT, UINT, DWORD) { ... } ISLab ICE HUFS MFC Tutorial 168 타이머 사용시 주의점 • PC 타이머 칩이 발생시키는 최소 시간 간격 : 55 밀리초 • 메시지 큐에서 약간의 지연 발생 • WM_TIMER 메시지 처리가 늦어지면 메시지가 쌓여 큐가 넘칠 수 있으므로 메시지 큐에서는 하나의 WM_TIMER 만 가능 (WM_PAINT도 마찬가지) ISLab ICE HUFS MFC Tutorial 169 스크롤 바 입력 메시지 • 종류 – WM_VSCROLL, WM_HSCROLL SB_PAGEUP SB_PAGEDOWN SB_LINEUP SB_LINEDOWN ISLab ICE HUFS MFC Tutorial 170 메뉴 입력 메시지 • 종류 – WM_COMMAND, WM_SYSCOMMAND • 단축키 사용 가능 • ASCII vs. VIRTKEY ISLab ICE HUFS MFC Tutorial 171 LButtonDown void CObeditView::OnLButtonDown(UINT nFlags, CPoint point) { switch(m_wCurDrawObject) // 객체 생성 { case CDrawObject::objectLine : m_pCurDrawObject = new CLine(m_crCurColor, m_nPenStyle, m_nPenWidth); break; case CDrawObject::objectRectangle : m_pCurDrawObject = new CRectangle(m_crCurColor,m_nPenStyle,m_nPenWidth); break; case CDrawObject::objectEllipse : m_pCurDrawObject = new CEllipse(m_crCurColor, m_nPenStyle, m_nPenWidth); break; } m_pCurDrawObject->SetStartPoint(point); // 객체의 시작위치 저장 m_pCurDrawObject->SetEndPoint(point); SetCapture(); } // 모든 마우스 메시지가 CObeditView 객체로 온다. // 마우스 메시지 독점. 마우스 드래그를 지원하기 위해 // ReleaseCapture 호출 때까지 ISLab ICE HUFS MFC Tutorial 172 MouseMove void CObeditView::OnMouseMove(UINT nFlags, CPoint point) { if (GetCapture() == this) // 드래그 중인지 판단 { CClientDC dc(this); dc.SetROP2(R2_NOTXORPEN); // XOR 모드로 그림을 그린다. m_pCurDrawObject->DrawObject(&dc); // 이전에 그려졌던 도형을 지운다 m_pCurDrawObject->SetEndPoint(point); // 새로운 도형의 위치 저장 m_pCurDrawObject->DrawObject(&dc); // 새로운 위치에 도형을 그린다. // virtual function } } ISLab ICE HUFS MFC Tutorial 173 LButtonUp void CObeditView::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture() == this) { CClientDC dc(this); m_pCurDrawObject->SetEndPoint(point); m_pCurDrawObject->DrawObject(&dc); ReleaseCapture(); // 마우스 독점 해제 } } ISLab ICE HUFS MFC Tutorial 174 윈도우에서의 화면 복구 1 1 1 2 1번 윈도우에 의해 가려 졌던 2번 윈도우가 클릭 된다. 2 가려졌던 영역이 일단 WM_ERASEBKGND 메시지에 의해 지워진다. 2 WM_PAINT 메시지에 의해 가려졌던 영역이 복구된다. ISLab ICE HUFS MFC Tutorial 175 WM_PAINT • 화면을 복구하는데 사용 – 윈도우로 출력하는데 사용되는 메시지가 아니다. • 윈도우가 처음 생성될 때도 한번 발생 • 새로 그려야 할 영역 고려 ISLab ICE HUFS MFC Tutorial 176 WM_PAINT - SDK • SDK에서 – 반드시 BeginPaint / EndPaint 함수를 이용하여야 한다. – 그려야 할 영역을 PAINTSTRUCT 인자로 알 수 있기 때문 HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd, &ps); // ps.rcPaint에 복구 영역의 좌표가 들어있다. // 이 부분만 딱 그려줄 수 있다면 가장 이상적이다. EndPaint(hWnd, &ps); ISLab ICE HUFS MFC Tutorial 177 WM_PAINT • OnDraw 함수 호출 void CView::OnPaint() { CPaintDC dc(this); OnPrepareDC(&dc); OnDraw(&dc); } ISLab ICE HUFS MFC Tutorial 178 자료 구조 유지 • 다시 그리기 위한 자료 구조 유지 class CObeditDoc : public CDocument { .... // Attributes public: CObList m_objectList; .... } ISLab ICE HUFS MFC Tutorial 179 LButtonUp 수정 void CObeditView::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture() == this) { CClientDC dc(this); m_pCurDrawObject->SetEndPoint(point); m_pCurDrawObject->DrawObject(&dc); ReleaseCapture(); // 마우스 독점 해제 CObeditDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->m_objectList.AddTail(m_pCurDrawObject); } } ISLab ICE HUFS MFC Tutorial 180 OnDraw void CObeditView::OnDraw(CDC* pDC) { ObeditDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); CRect rectClip, rectObject; pDC->GetClipBox(&rectClip); // 복구해야할 영역 POSITION pos = pDoc->m_objectList.GetHeadPosition(); while( pos != NULL ) { CDrawObject* pObject = (CDrawObject*) pDoc->m_objectList.GetNext(pos); pObject->GetBoundingRect(&rectObject); // 복구해야할 영역과 겹치는 부분만 다시 그림 if (!rectObject.IntersectRect(&rectObject, &rectClip)) continue; pObject->DrawObject(pDC); } } ISLab ICE HUFS MFC Tutorial 181 SDK/MFC에서의 메시지 처리 LONG __export FAR PASCAL MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE : OnCreate(); break; case WM_PAINT : OnPaint(); break; case WM_DESTROY : OnDestroy(); break; default : DefWindowProc(); } return OL; } BEGIN_MESSAGE_MAP(CMyWnd, CWnd) ON_WM_CREATE() ON_WM_PAINT() ON_WM_DESTROY() END_MESSAGE_MAP() AFX_MSGMAP_ENTRY _messageEntries[]= { { WM_CREATE, OnCreate }, { WM_PAINT, OnPaint }, { WM_DESTROY, OnDestroy } }; ISLab ICE HUFS MFC Tutorial 182 MFC에서의 메시지 처리(1) • CMainFrame BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP() int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // 상위 클래스의 OnCreate 부터 부른 다음 작업 수행 if(CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) .... ISLab ICE HUFS MFC Tutorial 183 MFC에서의 메시지 처리(2) • CWnd _AFXWIN_INLINE afx_msg int CWnd::OnCreate(LPCREATESTRUCT) { return (int)Default(); // DefWindowProc()을 부름 } – 대부분의 메시지는 거의 모두 Default()를 부름 ISLab ICE HUFS MFC Tutorial 184 명령 경로 배정(command routing) • WM_COMMAND, WM_UPDATE_COMMAND_UI – CCmdTarget로부터 계승받은 클래스만 받을 수 있다. • 메뉴 처리 – CWnd가 아닌 CDocument, CView에서 처리하는 것이 자연스러움 • 예) 화일 저장, 색 선택 ISLab ICE HUFS MFC Tutorial 185 CCmdTarget 클래스 CObject CCmdTarget CWinApp CDocTemplate CMultiDocTemplate CWnd CSingleDocTemplate CFrameWnd CView CDocument CDialog ISLab ICE HUFS MFC Tutorial 186 Routing 순서 Comand를 받은 오브젝트 routing 순서 프레임 윈도우 1. 활성화된 자식윈도우 혹은 뷰 2. 자기 자신 3. CWinApp 오브젝트 뷰(View) 1. 자기 자신 2. 자신과 연관된 문서오브젝트 문서(Document) 1. 자기 자신 2. 이 문서가 속한 문서템플릿 다이얼로그 1. 자기 자신 2. 이 다이얼로그를 소유한 윈도우 오브젝트 3. CWinApp 오브젝트 ISLab ICE HUFS MFC Tutorial 187 CCmdUI의 멤버 함수 멤버함수 이름 Enable 기능 메뉴 항목의 상태를 활성화시키거나 그레이 상태로 만든다. SetCheck 메뉴 항목의 옆에 체크 표시를 만든다. 툴바 버튼의 경우에는 눌려진 상태로 표시한다. SetRadio 기능 자체는 SetCheck와 같은데 체크 표시 대신에 표시를 사용한다. SetText 메뉴 항목의 텍스트를 변경한다. 툴바 버튼에 대해서는 별 의미가 없다. ISLab ICE HUFS MFC Tutorial 188 메시지 맵 매크로(1) • 기존의 윈도우 메시지 – WM_XXXX, ON_WM_XXXX, OnXxxxx • 예) WM_CHAR, ON_WM_CHAR, OnChar – WM_COMMAND, WM_UPDATE_COMMAND_UI 메시지는 예외 • 함수의 이름을 사용자가 정할 수 있음, void 처리함수이름(void); • 사용자 정의 메시지 – WM_USER에서 0x7FFF 사이의 값 – ON_MESSAGE – LONG 처리함수 이름(DWORD, LONG); ISLab ICE HUFS MFC Tutorial 189 등록된 메시지(2) • 등록된 메시지 – RegisterWindowMessage 함수를 이용해 메시지 값을 만든 경우 – ON_REGISTERED_MESSAGE, 함수의 인자는 사용 자 정의 메시지 와 동일 • 콘트롤로부터의 알림(notification) 메시지 – ON_CONTROL(알림코드, 컨트롤ID, 처리함수 이름) – void 처리함수이름(void); ISLab ICE HUFS MFC Tutorial 190 사용자 정의 메시지 • 종류 – WM_USER(0x7fff) 부터 • 메시지 전달 방법 – SendMessage • 메시지를 발생시켜 해당 윈도우에서 그 메시지의 처리가 끝난 다음 에야 리턴 – PostMessage • 메시지를 해당 윈도우가 소속된 메시지 큐에 집어넣고 바로 리턴 – 메시지 부가 인자로 다량의 데이타를 보낼 때는 사용자 데이타 타입을WPARAM이나 LPARAM로 캐스팅해서 보낸다. ISLab ICE HUFS MFC Tutorial 191 사용자 정의 메시지 예 #define WM_MYMESSAGE (WM_USER + 1) SendMessage(hTargetWnd, WM_MYMESSAGE, 0, (LPARAM)lpStr); BEGIN_MESSAGE_MAP(...) WM_MESSAGE(WM_MYMESSAGE, OnMyMessage) END_MESSAGE() void CMyWin::OnMyMessage(WPARAM wParam, LPARAM lParam) { lpData = (LPSTR)lParam; ... } ISLab ICE HUFS MFC Tutorial 192 메시지맵 매크로 • 종류 – – – – ON_COMMAND_RANGE ON_COMMAND_EX ON_UPDATE_COMMAND_UI_RANGE ON_CONTROL_RANGE ISLab ICE HUFS MFC Tutorial 193 Message Map Macro의 예 • CObeditView.cpp BEGIN_MESSAGE_MAP(CObeditView, CScrollView) //{{AFX_MSG_MAP(CObeditView) .... //}}AFX_MSG_MAP // Standard printing commands .... ON_COMMAND_RANGE(ID_PALETTECOLOR1, ID_PALETTECOLOR16, OnColorPalette) ON_UPDATE_COMMAND_UI_RANGE(ID_PALETTECOLOR1, ID_PALETTECOLOR16, OnUpdateColorPalette) END_MESSAGE_MAP() ISLab ICE HUFS MFC Tutorial 194 class CObeditView : public CScrollView { .... protected: //{{AFX_MSG(CObeditView) .... //}}AFX_MSG afx_msg void OnColorPalette(UINT nID); afx_msg void OnUpdateColorPalette(CCmdUI* pCmdUI); DECLARE_MESSAGE_MAP() }; void CObeditView::OnColorPalette(UINT nID) { m_nSelectedColorID = nID; m_crCurColor = color[nID - (UINT)ID_PALETTECOLOR1]; } void CObeditView::OnUpdateColorPalette(CCmdUI* pCmdUI) { pCmdUI->SetCheck(pCmdUI->m_nID == (UINT)m_nSelectedColorID); } ISLab ICE HUFS MFC Tutorial 195 void CMainFrame::OnViewColorbar() { if (m_wndColorBar.GetStyle() & WS_VISIBLE) m_wndColorBar.ShowWindow(SH_HIDE); else m_wndColorBar.ShowWindow(SH_SHOW); RecalcLayout(); void CMainFrame::OnUpdateViewColorbar(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_wndColorBar.GetStyle() & WS_VISIBLE); } ISLab ICE HUFS MFC Tutorial 196 GDI 객체 • GDI 객체 종류 – CBitmap, CBrush, CFont, CPalette, Cpen, CRgn • GDI 존속기간 – GetSafeHdc 함수 이용 void A::f() { CFont* pOldFont = pDC->SelectObject(m_pPrintFont); m_hOldFont = (HFONT) pOldFont->GetSafeHandle(); } void A::g() { if (m_hOldFont) pDC->SelectObject(CFont::FromHandle(m_hOldFont)); } ISLab ICE HUFS MFC Tutorial 197 폰트 설정 void CTestView::ShowFont(CDC* pDC, int& nPos, int nPoints) { TEXTMETRIC tm; CFont fontText; CString strText; CSize sizeText; fontText.CreateFont(-nPoint*20, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, “Arial”); CFont* pOldFont = (CFont*)pDC->SelectObject(&fontText); pDC->GetTextMetrics(&tm); strText.Format(“This is %d-point Arial”, nPoints); sizeText = pDC->GetTextExtent(strText); pDC->TextOut(0, nPos, strText); pDC->SelectObject(pOldFont); nPos -= tm.tmHeight + tm.tmExternalLeading; } ISLab ICE HUFS MFC Tutorial 198 ISLab ICE HUFS 스크롤 기능 목차 • • • • • 매핑 모드 좌표계 스크롤 기능 스크롤 바 논리 물리 좌표간 변환 ISLab ICE HUFS MFC Tutorial 200 Mapping Mode • 매핑 모드(mapping mode) – 윈도우 출력함수(GDI)에서 출력좌표를 해석하는 방법 – 디바이스 컨텍스트(device context)마다 존재 – 디폴트 매핑 모드는 MM_TEXT • MM_TEXT – 출력 원점이 윈도우 클라이언트 영역의 좌측 상단 – 출력 원점에서 X 좌표는 오른쪽으로 증가, Y 좌표는 아래 방향으 로 증가 – 단위 : 픽셀(pixel) – 단점 : 해상도에 따라 출력되는 내용의 크기가 달라진다. • 예) 프린트 ISLab ICE HUFS MFC Tutorial 201 Mapping Mode의 종류 매핑모드 MM_TEXT MM_LOMETRIC MM_HIMETRIC MM_LOENGLISH MM_HIENGLISH MM_TWIPS MM_ISOTROPIC MM_ANISOTROPIC 단위 픽셀 0.1 mm 0.01 mm 0.1 in 0.01 in 1/1440 in 지정가능 지정가능 X 방향증가 오른쪽 오른쪽 오른쪽 오른쪽 오른쪽 오른쪽 지정가능 지정가능 Y방향증가 아래쪽 위쪽 위쪽 위쪽 위쪽 위쪽 지정가능 지정가능 – MM_ISOTROPIC, MM_ANISOTROPIC 을 이용하여 화면 확대/축소 가능 ISLab ICE HUFS MFC Tutorial 202 MM_TWIPS • 프린터에 가장 많이 사용 • 1 twip은 1/20 포인트에 해당 (1포인트는 1/72 인치에 해 당) • 예 : 12포인트 문자 – 12 X 20 = 240 트윕 ISLab ICE HUFS MFC Tutorial 203 매핑 모드의 변경 • CDC 클래스의 SetMapMode 함수 이용 CClientDC dc(this); dc.SetMapMode(MM_LOMETRIC); dc.TextOut(100, 500, “테스트중입니다.-1”); dc.TextOut(100, -500, “테스트중입니다.-2”); 테스트중입니다.-1 500 윈도우 밖으로 출력되어 보이지 않는다. 500 100 테스트중입니다.-2 ISLab ICE HUFS MFC Tutorial 204 좌표계 • 디바이스(device) 좌표 – 실제 출력 장치의 좌표 • 논리(logical) 좌표 – 출력함수에 사용하는 좌표 • 디바이스 좌표와 논리 좌표간의 변환이 필요 – DPtoLP – LPtoDP ISLab ICE HUFS MFC Tutorial 205 좌표계의 원점 이동 • SetWindowOrg – 논리 좌표의 원점 이동 • SetViewportOrg – 디바이스 좌표의 원점 이동 ISLab ICE HUFS MFC Tutorial 206 CClientDC dc(this); dc.SetMapMode(MM_LOMETRIC); dc.MoveTo(0,0); dc.LineTo(100, -100); (0,0) 1 cm 1 cm ISLab ICE HUFS MFC Tutorial 207 CClientDC dc(this); dc.SetMapMode(MM_LOMETRIC); dc.SetViewportOrg(100,100); // 디바이스 좌표의 원점 이동 dc.MoveTo(0,0); dc.LineTo(100,-100); (0,0) (100,100) 1 cm 1 cm ISLab ICE HUFS MFC Tutorial 208 CClientDC dc(this); dc.SetMapMode(MM_LOMETRIC); dc.SetWindowOrg(100,100); // 윈도우 좌표의 원점 이동 dc.MoveTo(0,0); dc.LineTo(100,-100); 변경된 원점 1 cm (0,0) 1 cm 1 cm 1 cm ISLab ICE HUFS MFC Tutorial 209 좌표계 사이의 좌표 변환 • DPtoLP – 디바이스 좌표를 현재 사용중인 매핑모드에 맞춰 논리 좌표로 변 환 • LPtoDP – 논리 좌표를 현재 사용중인 매핑모드에 맞춰 디바이스 좌표로 변 환 – 예) 마우스 커서의 위치를 논리 좌표로 변환하는 경우 • 마우스 좌표는 디바이스 좌표와 동일한 특성을 갖는다. 즉 윈도우 클 라이언트 영역의 좌측 상단을 기준으로 픽셀 단위의 좌표가 넘어온 다. ISLab ICE HUFS MFC Tutorial 210 단위 길이 계산 • SetWindowExt / GetWindowExt • SetViewportExt / GetViewportExt ISLab ICE HUFS MFC Tutorial 211 CScrollView를 이용한 스크롤 기능 • 스크롤에 관계된 작업이 CScrollView에 이미 구현 • 편집 문서의 크기 결정 – 스크롤 영역 설정의 기능 void CObeditView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: calculate the total size of this view sizeTotal.cx = sizeTotal.cy = 100; SetScrollSizes(MM_TEXT, sizeTotal); } ISLab ICE HUFS MFC Tutorial 212 SetScrollSize • OnInitialUpdate 함수 – 뷰 오브젝트가 생성된 뒤에 바로 호출되는 함수 • SetScrollSize – void CScrollView::SetScrollSize(int nMapMode, SIZE sizeTotal, const SIZE& sizePage, const SIZE& sizeLine); – 편집 문서의 크기, 매핑모드, 스크롤 작업의 크기를 알림 – 스크롤 작업의 크기 • 스크롤 바를 눌렀을 때 얼마나 스크롤할 것인지 그 양을 말함 • 실행 중에 매핑모드에 변경이 생기면 그때마다 SetScrollSize를 호출 하여 변경사항을 반드시 반영해야 함 – sizePage : PageDown을 눌렀을 때. 디폴트 값 = 문서 크기의 1/10 – sizeLine : 스크롤 라인. 디폴트 값 = 문서 크기의 1/100 ISLab ICE HUFS MFC Tutorial 213 문서 크기의 지정 class CObeditDoc : public CDocument { .... public: CObList m_objectList; CSize m_sizeDoc; // 문서의 크기 CSize GetDocumentSize() { return m_sizeDoc; }; .... } CObeditDoc::CObeditDoc() { m_sizeDoc = CSize(500, 500); } void CObeditView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); SetScrollSizes(MM_TEXT, GetDocument()->GetDocumentsSize()); } ISLab ICE HUFS MFC Tutorial 214 스크롤 바 • 문서 영역 • 엄지(thumb) – 현재 뷰가 보여주고 있는 부분이 편집문서에서 어디에 위치한 것 인가 – 현재 보이는 부분이 전체적으로 볼 때 어느 정도의 부분을 차지 하는지 • 비례 스크롤바(proportional scrollbar) ISLab ICE HUFS MFC Tutorial 215 출력 원점의 보정 • 스크롤이 일어나면 편집 문서와 출력함수의 원점이 달라 짐 – SetViewportOrg, SetWindowOrg을 이용하여 두 원점을 하나로 만 듬 – 즉 CDC 클래스의 출력함수에서 사용하는 출력원점을 편집 문서 의 원점으로 이동시킴 – 항상 편집 문서의 원점을 바탕으로 한 좌표를 사용하도록 하면 좌표의 변환없이 문서의 좌표를 그대로 출력에 이용할 수 있음 • 이와 같은 일을 CScrollView가 알아서 한다. ISLab ICE HUFS MFC Tutorial 216 편집문서 500 100 윈도우 500 100 300 300 ISLab ICE HUFS MFC Tutorial 217 마우스 좌표와 논리 좌표의 충돌 마우스가 넘겨주는 좌표 편집문서의 좌표 뷰 전체문서 ISLab ICE HUFS MFC Tutorial 218 LButtonDown void CObeditView::OnLButtonDown(UINT nFlags, CPoint point) { CClientDC dc(NULL); OnPrepareDC(&dc); // 오브젝트의 매핑 모드와 원점을 현재의 스크롤 상태에 // 맞게 변환 // 즉 1. 매핑 모드 변환 // 2. 스크롤 바의 엄지 값을 읽어 그만큼 출력 장치의 // 원점을 뒤로 이동 dc.DPtoLP(&point); // 좌표 단위의 변환 및 원점의 위치까지 고려하여 좌표 // 좌표 변환 수행 // 즉, 마우스 좌표를 편집 문서의 원점으로부터의 // 좌표로 변환 switch(m_wCurDrawObject) { case CDrawObject::objectLine : .......... } ISLab ICE HUFS MFC Tutorial 219 MouseMove void CObeditView::OnMouseMove(UINT nFlags, CPoint point) { if (GetCapture() == this) { CClientDC dc(this); OnPrepareDC(&dc); dc.DPtoLP(&point); dc.SetROP2(R2_NOTXORPEN); m_pCurDrawObject->DrawObject(&dc); m_pCurDrawObject->SetEndPoint(point); m_pCurDrawObject->DrawObject(&dc); } ISLab ICE HUFS MFC Tutorial 220 LButtonUp void CObeditView::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture() == this) { CClientDC dc(this); OnPrepareDC(&dc); dc.DPtoLP(&point); m_pCurDrawObject->SetEndPoint(point); m_pCurDrawObject->DrawObject(&dc); ReleaseCapture(); CObeditDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->m_objectList.AddTail(m_pCurDrawObject); } ISLab ICE HUFS MFC Tutorial 221 View의 화면 출력 과정 • OnDraw에서 OnPrepareDC를 불러야 하나? • WM_PAINT 처리 시 OnPaint 호출 void CView::OnPaint() { CPaintDC dc(this); OnPrepareDC(&dc); OnDraw(&dc); } – 화면 출력 과정을 분리 – OnDraw는 순수 가상 함수(pure virtual function)이다. 그러므로 반드시 하위 클래스에서 작성해야 한다. – OnPrepareDC는 가상 함수(virtual function) – virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo=NULL); ISLab ICE HUFS MFC Tutorial 222 ISLab ICE HUFS 화면 확대/축소 기능 목차 • • • • • 익스텐트(extent)란? 배율 설정 다이얼로그 만들기 DDX/DDV SDK와의 비교 ISLab ICE HUFS MFC Tutorial 224 익스텐트(extent)란 • 특정 매핑 모드에서의 단위 길이 – MM_ISOTROPIC – MM_ANISOTROPIC • 현재 논리 좌표와 디바이스 좌표의 단위 길이를 구하거나 새로 설정 가능 • 논리 좌표와 디바이스 좌표는 단위 길이가 다를 수 있다. • 익스텐트(extent) 조절 GetWindowExt GetViewportExt SetWindowExt SetViewportExt 논리 좌표의 단위 길이 구함 디바이스 좌표의 단위 길이 구함 논리 좌표의 단위 길이 설정 디바이스 좌표의 단위 길이 설정 ISLab ICE HUFS MFC Tutorial 225 간단한 배율 설정 방법 • 배율 : N% CClientDC dc(this); dc.MoveTo(100, 100); dc.LineTo(300, 400); CClientDC dc(this); dc.MoveTo((int)(float)100*N/100, (int)(float)100*N/100); dc.LineTo((int)(float)300*N/100, (int)(float)400*N/100); • 단점 – 실수 연산 시 발생할 수 있는 값의 오차 문제 – 코드의 복잡도 증가 ISLab ICE HUFS MFC Tutorial 226 익스텐트 조절을 통한 배율 • 디바이스좌표 = 논리좌표 X ED / EL – ED : 디바이스 좌표의 단위 길이 – EL : 논리 좌표의 단위 길이 CClientDC dc(this); dc.SetViewportExt(N, N); dc.SetWindowExt(100, 100); // 좌표 X N / 100 dc.MoveTo(100, 100); dc.LineTo(300, 400); ISLab ICE HUFS MFC Tutorial 227 View 수정 • CObeditView 클래스에 멤버 변수로 배율 추가 class CObeditView : public CScrollView { .... UINT m_zoomRatio; .... }; CObeditView::CObeditView() { m_nSelectedColorID = 0; m_crCurColor = color[m_nSelectedColorID]; .... m_zoomRation = 100; // 초기값으로 100% 설정 } ISLab ICE HUFS MFC Tutorial 228 OnPrepareDC 함수 수정 • 클래스 바나 위저드를 이용하여 OnPrepareDC 함수 삽입 void CObeditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { CScrollView::OnPrepareDC(pDC, pInfo); pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetViewportExt(m_zoomRatio, m_zoomRatio); pDC->SetWindowExt(100, 100); } • 익스텐트의 값을 음수로 주면 그림의 방향이 반대가 된다. ISLab ICE HUFS MFC Tutorial 229 다이얼로그 박스 만들기 • 리소스 뷰에서 새로운 다이얼로그 추가 IDD_ZOOMDLG Spin Control의 Properties IDC_EDITZOOM IDC_SPINZOOM ISLab ICE HUFS MFC Tutorial 230 다이얼로그 클래스 생성 • 클래스 위저드 이용 ISLab ICE HUFS MFC Tutorial 231 DDX/DDV ISLab ICE HUFS MFC Tutorial 232 데이타 맵 class CZoomDlg : public CDialog { ...... // Dialog Data //{{AFX_DATA(CZoomDlg) enum { IDD = IDD_ZOOMDLG }; CSpinButtonCtrl m_spinZoom; UINT m_editZoom; //}}AFX_DATA ...... }; ISLab ICE HUFS MFC Tutorial 233 DoDataExchange void CZoomDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CZoomDlg) DDX_Control(pDX, IDC_SPINZOOM, m_spinZoom); DDX_Text(pDX, IDC_EDITZOOM, m_editZoom); DDX_MinMaxUInt(pDX, m_editZoom, 10, 800); //}}AFX_DATA_MAP } OnInitDialog에서 컨트 롤의 값을 설정한다. 다이얼로그박스호출 전에 값을 설정 CDialog 클래스의 데이타맵에 있는 변수 다이얼로그박스의 실행이 정상적으로 끝나면 값을 읽어온다. OnOK에서 컨트롤 의 값을 읽어온다. ISLab ICE HUFS MFC Tutorial 234 UpdateData • UpdateData 함수를 이용하여 DoDataExchange 함수 호 출 – 인자 • TRUE : 컨트롤의 값을 데이타맵의 변수로 읽어옴 • FALSE : 데이타맵의 변수 값을 컨트롤로 설정 ISLab ICE HUFS MFC Tutorial 235 OnInitDialog • WM_INITDIALOG – 클래스 위저드에서 선택 BOOL CZoomDlg::OnInitDialog() { CDialog::OnInitDialog(); m_spinZoom.SetBuddy(GetDlgItem(IDC_EDITZOOM); m_spinZoom.SetRange(10, 500); m_spinZoom.SetBase(10); m_spinZoom.SetPos(m_editZoom); return TRUE; } ISLab ICE HUFS MFC Tutorial 236 CSpinButtonCtrl SetBuddy 스핀 콘트롤이 증감시킨 값을 표시할 윈도우를 지정 이런 윈도우를 버디(buddy) 윈도우라고 함 GetDlgItem 함수를 이용하여 콘트롤 객체의 포인터를 구함 SetRange 스핀 콘트롤로 입력할 수 있는 최대값, 최소값을 지정 SetBase 스핀 콘트롤이 버디 윈도우에 값을 출력할 때 그 값의 형식 16이면 16진수, 10이면 십진수 SetPos 스핀 콘트롤에 표시할 값을 지정 ISLab ICE HUFS MFC Tutorial 237 OnOK • 클래스 위저드를 이용하여 함수 생성 가능 • UpdateData 호출을 해야 한다. – 생성시 UpdateDate(TRUE)를 OK 버튼이 눌려지면 UpdateData(FALSE)를 호출하 여야 하나 이것은 모두 상위 클래스인 CDialog에 만들어져 있으므로 하위 클래스 에서 생성하지 않아도 된다. ISLab ICE HUFS MFC Tutorial 238 배율 메뉴 추가 • 메뉴 ID_VIEW_ZOOM를 처리하는 함수 추가 (CObeditView.cpp) #include “stdafx.h” #include “Obedit.h” ... #include “ZoomDlg.h” void CObeditView::OnViewZoom() { CZoomDlg zoomDlg(this); zoomDlg.m_editZoom = m_zoomRatio; if (zoomDlg.DoModal() != IDOK) return; m_zoomRatio = zoomDlg.m_editZoom; SetZoomFactor(zoomDlg.m_editZoom); Invalidate(); } ISLab ICE HUFS MFC Tutorial 239 SetZoomFactor void CObeditView::SetZoomFactor(UINT zoomFactor) { m_zoomRatio = zoomFactor; CClientDC dc(this); OnPrepareDC(&dc); CSize size = GetDocument()->GetDocumentSize(); dc.LPtoDP(&size); SetScrollSize(MM_TEXT, size); } ISLab ICE HUFS MFC Tutorial 240 Dialog 생성 방법 • 모든 다이얼로그는 CDialog로 부터 계승 • 생성 방법 – Resource view에서 dialog template 생성 – Class Wizard 호출 • Control로부터의 노티피케이션(notification) 메시지 처리 • 각각의 다이얼로그 박스 컨트롤에서 입력되는 값 저장 및 컨트롤에 서의 값을 읽어 오는 데이터 멤버도 만듦 (DDX) • 데이타 값의 범위 지정 가능 (DDV) ISLab ICE HUFS MFC Tutorial 241 Modal/Modeless • Modal – DoModal 함수 호출 • Modeless – Create 함수 호출 – Dialog box를 resource view에서 그릴 때 dialog box의 프로퍼티 로 VISIBLE을 반드시 주어야 한다. ISLab ICE HUFS MFC Tutorial 242 SDK에서의 다이얼로그 생성 방법 IDD_TESTDIALOG IDOK IDCANCEL IDC_NUMBER ISLab ICE HUFS MFC Tutorial 243 class CTestDialog : public CDialog { // Construction public: CTestDialog(CWnd* pParent = NULL); // Dialog Data //{{AFX_DATA(CTestDialog) enum { IDD = IDD_TESTDIALOG }; //}}AFX_DATA WORD m_wInputVal; // Overrides //{{AFX_VIRTUAL(CTestDialog) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CTestDialog) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; ISLab ICE HUFS MFC Tutorial 244 GetDlgItem - 값 설정 BOOL CTestDialog::OnInitDialog() { CDialog::OnInitDialog(); // UpdateDate(FALSE) 호출 CString szStr; szStr.Format(“%d”, m_wInputVal); ((CEdit*)GetDlgItem(IDC_NUMBER))->SetWindowText(szStr); ((CEdit*)GetDlgItem(IDC_NUMBER))->SetFocus(); return FALSE; } • 반드시 cast 연산자 사용 • SetFocus : 윈도우에 입력 포커스 설정 ISLab ICE HUFS MFC Tutorial 245 GetDlgItem - 값 읽기 void CTestDialog::OnOK() { CString szStr; ((CEdit*)GetDlgItem(IDC_NUMBER))->GetWindowText(szStr); m_wInputVal = atoi(szStr); CDialog::OnOK(); // UpdateData(TRUE) 호출 // EndDialog(IDOK) 호출 } ISLab ICE HUFS MFC Tutorial 246 SDK Dialog 사용시 { . . . CTestDialog testDlg(this); testDlg.m_wInputVal = nVal; if (testDlg.DoModal() == IDOK) { nVal = testDlg.m_wInputVal; } } ISLab ICE HUFS MFC Tutorial 247 Modeless Dialog • 지역 변수로 생성하면 않된다. CTestDialog::CTestDialog(CWnd* pParent) : CDialog(CTestDialog::IDD, pParent) { Create(CTestDialog::IDD, pParent); // modeless dialog 생성 } void CObeditView::f() { CTestDialog testDlg(this); } // 지역변수로 만들면 lifetime이 끝나면서 // 사라진다. void CObeditView::g() { CTestDialog* pDlg = new CTestDialog(this); } ISLab ICE HUFS MFC Tutorial 248 모드리스 다이얼로그 생성 Visible 세팅 ISLab ICE HUFS MFC Tutorial 249 DDX/DDV 사용시 ISLab ICE HUFS MFC Tutorial 250 DDX/DDV를 사용한 클래스 정의 class CTestDialog : public CDialog { public: WORD m_nVal; CTestDialog(CWnd* pParent = NULL); //{{AFX_DATA(CTestDialog) enum { IDD = IDD_TESTDIALOG }; UINT m_wNumber; //}}AFX_DATA //{{AFX_VIRTUAL(CTestDialog) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL .... } ISLab ICE HUFS MFC Tutorial 251 DoDataExchange void CTestDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CTestDialog) DDX_TEXT(pDX, IDC_NUMBER, m_wNumber); DDV_MinMaxUInt(pDX, m_wNumber, 50, 200); //}}AFX_DATA_MAP } ISLab ICE HUFS MFC Tutorial 252 DDX/DDV 매크로 DDX_CBIndex, DDX_CBString, DDX_CBStringExact DDX_LBIndex, DDX_LBString, DDX_LBStringExact DDX_Check DDX_Radio DDX_Scroll DDX_Text DDX_Control 콤보 박스 관련 리스트 박스 관련 체크 박스 관련 라디오 박스 관련 스크롤바 관련 에디트 콘트롤 관련 ISLab ICE HUFS MFC Tutorial 253 다이얼로그 클래스 CDialog CCommonDialog CFileDialog CFontDialog CColorDialog CFindReplaceDialog CPrintDialog CPageSetupDialog ISLab ICE HUFS MFC Tutorial 254 배율 설정 기능의 ToolBar로의 적용 • CMainFrame 클래스에 다음 함수 정의 void CMainFrame::SetZoomRange(int nMin, int nMax) { m_wndToolBar.m_zoomScroll.SetScrollRange(nMin, nMax); } void CMainFrame::SetZoomPos(int nPos) { m_wndToolBar.m_zoomScroll.SetScrollPos(nPos); CString szTemp; szTemp.Format(“%d %%”, nPos); m_wndToolBar.m_zoomStatic.SetWindowText(szTemp); } ISLab ICE HUFS MFC Tutorial 255 CObeditView::OnInitialUpdate #include “MainFrm.h” . . . void CObeditView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd(); pFrame->SetZoomRange(10, 800); pFrame->SetZoomPos(m_zoomRatio); SetScrollSize(MM_TEXT, GetDocument()->GetDocumentSize()); } ISLab ICE HUFS MFC Tutorial 256 CObeditView::SetZoomFactor void CObeditView::SetZoomFactor(UINT zoomFactor) { m_zoomRatio = zoomRatio; CClientDC dc(NULL); OnPrepareDC(&dc); CSize size = GetDocument()->GetDocumentSize(); dc.LPtoDP(&size); SetScrollSize(MM_TEXT, size); CMainFrame *pMain = (CMainFrame*)AfxGetMainWnd(); pMain->SetZoomPos(m_zoomRatio); } ISLab ICE HUFS MFC Tutorial 257 WM_HSCROLL 처리 #include “ObeditDoc.h” #include “ObeditView.h” . . . void CMyToolBar::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int nMin, nMax; m_zoomScroll.GetScrollRange(&nMin, &nMax); int nOldPos, nCurPos = m_zoomScroll.GetScrollPos(); nOldPos = nCurPos; switch(nSBCode) { case SB_LEFT : nCurPos = nMin; break; ISLab ICE HUFS MFC Tutorial 258 case SB_RIGHT : nCurPos = nMax; break; case SB_LINELEFT : nCurPos -= 10; break; case SB_LINERIGHT : nCurPos += 10; break; case SB_PAGELEFT : nCurPos -= 50; break; case SB_PAGERIGHT : nCurPos += 50; break; case SB_THUMBTRACK : case SB_THUMBPOSITION : nCurPos = nPos; break; } ISLab ICE HUFS MFC Tutorial 259 if (nCurPos < nMin) nCurPos = nMin; else if (nCurPos > nMax) nCurPos = nMax; if (nOldPos == nCurPos) return; m_zoomScroll.SetScrollPos(nCurPos); CString szTemp; szTemp.Format(“%d %%”, nCurPos); m_zoomStatic.SetWindowText(szTemp); // set zoom ratio to view window CMDIChildWnd* pChildFrame = (CMDIChildWnd *) (((CMDIFrameWnd*)AfxGetMainWnd())->MDIGetActive()); CObeditView* pView = (CObeditView*)pChildFrame->GetActiveView(); pView->SetZoomFactor(nCurPos); pView->Invalidate(); } ISLab ICE HUFS MFC Tutorial 260 마우스 커서의 변환 • SetCursor void CObeditView::OnLButtonDown() { . . . ::SetCapture(AfxGetApp()->LoadCursor(IDC_MYCURSOR1); } // WM_SETCURSOR 메시지 처리 BOOL CObeditView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { ::SetCursor(AfxGetApp()->LoadCursor(IDC_MYCURSOR2); return TRUE; } ISLab ICE HUFS MFC Tutorial 261 ISLab ICE HUFS 기타 Dialog Box 구현 목차 • Owner Draw List Box • Property Sheet ISLab ICE HUFS MFC Tutorial 263 Owner-Draw List Box • • • • • 펜 속성을 선택하는 dialog 각 펜의 모양을 그림으로 list box에 표현 List box의 각 항목을 직접 그려야 함 List box의 각 항목의 순서를 지정할 수 있어야 함 List box에 그릴 각 항목의 크기를 알 수 있어야 함 ISLab ICE HUFS MFC Tutorial 264 펜 속성 지정 다이얼로그 Static. IDC_STATIC Edit Box. IDC_EDITWIDTH Spin. IDC_SPINWIDTH List Box. IDC_LISTSTYLE 비트맵이 들어가기 때문 ISLab ICE HUFS MFC Tutorial 265 CPenAttrDlg • CPenAttrDlg 클래스 생성 • Member Variable - Class Wizard – m_editWidth – m_listStyle – m_spinWidth Value Control Control UINT CListBox CSpinButtonCtrl ISLab ICE HUFS MFC Tutorial 266 CLineStyleListBox 클래스 생성 • CListBox로부터 계승 • Owner-Draw List Box를 위하여 다음 함수를 재정의 – CompareItem • 정렬의 대상이 명확하지 않기 때문에 이를 비교하기 위한 함수 – DrawItem • 리스트 박스의 항목을 그릴 때 각 항목마다 호출되는 함수 – MeasureItem • 항목의 높이를 정하기 위해 각 항목마다 호출되는 함수 ISLab ICE HUFS MFC Tutorial 267 MeasureItem #define COLOR_ITEM_HEIGHT 20 void CLineStyleListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItem) { lpMeasureItem->itemHeight = COLOR_ITEM_HEIGHT; } ISLab ICE HUFS MFC Tutorial 268 DrawItem(1) void CLineStyleListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); int nStyle = (int)lpDrawItemStruct->itemData; if (lpDrawItemStruct->itemAction & ODA_DRAWENTIRE) { CPen Pen(nStyle, 1, RGB(0,0,0)); // 검은 색 펜을 만든다 CPen* pOldPen = pDC->SelectObject(&Pen); int y = lpDrawItemStruct->rcItem.top + (lpDrawItemStruct ->rcItem.bottom + lpDrawItemStruct->rcItem.top)/2); pDC->MoveTo(0, y); pDC->LineTo(lpDrawItemStruct->rcItem.right, y); pDC->SelectObject(pOldPen); } ISLab ICE HUFS MFC Tutorial 269 DrawItem(2) if ((lpDrawItemStruct->itemState & ODS_SELECTED) && (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE))) { // item has been selected - hilite frame pDC->InvertRect(&lpDrawItemStruct->rcItem); } if (!(lpDrawItemStruct->itemState & ODS_SELECTED) && (lpDrawItemStruct->itemAction & ODA_SELECT)) { pDC->InvertRect(&lpDrawItemStruct->rcItem); } } ISLab ICE HUFS MFC Tutorial 270 CompareItem int CLineStyleListBox::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct) { int nStyle1 = (int)lpCompareItemStruct->itemData1; int nStyle2 = (int)lpCompareItemStruct->itemData2; if (nStyle1 == nStyle2) return 0; else if (nStyle1 < nStyle2) return -1; else return 1; } ISLab ICE HUFS MFC Tutorial 271 DRAWITEMSTRUCT typedef UINT UINT UINT UINT struct tagDRAWITEMSTRUCT { CtlType; // Owner-Draw 리스트 박스의 경우에는 ODT_LISTBOX가 들어옴 CtlID; // Control ID가 들어온다. itemID; // List box에서 몇 번째 항목인지를 나타내는 인덱스가 들어옴 itemAction; // 지금 list box에 취해진 작업의 종류를 나타낸다. // ODA_DRAWENTIRE : list box 자체가 다시 그려져야 할 때 // ODA_FOCUS : list box에 포커스가 새로 왔거나 포커스를 잃을 때 // ODA_SELECT : list box의 선택 상태가 변경되었을 때 UINT itemState; // 지금 항목의 상태를 나타낸다. 상태에 따라 그려주는 것이 // 달라지기 때문에 중요하다. Ownerdraw list box의 경우에는 // ODS_DISABLED : 이 항목이 비활성화된 것으로 그려져야 하는 경우 // ODS_FOCUS : 이 항목에 입력 포커스가 있는 것으로 그려져야 할 때 // ODS_SELECTED : 이 항목이 선택된 것으로 그려져야 할 경우 HWND hWnditem; // ownerdraw list box의 window handle HDC hDC; // 이 항목이 그려질 영역에 대한 device context handle // 핸들을 기반으로 존재하는 모든 클래스들은 핸들로부터 클래스 // 오브젝트를 만들어 주는 FromHandle이라는 멤버함수를 가지고 있다. // DrawItem 함수에서는 이 핸들을 CDC 클래스로 변환하여 사용한다. RECT rcItem; // 이 항목의 위치를 나타낸다. 반드시 이 안에만 그려야 함 DWORD itemDate; // 이 항목에 들어간 값을 나타낸다. 보통의 list box라면 // 여기에 텍스트가 들어가게 된다. ISLab ICE HUFS } DRAWITEMSTRUCT; MFC Tutorial 272 리스트 박스에 항목 추가 • InsertString – 절렬 순서에 관계없이 항목을 지정한 곳에 넣는다. • AddString – 정렬한 다음에 리스트 박스에 추가 – CompareItem 함수를 호출하여 정렬하게 된다. • 오너드로인 경우 그 항목을 그릴 때 사용할 수 있는 값을 줌 – 예제에서는 펜의 스타일을 인자로 사용 • 직접 데이타 맵을 수정해야 ISLab ICE HUFS MFC Tutorial 273 Data Map 수정 // PenAttrDlg.h : header file // #include “LineStyleListBox.h” class CPenAttrDlg : public CDialog { // Construction public: int m_lineStyle; // 선의 스타일을 가리키는 변수 CPenAttrDlg(CWnd* pParent = NULL); // Dialog Data //{{AFX_DATA(CPenAttrDlg) enum { IDD = IDD_PENATTRIBUTE; }; CSpinButtonCtrl m_spinWidth; CLineStyleListBox m_listStyle; UINT m_editWidth; //}}AFX_DATA ISLab ICE HUFS MFC Tutorial 274 WM_INITDIALOG BOOL CPenAttrDlg::OnInitDialog() { CDialog::OnInitDialog(); m_spinWidth.SetBuddy(GetDlgItem(IDC_EDITWIDTH)); m_spinWidth.SetRange(1, 20); m_spinWidth.SetBase(10); m_spinWidth.SetPos(m_editWidth); m_listStyle.AddString((LPCTSTR)(PS_SOLID)); m_listStyle.AddString((LPCTSTR)(PS_DASH)); m_listStyle.AddString((LPCTSTR)(PS_DOT)); m_listStyle.AddString((LPCTSTR)(PS_DASHDOT)); m_listStyle.AddString((LPCTSTR)(PS_DASHDOTDOT)); m_listStyle.AddString((LPCTSTR)(PS_NULL)); return TRUE; } ISLab ICE HUFS MFC Tutorial 275 OnOK void CPenAttrDlg::OnOK() { int index = m_listStyle.GetCurSel(); m_lineStyle = (UINT)m_listStyle.GetItemData(index); CDialog::OnOK(); } ISLab ICE HUFS MFC Tutorial 276 메뉴 처리 함수 생성 • ID_OBJECT_PENATTR 명령의 COMMAND 메시지 핸들러 #include “PenAttrDlg.h” . . . void CObeditView::OnObjectPenattr() { CPenAttrDlg penAttrDlg(this); penAttrDlg.m_editWidth = m_nPenWidth; penAttrDlg.m_lineStyle = m_nPenStyle; if (penAttrDlg.DoModal() != IDOK) return; m_nPenWidth = penAttrDlg.m_editWidth; m_nPenStyle = penAttrDlg.m_lineStyle; } ISLab ICE HUFS MFC Tutorial 277 Property Sheet • 여러 개의 Property Page로 하나의 Property Sheet를 생성 ISLab ICE HUFS MFC Tutorial 278 파일 정보 다이얼로그 생성 Static. IDC_APPNAME Edit. IDC_AUTHOR Edit. IDC_KEYWORDS List Box. IDC_COMMENTS Edit. IDC_TITLE Edit. IDC_SUBJECT IDD_SUMM_PAGE ISLab ICE HUFS MFC Tutorial 279 Dialog Properties ISLab ICE HUFS MFC Tutorial 280 CSummaryPage 클래스 생성 • 상위 클래스로 CPropertyPage 선택 • Member Variables (Class Wizard) – – – – – – IDC_APPNAME IDC_AUTHOR IDC_COMMENTS IDC_KEYWORDS IDC_SUBJECT IDC_TITLE m_AppName m_Author m_Comments m_Keywords m_Subject m_Title Value Value Value Value Value Value CString CString CString CString CString CString ISLab ICE HUFS MFC Tutorial 281 파일 통계 다이얼로그 IDC_REVNUM IDC_EDITTIME IDC_CREATEDATE IDC_LASTPRINT IDC_LASTSAVE ISLab ICE HUFS MFC Tutorial 282 CFileStatPage 클래스 생성 • 상위 클래스로 CPropertyPage 선택 • Member Variables (Class Wizard) – – – – – IDC_CREATEDATE m_CreateDate Value IDC_EDITTIME m_EditTime IDC_LASTPRINT m_LastPrint IDC_LASTSAVE m_LastSave IDC_REVNUM m_RevNum CString Value Value Value Value CString CString CString CString ISLab ICE HUFS MFC Tutorial 283 Document 클래스에 멤버 추가 class CObeditDoc : public CDocument { . . . public: CString m_AppName; CString m_Author; CString m_Comments; CString m_Keywords; CString m_Subject; CString m_Title; CString UINT CString CString UINT CTime . . . m_CreateDate; m_EditTime; m_LastPrint; m_LastSave; m_RevNum; m_StartTime; ISLab ICE HUFS MFC Tutorial 284 생성자 CObeditDoc::CObeditDoc() { m_sizeDoc = CSize(500, 500); m_AppName = _T(“도형편집기”); // 유니코드 혹은 ANSI 문자열 } ISLab ICE HUFS MFC Tutorial 285 OnNewDocument BOOL CObeditDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; m_EditTime = 0; m_RevNum = 0; char szTemp[32]; _strdate(szTemp); m_CreateDate = szTemp; m_CreateDate += “ “; _strtime(szTemp); m_CreateDate += szTemp; m_StartTime = CTime::GetCurrentTime(); return TRUE; } ISLab ICE HUFS MFC Tutorial 286 Property Sheet 생성 • CPropertySheet – 하나 이상의 Property Page로 구성 – 각 PropertyPage 객체를 AddPage 함수를 이용하여 등록 ISLab ICE HUFS MFC Tutorial 287 ID_FILE_SUMMARY_INFO #include “FileStatPage.h” #include “SummaryPage.h” . . . void CObeditView::OnFileSummaryInfo() { CPropertySheet sheet(_T(“문서정보”)); CSummaryPage sum; CFileStatPage state; sheet.AddPage(&sum); sheet.AddPage(&state); sum.m_AppName = GetDocument()->m_AppName; sum.m_Author = GetDocument()->m_Author; sum.m_Comments = GetDocument()->m_Comments; sum.m_Keywords = GetDocument()->m_Keywords; sum.m_Subject = GetDocument()->m_Subject; sum.m_Title = GetDocument()->m_Title; ISLab ICE HUFS MFC Tutorial 288 state.m_CreateDate = GetDocument()->m_CreateDate; state.m_EditTime.Format(“%d”, GetDocument()->m_EditTime); state.m_LastPrint = GetDocument()->m_LastPrint; state.m_LastSave = GetDocument()->m_LastSave; state.m_RevNum.Format(“%d”, GetDocument()->m_RevNum); if (sheet.DoModal() != IDOK) return; GetDocument()->m_AppName = sum.m_AppName; GetDocument()->m_Author = sum.m_Author; GetDocument()->m_Comments = sum.m_Comments; GetDocument()->m_Keywords = sum.m_Keywords; GetDocument()->m_Subject = sum.m_Subject; GetDocument()->m_Title = sum.m_Title; } ISLab ICE HUFS MFC Tutorial 289 CProperySheet 클래스 • 보통의 윈도우임 • 일반적인 다이얼로그처럼 사용 – DoModal – Create • Style CObject – Child – Thin – More Styles - Disabled CCmdTarget CWnd CPropertySheet ISLab ICE HUFS MFC Tutorial 290 CProperSheet 클래스 멤버 함수 • • • • AddPage RemovePage GetPageCount SetActivePage – 특정 페이지를 전면으로 – CPropertyPage* pPropPage = GetPage(0); • OnCreate – 프라퍼티시트에 다른 콘트롤을 달때 – MoveWindow : 프로퍼티시트의 크기 확대시 – GetWindowRect : 현재 윈도우의 크기와 위치를 알고자 할때 ISLab ICE HUFS MFC Tutorial 291 적용 버튼 활성화 • CPropertyPage::SetModified(TRUE) – 적용 버튼이 활성화된다. • 적용 버튼에 대한 핸들러 작성 – 적용 버튼의 컨트롤 ID : ID_APPLY_NOW – COMMAND 메시지 핸들러 작성 – 직접 메시지맵을 수정해야 BEGIN_MESSAGE_MAP(CMyPropertySheet, CPropertySheet) //{{AFX_DATA(CMyPropertySheet) ON_COMMAND(ID_APPLY_NOW, OnApplyNow) //}}AFX_MSG_MAP END_MESSAGE_MAP() ISLab ICE HUFS MFC Tutorial 292 적용 처리 함수 class CMyPropertySheet : public CPropertySheet { public: DECLARE_DYNAMIC(CMyPropertySheet) .... // Message Handlers protected: //{{AFX_MSG(CMyPropertySheet) afx_msg void OnApplyNow(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; void CMyPropertySheet::OnApplyNow() { Default(); .... // 리턴하기 전에 프로퍼티시트를 구성하는 각 페이지마다 // SetModified(FALSE)를 호출해야 } ISLab ICE HUFS MFC Tutorial 293 Wizard 모드 • SetWizardMode • SetWizardButton • SetFinishText – Finish 버튼에 나타나는 타이틀을 변경하고자 할 때 ISLab ICE HUFS MFC Tutorial 294 SetWizardMode void CObeditView::OnFileSummaryInfo() { CPropertySheet sheet(_T("문서정보")); CSummaryPage sum; CFileStatPage state; sheet.AddPage(&sum); sheet.AddPage(&state); sheet.SetWizardMode(); sum.m_AppName = GetDocument()->m_AppName; sum.m_Author = GetDocument()->m_Author; sum.m_Comments = GetDocument()->m_Comments; ISLab ICE HUFS MFC Tutorial 295 SetWizardButton PSWIZB_BACK PSWIZB_NEXT PSWIZB_FINISH PSWIZB_DISABLEDFINISH 뒤로 다음 종료 종료 버튼을 버튼을 버튼을 버튼을 활성화한다. 활성화한다. 활성화한다. disable한다. BOOL CMyPropertyPage::OnSetActive() // virtual function { CPropertySheet* pSheet = (CPropertySheet*)GetParent(); pSheet->SetWizardButton( PSWIZB_NEXT ); return CPropertySheet::OnSetActive(); } ISLab ICE HUFS MFC Tutorial 296 ISLab ICE HUFS 파일 I/O 기능의 추가 목차 • • • • MFC의 파일 I/O 구조 문서 변경 여부 CFile, CArchive Serialize ISLab ICE HUFS MFC Tutorial 298 MFC의 파일 I/O 구조 • CWinApp, CDocument 클래스에서 미리 일반화시켜 놓았 다. • 사용자는 필요한 부분의 가상 함수만 제공 New Open Close Save Save As CWinApp::OnFileNew CWinApp::OnFileOpen CDocument::OnFileClose CDocument::OnFileSave CDocument::OnFileSaveAs • New, Open도 실제로는 CDocument 클래스 내에 정의된 부분을 호출 ISLab ICE HUFS MFC Tutorial 299 OnFileNew • MDI 프로그램의 경우라면 -> MDI 자식윈도우 클래스와 뷰 클래스의 오브젝트를 만든다. • SDI 프로그램의 경우라면 -> 이미 만들어져 있는 뷰를 그 대로 사용한다. • 다음으로 문서클래스의 오브젝트를 생성한다. • 그리고 나서 문서클래스(CDocument 클래스)의 OnNewDocument 멤버함수를 호출한다. • 뷰클래스의 OnInitialUpdate 함수를 호출한다. ISLab ICE HUFS MFC Tutorial 300 OnFileOpen • 읽어 들일 파일 이름을 입력받기 위한 파일 열기 다이얼 로그 박스를 띄운다. • MDI 프로그램의 경우라면 -> MDI 자식윈도우 클래스의 오브젝트와 뷰클래스의 오브젝트를 만든다. • SDI 프로그램의 경우라면 -> 이미 만들어져 있는 뷰를 그 대로 사용한다. • 다음으로 문서클래스의 오브젝트를 생성한다. • 파일의 내용을 읽어들이기 위해 문서클래스의 OnOpenDocument 멤버함수를 호출한다. • 뷰클래스의 OnInitialUpdate 함수를 호출한다. ISLab ICE HUFS MFC Tutorial 301 파일 열기 다이얼로그 박스 ISLab ICE HUFS MFC Tutorial 302 OnFileClose • 현재 문서가 저장되지 않았으면(IsModified 함수 호출) 저장 여부를 묻는 메시지박스를 띄운다. 저장하겠다고 하 면 파일 이름이 있는 경우, 문서클래스의 OnSaveDocument 함수를 불러 저장 • 저장하겠다고 했지만 파일 이름이 없는 경우, 파일 이름 을 입력받기 위한 다이얼로그 박스를 띄워 이름을 입력받 아 저장한다(역시 OnSaveDocument 호출) • 문서 클래스의 OnCloseDocument 함수를 불러 이 문서 와 관련된 청소 작업을 한다. ISLab ICE HUFS MFC Tutorial 303 OnCloseDocument • 현재 편집중이던 문서와 관련된 자료 구조 등을 정리하는 작업과 윈도우 등을 닫는 작업을 수행한다. • 자료 구조를 정리하기 위해 문서클래스의 DeleteContents 함수를 호출한다. ISLab ICE HUFS MFC Tutorial 304 문서 변경 여부 • SetModifiedFlag – 문서가 변경되는 지점에서 SetModifiedFlag() 함수 호출 • IsModified – 문서가 변경되었는지를 알아내는 함수. 이전에 SetModifiedFlag 함수를 불렀다면 TRUE가 아니면 FALSE가 반환된다. – 파일을 저장하면 이 플래그는 다시 FALSE로 바뀐다. ISLab ICE HUFS MFC Tutorial 305 OnFileSave • 편집중인 문서의 파일 이름이 있으면 문서클래스의 OnSaveDocument 함수를 불러 저장 • 편집중인 문서의 파일 이름이 없으면 파일 이름을 입력받 기 위한 다이얼로그 박스를 띄워 이름을 입력받아 저장 (역시 OnSaveDocument 호출) ISLab ICE HUFS MFC Tutorial 306 OnFileSaveAs • 파일 이름을 입력받기 위한 다이얼로그 박스를 띄운다. • 이름이 입력되면 OnSaveDocument 함수를 불러 문서 의 내용을 저장한다. ISLab ICE HUFS MFC Tutorial 307 CFile, CArchive CFile file; // CFile 클래스의 file 오브젝트를 정의한다. file.Open( “sample”, CFile::modeRead ); // 파일을 오픈한다. DeleteContents(); // 지금까지 편집중이던 이전 문서의 내용을 삭제 CArchive archive(&file, CArchive::loadArchive); // file 오브젝트를 대신 // 하는 CArchive 클래스의 archive 오브젝트를 // 생성한다. Serialize(archive); // 파일의 내용을 읽어들인다. archive.Close(); // 파일 입출력을 대행하던 archive를 닫는다. file.Close(); // 파일을 닫는다. ISLab ICE HUFS MFC Tutorial 308 CArchive • 저장될 대상과 실제 저장 매체(storage medium) 사이의 매개체 역할을 수행 • 저장 매체의 특성에 관계없이 CArchive 클래스의 멤버 함 수만을 이용하여 입출력 – 파일, 소켓, OLE 파일 저장대상이 되는 자료구조나 전송대상이 되는 자료구조 CArchive 클래스 네트웍 ISLab ICE HUFS MFC Tutorial 309 CArchive 클래스의 멤버 함수 >> operator BYTE, WORD, LONG, DWORD, float, double과 같은 일반수형과 Cobject로부터 계승된 클래스의 읽기 담당 << operator BYTE, WORD, LONG, DWORD, float, double과 같은 일반수형과 Cobject로부터 계승된 클래스의 저장 담당 Read 이진 데이터를 읽어들인다. Write 이진 데이터를 저장한다. WriteString 한 줄의 문자열을 저장한다. ReadString 한 줄의 문자열을 읽어들인다. GetFile CArchive 클래스의 오브젝트가 대신하고 있는 CFile 오브젝트의 포인터를 돌려준다 IsLoading CArchive 클래스의 오브젝트를 읽기 작업을 위해 오픈한 경우에는 TRUE가 리턴 IsWritingCArchive 클래스의 오브젝트를 저장 작업을 위해 오픈한 경우에는 TRUE가 리턴 ISLab ICE HUFS MFC Tutorial 310 Serialize void CObeditDoc::Serialize(CArchive& ar) { if (ar.IsLoading()) { // TODO: add storing code here } else { // TODO: add loading code here } } ISLab ICE HUFS MFC Tutorial 311 직렬화(serialization) • 디스크에 저장하거나 읽는 작업 • 디스크에 저장할 때는 순서대로 데이터를 저장해야 하므 로 직렬화라는 이름을 붙임 • Linked list의 멤버 함수에도 Serialize 함수가 있음. – 이것은 각 노드에 있는 객체의 Serialize 함수를 불러준다. ISLab ICE HUFS MFC Tutorial 312 CObeditDoc::Serialize(1) .... #include #include #include #include .... “stdafx.h” “Obedit.h” “ObeditDoc.h” “DrawObj.h” void CObeditDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { CTime curTime = CTime::GetCurrentTime(); m_LastSave = curTime.Format("%m/%d/%y %H:%M:%S"); CTimeSpan elapsedTime = curTime - m_StartTime; m_EditTime += elapsedTime.GetTotalSeconds(); m_StartTime = curTime; ISLab ICE HUFS MFC Tutorial 313 CObeditDoc::Serialize(2) m_RevNum++; m_StartTime = CTime::GetCurrentTime(); ar ar ar ar ar ar << << << << << << m_AppName; m_Author; m_Comments; m_Keywords; m_Subject; m_Title; ar ar ar ar ar << << << << << m_CreateDate; m_EditTime; m_LastPrint; m_LastSave; m_RevNum; ar ar ar ar ar ar ar ar ar ar ar ar << m_sizeDoc; } else { >> >> >> >> >> >> >> >> >> >> >> m_AppName; m_Author; m_Comments; m_Keywords; m_Subject; m_Title; m_CreateDate; m_EditTime; m_LastPrint; m_LastSave; m_RevNum; ar >> m_sizeDoc; } m_objectList.Serialize(ar); } ISLab ICE HUFS MFC Tutorial 314 CLine::Serialize void CLine::Serialize(CArchive& ar) { CDrawObject::Serialize(ar); if (ar.IsLoading()) { } else { } } ISLab ICE HUFS MFC Tutorial 315 CDrawObject::Serialize void CDrawObject::Serialize(CArchive& ar) { CObject::Serialize(ar); if (ar.IsStoring()) { ar << m_wObjType; ar << m_crColor; ar << m_nPenStyle; ar << m_nPenWidth; ar << m_rcRect; } else { ar >> m_wObjType; ar >> m_crColor; ar >> m_nPenStyle; ar >> m_nPenWidth; ar >> m_rcRect; } } ISLab ICE HUFS MFC Tutorial 316 CObject::Serialize • 호출하지 않으면 파일 입출력이 제대로 동작 안함 • CObject 클래스에 관한 정보를 저장하고 읽어들이는 기 능 • 이 정보를 바탕으로 도형클래스를 따로 생성하지 않아도 자동으로 도형클래스를 생성하고 있다. ISLab ICE HUFS MFC Tutorial 317 Serialize 함수 호출 순서 CDocument의 Serialize 함수 도형리스트의 Serialize 함수호출 (m_objectList.Serialize) 일단 프로그램 전체에 걸친 정 보를 입출력 한 다 도형별로 Serialize 함수를 호출 ISLab ICE HUFS MFC Tutorial 318 SetModifiedFlag ISLab ICE HUFS MFC Tutorial 319 SetModifiedFlag 추가 void CObeditView::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture() == this) { CClientDC dc(this); OnPrepareDC(&dc); dc.DPtoLP(&point); m_pCurDrawObject->SetEndPoint(point); m_pCurDrawObject->DrawObject(&dc); ReleaseCapture(); CObeditDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->m_objectList.AddTail(m_pCurDrawObject); pDoc->SetModifiedFlag(TRUE); } } ISLab ICE HUFS MFC Tutorial 320 DeleteContents void CObeditDoc::DeleteContents() { while(!m_objectList.IsEmpty()) { delete m_objectList.RemoveHead(); } CDocument::DeleteContents(); } ISLab ICE HUFS MFC Tutorial 321 CArchive 클래스 연산자 <<, >>가 가능한 타입 • • • • • • CObject에 대한 포인터 CString SIZE, CSize, POINT, CPoint, RECT, CRect CTime, CTimeSpan float, double BYTE, WORD, DWORD, LONG • CObject 포인터가 아닌 일반 객체는 Serialize 함수를 호 출하여 입출력해야 한다. ISLab ICE HUFS MFC Tutorial 322 ISLab ICE HUFS 프린터 관련 명령 목차 • MFC의 프린트 구조 • MFC에서의 미리보기 구조 ISLab ICE HUFS MFC Tutorial 324 MFC에서의 프린터 • 관련 메뉴 – Print, Print Setup, Print Preview • CPrintDialog ISLab ICE HUFS MFC Tutorial 325 프린트 관련 메뉴 메뉴 Print Print Setup Print Preview 기능 프린터로 인쇄 프린터의 환경 설정 프린터 출력을 화면 으로 처리함수 이름 및 정의 위치 OnFilePrint(CView) OnFilePrintSetup(CWinApp) OnFilePrintPreview(CView) ISLab ICE HUFS MFC Tutorial 326 화면과 프린터출력의 비교 • 거의 모든 함수가 표준화되어 있다. – 화면 출력에도 사용하는 그래픽 디바이스에 관계없이 단일한 하 나의 함수 집합(GDI, Graphic Device Interface)을 이용할 수 있다. - CDC 클래스 – 그외 • ODBC(Open Database Connectivity) • MCI(Media Control Interface) – 프린터 출력시에도 CDC 클래스를 이용하여 출력 • 차이점 – 여러 장의 종이에 출력 – 출력 상태 표시 ISLab ICE HUFS MFC Tutorial 327 프린터 작업시 뷰클래스가 해야 하는 일 • 최대 몇페이지나 출력할 수 있는지, 어느 페이지서부터 어느 페이지까지 출력할 것인지를 결정 - 프린터 다이얼 로그 박스를 띄워 선택을 입력받는다. • 특정 페이지를 출력하도록 요구받았을 때 그 부분을 그릴 수 있어야 한다. 필요하다면 머리말과 꼬리말을 출력할 수 있어야 한다. • 출력에 필요한 폰트와 다른 GDI 자원들을 할당하고 제거 할 수 있어야 한다. • 프린터 다이얼로그를 띄워 프린터 DC를 구함 • 일반적인 코딩은 가상함수로 제공 ISLab ICE HUFS MFC Tutorial 328 CView::OnFilePrint CView::OnPreparePrinting CView::OnBeginPrinting 출력문서의 페이지 수를 결정해 준다. 다음으로 DoPreparePrinting 함수를 호출하여 프린트 다이 얼로그박스를 표시하고 DC를 생성한다. 프린트 작업동안 필요한 각종 리소스를 할당한다. CDC::StartDoc 프린트 작업이 시작됨을 프린터에 알린다. CView::OnPrepareDC CDC::StartPage CView::OnPrint 프린트와 관계된 여러가지 DC의 속성들을 바꾸어준다. 더 출력할 페이지가 있는지 검사한다. 프린트 디바이스 쪽에 새 페이지의 출력이 시작되었음을 알린다. 머릿말과 꼬릿말이 있으면 출력하고 지정된 페이지를 출력한다. CDC::EndPage 페이지의 출력이 끝났음을 알린다. CDC::EndDoc 문서 전체의 출력이 끝났음을 알린다. CView::OnEndPrinting OnBeginPrinting에서 할당했던 리소스들을 제거한다. ISLab ICE HUFS MFC Tutorial 329 MFC의 프린트 기능의 구현 • 뷰클래스의 다음 함수의 구현을 어떻게 만드느냐에 달림 – – – – – OnPreparePrinting OnBeginPrinting OnEndPrinting OnPrepareDC OnPrint • 프린트 다이얼로그를 띄우고 프린트 DC를 만들고 프린트 취소 다이얼로그를 띄우고 하는 일은 MFC가 알아서 수행 ISLab ICE HUFS MFC Tutorial 330 프린트 제어를 위한 CDC 클래스의 함수 • Escape Sequence 함수 • StartDoc – 새로운 문서의 출력이 나감을 알린다. • StartPage – 새로운 페이지의 출력이 나감을 알린다. • EndPage – 페이지의 출력이 끝났음을 알린다. • EndDoc – 문서의 출력이 종료되었음을 알린다. ISLab ICE HUFS MFC Tutorial 331 CPrintInfo(1) • OnPreparePrinting 함수의 인자로 넘어옴 • 프린터와 관련한 사용자의 입력을 저장하거나 프린트, 미 리보기 관련 정보를 보관 • 예 – 프린트 할 페이지의 범위 – 현재 프린트하고 있는 페이지의 번호 – 출력용지의 크기 등 ISLab ICE HUFS MFC Tutorial 332 CPrintInfo(2) struct CPrintInfo // Printing information structure { CPrintInfo(); ~CPrintInfo(); CPrintDialog* m_pDD; // 여기에 프린트 공통 다이얼로그의 포인터를 보관 BOOL m_bPreview; // 미리보기상태(TRUE)인지 프린트상태(FALSE)인지 표시 BOOL m_bContinuePrinting; // 프린트를 계속할 것인지의 여부를 표시 UINT m_nCurPage; // 현재 인쇄중이거나 미리보기중인 페이지 UINT m_nNumPreviewPages; // 동시에 미리보기하려는 페이지 수 CString m_strPageDesc; // 페이지번호를 표시하기위한 포맷 스트링 LPVOID m_lpUserData; // pointer to user created struct CRect m_rectDraw; // 인쇄할 종이의 크기 void void UINT UINT UINT UINT SetMinPage(UINT nMinPage); SetMaxPage(UINT nMaxPage); GetMinPage() const; GetMaxPage() const; GetFromPage() const; GetToPage() const; // 출력가능한 페이지의 범위 // 사용자가 입력한 출력 페이지의 // 범위 }; ISLab ICE HUFS MFC Tutorial 333 OnPrint의 디폴트 코딩 void CView::OnPrint(CDC* pDC, CPrintInfo*) { ASSERT_VALID(pDC); // Override and set printing variables based on page number OnDraw(pDC); // Call Draw } • 페이지의 개념이 없음 • OnDraw를 조금 수정하여 프린트에도 적용 • OnPrint호출 전에 OnPrepareDC를 먼저 호출한다. – 윈도우 매핑모드 변경 – CScrollView의 경우 : 스크롤 상황에 맞추어 원점을 이동 ISLab ICE HUFS MFC Tutorial 334 View 클래스 수정 • 출력이 나가는 종이의 높이 지정 class CObeditView : public CScrollView { ... int m_nPaperHeight; ... }; ISLab ICE HUFS MFC Tutorial 335 OnPreparePrinting BOOL CObeditView::OnPreparePrinting(CPrintInfo* pInfo) { pInfo->m_nNumPreviewPages = 1; // 미리보기 할 페이지 수를 1로 정함 return DoPreparePrinting(pInfo); } • 사용자가 출력 용지를 설정하기 전까지는 몇 페이지에 걸 쳐 출력이 일어날지 모름 • 워드 프로세서의 경우 미리 출력 용지를 결정하므로 pInfo->SetMaxPage 함수를 호출하여 출력할 페이지 를 결정할 수 있음 ISLab ICE HUFS MFC Tutorial 336 OnBeginPrinting(1) void CObeditView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo) { m_nPaperHeight = pDC->GetDeviceCaps(VERTRES); CSize docSize = GetDocument()->GetDocumentSize(); int nMaxPage = max(1,(docSize.cy+m_nPaperHeight-1)/m_nPaperHeight)); pInfo->SetMaxPage(nMaxPage); } ISLab ICE HUFS MFC Tutorial 337 OnBeginPrinting(2) • CDC::SetDeviceCaps 함수를 이용하여 출력 용지의 높이 를 구함 • 프린트 중에 사용할 GDI 리소스(펜, 폰트, 브러쉬등)를 할당해 두는 일을 하는 곳 – 페이지 출력시마다 리소스 할당을 하지 않기 위해 – 즉, 프린트 작업에 들어가기에 앞서 전체적으로 필요한 GDI 리소 스를 할당 – OnEndPrinting에서 이 리소스들을 제거 ISLab ICE HUFS MFC Tutorial 338 GetDeviceCaps의 인자 HORZRES VERTRES HORSIZE VERTSIZE LOGPIXELSX LOGPIXELSY NUMCOLORS TECHNOLOGY 현재 선택된 출력용지의 폭을 픽셀 단위로 알고자 할 때 현재 선택된 출력용지의 높이를 픽셀 단위로 알고자 할 때 현재 선택된 출력용지의 폭을 밀리미터 단위로 알고자 할 때 현재 선택된 출력용지의 높이를 밀리미터 단위로 알고자 할때 현재 프린터의 수평방향의 DPI(Dot Per Inch)를 알고자 할 때 현재 프린터의 수직방향의 DPI(Dot Per Inch)를 알고자 할 때 프린터가 지원하는 색상의 수를 리턴한다. 흑백이면 2 현재 디바이스컨텍스트가 나타내는 출력장치가 무엇인지를 돌려준다. 예로 프린터의 경우에는 DT_RASPRINTER가 리턴될 것이다. DT_PLOTTER : 백터 플로터 DT_RASDISPLAY : 래스터 디스플레이 DT_RASPRINTER : 래스터 프린터 DT_RASCAMERA : 래스터 카메라 .... ISLab ICE HUFS MFC Tutorial 339 OnEndPrinting • 본 예제에서는 할당한 리소스들이 없으므로 OnEndPrinting에서 할 일이 없음 void CObeditView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { } ISLab ICE HUFS MFC Tutorial 340 OnPrepareDC 함수의 수정 void CObeditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { if (pInfo == NULL) { CScrollView::OnPrepareDC(pDC, pInfo); pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetViewportExt(m_zoomRatio, m_zoomRatio); pDC->SetWindowExt(100, 100); } else { pDC->SetViewportOrg(0, -(pInfo->m_nCurPage-1)*m_nPaperHeight); } } ISLab ICE HUFS MFC Tutorial 341 OnPrepareDC에서의 주의점 • 인자로 넘어오는 CDC 클래스의 오브젝트에 대한 포인터 에 대하여 출력을 할 경우 – 윈도우 출력의 경우 : 출력이 나감 – 프린터 출력의 경우 : 출력이 안 나감 – 프린터 출력시에는 OnPrepareDC의 호출이 끝난 다음에야 새 페 이지의 출력을 프린터 드라이버에 알리는 CDC::StartPage를 호출 하기 때문. 그 전에 호출한 것은 아무런 소용이 없다. • 두번째 인자 pInfo – NULL : 화면 출력 – NULL이 아님 : 프린트 출력. 이때 프린트 쪽의 원점을 뒤로 이동 하여 다음 페이지 출력 – pInfo->m_nCurPage : 현재 출력이 나갈 페이지의 번호를 가리킴 ISLab ICE HUFS MFC Tutorial 342 SetViewportOrg를 이용한 페이지의 출력 전체 편집문서 1. N 페이지만 프린트로 출력이 나가야한다. 2. 출력원점의 보정없이 OnDraw를 호출하면 항상 1 페이지가 출력된다. 종이의 원점에 전체편집문서의 원점이 바로 대응 되기 때문이다. 3. 종이의 출력원점을 전체편집문서의 원점과 맞추어주기위해 그만큼 뒤로 이동하고 OnDraw를 호출한다. 그러면 1페이지부터 N-1 페이지까지의 출력은 종이밖으로 출력되기 때문에 무시된다. 1 페이지 N 페이지 출력용지 ISLab ICE HUFS MFC Tutorial 343 편집 문서의 수정 • 출력 용지를 늘리기위해 CObeditDoc::CObeditDoc() { m_sizeDoc = CSize(1500, 5000); m_AppName = _T(“도형편집기”); } ISLab ICE HUFS MFC Tutorial 344 Mapping Mode 변경 • MM_TEXT로 출력시 출력 결과가 너무 작고, 프린터 기종 마다 크기가 다르므로 void CObeditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { if (pInfo == NULL) { CScrollView::OnPrepareDC(pDC, pInfo); pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetViewportExt(m_zoomRatio, m_zoomRatio); pDC->SetWindowExt(100, 100); } else { pDC->SetMapMode(MM_LOMETRIC); pDC->SetViewportOrg(0, -(pInfo->m_nCurPage-1)*m_nPaperHeight); } } ISLab ICE HUFS MFC Tutorial 345 출력 용지 페이지 수 계산 void CObeditView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo) { m_nPaperHeight = pDC->GetDeviceCaps(VERTRES); OnPrepareDC(pDC, pInfo); CPoint pt(m_nPaperHeight, m_nPaperHeight); pDC->DPtoLP(&pt); CSize docSize = GetDocument()->GetDocumentSize(); int nMaxPage = max(1, (docSize.cy + pt.y - 1) / pt.y); pInfo->SetMaxPage(nMaxPage); } • GetDiviceCaps(VERTSIZE)를 호출하면 1 밀리미터 단위의 값이 넘 어옴. MM_LOMETRIC은 0.1 밀미미터 단위의 값임 – 오차가 크므로 픽셀 단위의 값을 구한 다음 DPtoLP를 이용하여 오차를 없앰 ISLab ICE HUFS MFC Tutorial 346 프린터로 아무것도 출력이 안되는 이유 +Y -X +X 출력원점 -Y 출력용지 ISLab ICE HUFS MFC Tutorial 347 OnPrepareDC의 수정 void CObeditView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { if (pInfo == NULL) { CScrollView::OnPrepareDC(pDC, pInfo); pDC->SetMapMode(MM_ANISOTROPIC); pDC->SetViewportExt(m_zoomRatio, m_zoomRatio); pDC->SetWindowExt(100, 100); } else { pDC->SetMapMode(MM_LOMETRIC); pDC->SetMapMode(MM_ANISOTROPIC); CSize size = pDC->GetViewportExt(); pDC->SetViewportExt(size.cx, -size.cy); // 반대방향으로 뒤집음 pDC->SetViewportOrg(0, -(pInfo->m_nCurPage-1)*m_nPaperHeight); } } ISLab ICE HUFS MFC Tutorial 348 MFC에서의 미리보기 구조 • MFC에서는 기본적인 프린터 출력루틴만 제대로 만들어 졌다면 미리보기는 자연스럽게 구현이 된다. • 차이점 – 미리보기는 윈도우로 출력되기 때문에 프린터 출력과는 달리 WM_PAINT를 처리할 수 있어야 한다. – 사용자의 입력을 기다렸다가 페이지를 출력한다. • CPreviewDC – 두개의 DC를 사용 • 프린터 DC를 흉내낸 DC • 출력이 실제로 표시되는 윈도우를 나타내는 DC ISLab ICE HUFS MFC Tutorial 349 CPreviewView 클래스 • CPreviewView 클래스 – 메인 프레임의 자식 윈도우로 존재 • CPrintInfo의 m_bPreview가 TRUE이면 미리보기 중 ISLab ICE HUFS MFC Tutorial 350 미리보기 창에 출력 void CObeditView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo) { m_nPaperHeight = pDC->GetDeviceCaps(VERTRES); OnPrepareDC(pDC, pInfo); CPoint pt(m_nPaperHeight, m_nPaperHeight); pDC->DPtoLP(&pt); CSize docSize = GetDocument()->GetDocumentSize(); int nMaxPage = max(1, (docSize.cy + pt.x - 1)/pt.x); pInfo->SetMaxPage(nMaxPage); 분리자 두 페이지 모드일 때 나갈 문자열 CString tempString; tempString.Format("총 %d 페이지 중 %%d 페이지\n총 %d 페이지 중 %%d-%%d 페이 지",nMaxPage, nMaxPage); pInfo->m_strPageDesc = tempString; } 한 페이지 모드일 때 나갈 문자열 ISLab ICE HUFS MFC Tutorial 351 ISLab ICE HUFS 분리 윈도우 목차 • 분리 윈도우 • 동적 분리 윈도우 • 정적 분리 윈도우 ISLab ICE HUFS MFC Tutorial 353 정적 동적 분리 윈도우(1) 동적 분리 윈도우 정적 분리 윈도우 ISLab ICE HUFS MFC Tutorial 354 정적 동적 분리 윈도우(2) ISLab ICE HUFS MFC Tutorial 355 분리 윈도우의 구현 • CSplitterWnd 클래스를 이용 – 다음 클래스의 member data로 존재 • CFrameWnd • CMDIChildWnd ISLab ICE HUFS MFC Tutorial 356 동적 분리 윈도우의 구현 class CChildWnd : public CMDIChildWnd { DECLARE_DYNCREATE(CChildFrame) public: CChildFrame(); // Attributes public: CSplitterWnd m_wndSplitter; // Operations public: // Overrides // ClassWizard generated virtual function overrides // {{AFX_VIRTUAL(CChildFrame) virtual BOOL PreCreateWindow(CREATESTRUCT& cs); .... ISLab ICE HUFS MFC Tutorial 357 자식 윈도우 생성시 • 최대 4개의 동적 분리 윈도우 생성 가능 BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { return m_wndSplitter.Create(this, 2, 2, CSize(10, 10), pContext); } 분리 윈도 우의 행 갯수 분리 윈도 우의 열 갯수 동적 분리 윈도우의 창의 최소 크기 ISLab ICE HUFS MFC Tutorial 358 분리 윈도우의 크기 변경 • 프로그램에서 변경시 – SetColumnInfo,SetRowInfo 함수를 이용하여 크기 변경 void void void void GetRowInfo( int row, int& cyCur, int& cyMin ); GetColumnInfo( int col, int& cxCur, int& cxMin ); SetRowInfo( int row, int cyIdeal, int cyMin ); SetColumnInfo( int col, int cxIdeal, int cxMin ); ISLab ICE HUFS MFC Tutorial 359 pContext struct CCreateContext { m_pNewViewClass m_pCurrentDoc m_pNewDocTemplate m_pLastView m_pCurrentFrame // // // // // // 생성하고자 하는 새로운 뷰의 CRuntimeClass 새로 생성한 뷰가 연관된 이미 존재하는 도큐먼트 객체 새로운 MDI 프레임 윈도우의 생성과 연관된 도큐먼트 템플릿 이미 존재하는 뷰 현재 생성하고 있는 프레임 윈도우 ISLab ICE HUFS MFC Tutorial 360 다른 윈도우에 갱신이 안 되는 경우 ISLab ICE HUFS MFC Tutorial 361 OnLButtonUp 코드 수정 void CObeditView::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture() == this) { CClientDC dc(this); OnPrepareDC(&dc); dc.DPtoLP(&point); m_pCurDrawObject->SetEndPoint(point); m_pCurDrawObject->DrawObject(&dc); ReleaseCapture(); CObeditDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->m_objectList.AddTail(m_pCurDrawObject); pDoc->SetModifiedFlag(TRUE); pDoc->UpdateAllViews(this); } } 자신의 문서 내용을 출력하고 있는 모든 뷰에게 내용을 다시 그리라고 하는데 사용하는 함수 ISLab ICE HUFS MFC Tutorial 362 UpdateAllViews • CDocument 클래스의 멤버 함수 • 자신의 문서 내용을 출력하고 있는 모든 뷰에게 내용을 다시 그리라고 하는데 사용 • void UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL); – pSender : 도큐먼트를 변경한 뷰, NULL이면 모든 뷰 갱신 – lHint : 변경 정보 – pHint : 변경과 관계된 객체에 대한 포인터 • CView 클래스의 OnUpdate 함수 호출 ISLab ICE HUFS MFC Tutorial 363 OnUpdate • UpdateAllView는 각 뷰 클래스의 OnUpdate 함수 호출 – 각각의 OnUpdate 함수는 Invalidate를 호출하여 윈도우 영역 전 체를 다시 그린다. – 이를 방지하기 위해 수정해야 한다. 즉 OnUpdate에 갱신된 정보 를 포함하여 이 정보에 따라 그림을 수정해야 함 • 예제에서 OnUpdate가 불리는 경우 – 새로운 객체를 삽입하였을 때 객체 삽입을 알려주어야 할 때 – 배율 설정시에 모든 뷰에 배율이 변경되었다는 것을 알려주어야 할때 ISLab ICE HUFS MFC Tutorial 364 분리 윈도우의 배율의 불일치 ISLab ICE HUFS MFC Tutorial 365 OnUpdate 함수 정의 void CObeditView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { if (pSender == this) return; switch(lHint) 새로운 객체 추가 { case 1 : { CClientDC dc(this); OnPrepareDC(&dc); ((CDrawObject *)pHint)->DrawObject(&dc); break; } 한 뷰에서 다른 case 2 : 뷰로 배율을 전파 { SetZoomFactor(((CObeditView *)pSender)->m_zoomRatio); Invalidate(); break; } } } ISLab ICE HUFS MFC Tutorial 366 UpdateAllViews 호출 수정(1) void CObeditView::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture() == this) { CClientDC dc(this); OnPrepareDC(&dc); dc.DPtoLP(&point); m_pCurDrawObject->SetEndPoint(point); m_pCurDrawObject->DrawObject(&dc); ReleaseCapture(); 삽입된 객체 CObeditDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc->m_objectList.AddTail(m_pCurDrawObject); pDoc->SetModifiedFlag(TRUE); pDoc->UpdateAllViews(this, 1, m_pCurDrawObject); } } 객체 사입 ISLab ICE HUFS MFC Tutorial 367 UpdateAllViews 호출 수정(2) void CObeditView::OnViewZoom() { CZoomDlg zoomDlg(this); zoomDlg.m_editZoom = m_zoomRatio; if (zoomDlg.DoModal() != IDOK) return; m_zoomRatio = zoomDlg.m_editZoom; SetZoomFactor(zoomDlg.m_editZoom); GetDocument()->UpdateAllViews(this, 2); Invalidate(); } 배율 변경 ISLab ICE HUFS MFC Tutorial 368 CMyToolBar::OnHScroll 수정 void CMyToolBar::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int nMin, nMax; m_zoomScroll.GetScrollRange(&nMin, &nMax); int nOldPos, nCurPos = m_zoomScroll.GetScrollPos(); nOldPos = nCurPos; switch(nSBCode) .... // set zoom ratio to view window CMDIChildWnd* pChildFrame = (CMDIChildWnd *) (((CMDIFrameWnd *)AfxGetMainWnd())->MDIGetActive()); CObeditView *pView = (CObeditView *)pChildFrame->GetActiveView(); pView->SetZoomFactor(nCurPos); pView->GetDocument()->UpdateAllViews(pView, 2); pView->Invalidate(); } 배율 변경 ISLab ICE HUFS MFC Tutorial 369 정적 분리 윈도우 • 프레임 클래스의 OnCreateClient 함수를 오버라이드 해서 구현 • 서로 다른 뷰를 가지도록 만든다. ISLab ICE HUFS MFC Tutorial 370 OnCreateClient 함수 BOOL CMyFrame::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext) { // 먼저 가로로 두 개의 정적윈도우를 만들 것임을 알린다. if (!m_wndSplitter.CreateStatic(this, 1, 2); return FALSE; // 첫번째 정적 윈도우를 생성한다. 이 윈도우는 템플릿에 등록된 뷰 클래스이다. if (!m_wndSplitter.CreateView(0, 0, pContext->m_pNewViewClass, CSize(130, 50), pContext)) return FALSE; // 두번째 정적 윈도우를 생성한다. 이 윈도우는 CInputView 클래스이다. if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CInputView), CSize(0, 0), pContext)) return FALSE; // 두번째 뷰를 활성화한다. SetActiveView((CView*)m_wndSplitter.GetPane(0, 1); return TRUE; } ISLab ICE HUFS MFC Tutorial 371 세개의 정적 분리 윈도우 생성 ISLab ICE HUFS MFC Tutorial 372 세 개의 정적 분리윈도우의 구현 if (!m_wndSplitter1.CreateStatic(this, 1, 2)) return FALSE; if (!m_wndSplitter1.CreateView(0, 0, RUNTIME_CLASS(CFileTreeView), CSize(100,100), pContext)) return FASLE; if (!m_wndSplitter2.CreateStatic(&m_wndSplitter1, 2, 1, WS_CHILD | WS_VISIBLE | WS_BORDER, m_wndSplitter1.IdFromRowCol(0,1))) return FALSE; if (!m_wndSplitter2.CreateView(0, 0, RUNTIME_CLASS(CListView), CSize(100, 150), pContext)) return FALSE; if (!m_wndSplitter2.CreateView(1, 0, RUNTIME_CLASS(CTextView), CSize(100, 120), pContext)) return FALSE; SetActiveView((CView*)m_wndSplitter2.GetPane(0, 0)); ISLab ICE HUFS MFC Tutorial 373 ISLab ICE HUFS MFC 디버깅 매크로와 예외 처리 목차 • • • • 메시지 출력 ASSERT 매크로 오브젝트의 유효성 검사 예외 처리 ISLab ICE HUFS MFC Tutorial 375 컴파일 옵션 • Debug 모드 – _DEBUG • Release 모드 – NODEBUG ISLab ICE HUFS MFC Tutorial 376 디버그 모드로 수행 ISLab ICE HUFS MFC Tutorial 377 디버깅 모드로 수행 • • • • • 한 문장씩 수행 함수 안으로 들어가 수행 수행중인 함수밖으로 커서 위치까지 수행 Call Stack ISLab ICE HUFS MFC Tutorial 378 TRACE 매크로 • 디버그 창으로 메시지 출력 • 디버그 모드로 컴파일할 때만 수행 TRACE(“Sample TRACE Output : %d == 0x%x\n”, i, i); ISLab ICE HUFS MFC Tutorial 379 ASSERT 매크로 • 어떤 조건을 검사하여 거짓이면 그 위치(파일 이름과 행 번호)를 출력하는데 사용 • 주로 프로그램 개발 기간 중에 함수의 인자로 들어온 값 이 맞게 들어왔는지의 여부를 판단하는데 사용 • 디버그 모드로 컴파일 시에만 수행 ASSERT(prt != NULL); ISLab ICE HUFS MFC Tutorial 380 VERIFY 매크로 • ASSERT 매크로와 동일 • 단, 디버그 모드가 아닌 Release 모드로 컴파일 시에도 수 행 VERIFY(LoadAccelTable(hWnd, “MainWnd”)); ISLab ICE HUFS MFC Tutorial 381 오브젝트의 유효성 검사 • CObject 클래스의 후손에만 적용 • AssertValid – 현재 오브젝트의 데이터멤버가 올바른 값을 갖고 있는지의 여부 를 검사 • Dump – 현재 오브젝트의 데이터멤버를 출력하는데 사용 • 디버그 모드에서만 수행 – _DEBUG ISLab ICE HUFS MFC Tutorial 382 AssertValid class CHorzLine : public CObject { CPoint m_ptStart, m_ptEnd; .... #ifdef _DEBUG void AssertValid() const; void Dump(CDumpContext& dc) const; #endif }; void CHorzLine::AssertValid() const { CObject::AssertValid(); // 먼저 선조 클래스의 유효성을 검사한다. ASSERT(m_ptStart.y == m_ptEnd.y); } ISLab ICE HUFS MFC Tutorial 383 Dump void CHorzLine::Dump(CDumpContext& dc) const { CObject::Dump(dc); // 먼저 선조클래스의 데이터멤버를 호출한다. dc << “X : “ << (WORD)m_ptStart.x << “ Y : “ << (WORD)m_ptStart.y << “\n”; dc << “Y : “ << (WORD)m_ptEnd.x << “ Y : “ << (WORD)m_ptEnd.y << “\n”; } void f() { CHorzLine* pLine = new CHorzLine; .... #ifdef _DEBUG pLine->Dump(afxDump); #endif .... afxDump는 CDumpContext 타입의 전역 변수. 출력이 윈도우의 Debug 탭으로 출 력 ISLab ICE HUFS MFC Tutorial 384 예외처리 체크 되어야 ISLab ICE HUFS MFC Tutorial 385 ISLab ICE HUFS 공통 컨트롤(Common Control) 목차 • • • • • • • Common Control의 종류 Control Message 처리 Animation Control Progress Control Slider Control List Control Tree Control ISLab ICE HUFS MFC Tutorial 387 Common Control의 종류(1) • CAnimateCtrl • CHeaderCtrl • CHotKeyCtrl • CImageList • CListCtrl ISLab ICE HUFS MFC Tutorial 388 Common Control의 종류(2) • CProgressCtrl • CRichEditCtrl – OLE 복합문서 컨테이너 ISLab ICE HUFS MFC Tutorial 389 Common Control의 종류(3) • CSliderCtrl • CSpinButtonCtrl • CStatusBarCtrl • CTabCtrl ISLab ICE HUFS MFC Tutorial 390 Common Control의 종류(4) • CToolBarCtrl • CToolTipCtrl • CDragListBox • CCheckListBox ISLab ICE HUFS MFC Tutorial 391 Common Control의 종류(5) • CTreeCtrl ISLab ICE HUFS MFC Tutorial 392 Common Control • Common contorl의 code는 윈도우의 system\COMCTL32.DLL에 있다. – – – – 각 컨트롤에 대한 윈도우 프로시저 각 컨트롤을 위한 윈도 클래스를 등록하는 코드가 포함 등록 코드는 DLL이 로드될 때 호출 다이얼로그를 초기화할 때 프로그램에서는 다이얼로그 리소스에 서 기호 클래스 이름을 사용해서 DLL에 있는 윈도 프로시저를 연 결 – 이렇게 함으로써 프로그램에서는 컨트롤의 윈도를 소유하게 되 지만, 코드는 DLL에 존재 • 공통 컨트롤은 Class Wizard가 멤버 변수를 제공하지 않 음 • 공통 컨트롤들로부터 통지 메시지들을 매핑하는 일에는 Class Wizard를 이용할 수 있다. ISLab ICE HUFS MFC Tutorial 393 Common Control의 사용 • Common control 역시 컨트롤이기 때문에 dialog box에서 사용할 수 있다. • 보통 윈도우의 자식 윈도우로 존재할 수 있다. ISLab ICE HUFS MFC Tutorial 394 Dialog Box에서 사용(1) Progress Control Slider Control List Control Spin Control Hotkey Control Tree Control Tap Control Animation Control ISLab ICE HUFS MFC Tutorial 395 Dialog Box에서 사용(2) • Resource view에 있는 control palette 이용 • 없는 것은 데이터 멤버로 만들어 놓은 다음 WM_INITDIALOG 메시지가 왔을 때 Create 같은 멤버함 수를 이용해 직접 생성 • Class wizard를 이용해 dialog box template에 해당하는 dialog class 생성 • Add Member Variable 버튼을 택하여 common control에 해당하는 데이터 멤버를 만듦 – 강제적으로 Category가 CONTROL이 된다. ISLab ICE HUFS MFC Tutorial 396 일반윈도우의 자식윈도우로 사용시 • 각 common control 클래스의 오브젝트를 정의 • 각 컨트롤의 Create 함수를 이용해 컨트롤 생성 • Common control을 dialog template에 만들어 놓으면 알아서 생성되 기 때문에 직접 common control 클래스의 Create 멤버함수를 불러줄 필요가 없다. class CMyView : public CView { .... CProgressCtrl m_progressBar; .... }; int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) .... m_progressBar.Create(...); .... ISLab ICE HUFS MFC Tutorial 397 Notification Message 처리 • Control은 자신에게 무슨 일이 발생하면 부모 윈도우에게 알려준다. – Control이 dialog box에서 사용된 경우라면 이 때 부모윈도우는 dialog box가 된다. ISLab ICE HUFS MFC Tutorial 398 Notification Message • WM_COMMAND – 원래의 window control들이 이용 – 표준 32비트 wParam, lParam 메시지 파라미터는 common control이 부모에게 보내는 정보를 위해 사용하기에는 부적절 • WM_NOTIFY – wParam은 control ID – lParam은 control에 의해 운영되는 NMHDR 구조체 포인터이거나 이를 포함하는 더 큰 구조체 ISLab ICE HUFS MFC Tutorial 399 NMHDR typedef struct tagNMHDR { HWND hwndFrom; // 메시지를 보내는 control handle UINT idFrom; // 메시지를 보내는 control ID UINT code; // control-특성적인 notification code } NMHDR; • code로 들어오는 notification code에는 모든 common control에 공통되는 것과 common control에 따라 달라지 는 것 두 종류가 존재 ISLab ICE HUFS MFC Tutorial 400 공통되는 Notification Code NM_CLICK NM_DBCLICK NM_RCLICK NM_RDBCLICK NM_RETURN NM_SETFOCUS NM_KILLFOCUS NM_OUTOFMEMORY 컨트롤을 컨트롤을 컨트롤을 컨트롤을 컨트롤이 경우 컨트롤에 컨트롤이 메모리가 좌측 좌측 우측 우측 입력 마우스 버튼으로 클릭했을 때 마우스 버튼으로 더블 클릭했을 때 마우스 버튼으로 클릭했을 때 마우스 버튼으로 더블 클릭했을 때 포커스를 갖고 있을 때 리턴키를 친 입력 포커스가 갈 때 입력 포커스를 잃을 때 부족해서 하던 일을 끝내지 못할 때 ISLab ICE HUFS MFC Tutorial 401 다양한 Notification Code Structure • 툴팁 컨트롤 – NMHDR 스트럭처만을 그대로 이용 • 트리뷰 컨트롤 – 한 항목을 선택하면 TVN_SELCHANGING라는 알림코드를 갖는다. WM_NOTIFY 메시지 발생. 이때 lParam은 NM_TREEVIEW 스트럭 처를 갖는다. typedef struct _NM_TREEVIEW { NMHDR hdr; UINT action; TV_ITEM itemNew; TV_ITEM itemOld; POINT ptDrag; } NM_TREEVIEW; ISLab ICE HUFS MFC Tutorial 402 Message Map에서의 Notification Message • ON_NOTIFY 매크로 사용 – ON_NOTIFY(wNotifyCode, ctrlID, memberFn) – ctrlID를 공통 컨트롤 ID로 갖는 공통컨트롤로부터 wNotifyCode라는 알림코드가 오면 memberFn이라는 처리 함수를 불러달라는 것 – void memberFn(NMHDR* pNotifyStruct, LRESULT* result); 공통 컨트롤에 따라 달라진다. 처리 결과를 돌려준다. 처리했으면 0을 리턴 ISLab ICE HUFS MFC Tutorial 403 Message Map Macro • ON_NOTIFY_RANGE, ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE – 동일한 종류의 여러 control로부터 오는 notification code를 처 리하고자 할 때 – 매번 처리함수를 따로 만들지 않고 하나의 처리함수를 정의해 사 용 ISLab ICE HUFS MFC Tutorial 404 Notification Code 처리 예 • List control에서 사용자가 선택하는 항목이 달라질 때 BEGIN_MESSAGE_MAP(....) .... ON_NOTIFY(LVN_ITEMCHANGED, IDC_LISTCTRL, OnListCtrlClick) .... END_MESSAGE_MAP() void CCmmCtrlView::OnListCtrlClick(NMHDR* pNotifyStruct, LRESULT* result) { NM_LISTVIEW* pListView = (NM_LISTVIEW *)pNotifyStruct; // 자신의 용도에 맞게 적절히 처리한다. .... 적절한 타입으로 *result = 0; 캐스팅 하여 사용 } ISLab ICE HUFS MFC Tutorial 405 Message Reflection • Notification message를 부모 윈도우로 보냈을 때 처리가 안 되었다면 이를 다시 컨트롤로 보내 자체에서 처리가 되도록 하는 기능 • MFC 4.0에서 새로 제공해주는 기능 • 부모 윈도우의 의존성에서 벗어나 나름대로의 동작 방식 을 더 가질 수 있게 됨 • Message Reflection의 경우 컨트롤 자체의 message map 에 등록해야 – ON_NOTIFY_REFLECT 매크로 사용 ON_NOTIFY_REFLECT(wNotifyCode, memberFn) ISLab ICE HUFS MFC Tutorial 406 예제 • • • • 프로젝트 이름 : CmmCtrl SDI 데이터베이스 옵션은 주지 않음 Toolbar, status bar, 프린트 관련 옵션도 선택 않음 ISLab ICE HUFS MFC Tutorial 407 메뉴 구성 Common Control Animate Image List Slider Progress Tree List -----------Exit Help ID_COMM_ANIMATE ID_COMM_IMAGE ID_COMM_SLIDER ID_COMM_PROGRESS ID_COMM_TREE ID_COMM_LIST ISLab ICE HUFS MFC Tutorial 408 Control ID 생성 // CmmCtrlView.cpp #define #define #define #define #define IDC_ANIMATE IDC_PROGRESS IDC_SLIDER IDC_LISTCTRL IDC_TREECTRL 200 201 202 203 204 // // // // // Animation control ID Progress control ID Slider control ID List control ID Tree control ID • Resource Symbol을 이용해도 됨 ISLab ICE HUFS MFC Tutorial 409 컨트롤 멤버데이터 정의 • CCmmCtrlView 클래스에 정의 CAnimateCtrl CImageList CImageList CSliderCtrl CProgressCtrl CListCtrl CTreeCtrl HTREEITEM m_wndAnimateCtrl; // Animation control m_wndImageList; // Image list 1 m_wndSmallImageList; // Image list 2 m_wndSliderCtrl; // Slider control m_wndProgressCtrl; // Progress control m_wndListCtrl; // List control m_wndTreeCtrl; // Tree control m_treeRoot; // Tree control에서 사용된다. // 루트 항목을 가리킨다. BOOL m_bListCtrl; // List control의 생성여부 BOOL m_bTreeCtrl; // Tree control의 생성여부 BOOL m_bSlider; // Slider control의 생성여부 ISLab ICE HUFS MFC Tutorial 410 남아있는 객체 삭제를 위한 함수 void CCmmCtrlView::CheckWnd() { if (m_bListCtrl) // List control이 있으면 없앤다. { m_wndImageList.DeleteImageList(); m_wndSmallImageList.DeleteImageList(); m_wndListCtrl.DestroyWindow(); m_bListCtrl = FALSE; } else if (m_bTreeCtrl) // Tree control이 있으면 없앤다. { m_wndImageList.DeleteImageList(); m_wndTreeCtrl.DestroyWindow(); m_bTreeCtrl = FALSE; } else if (m_bSlider) { m_wndSliderCtrl.DestroyWindow(); m_bSlider = FALSE; } } ISLab ICE HUFS MFC Tutorial 411 CCmmCtrlView의 생성자/소멸자 변경 CCmmCtrlView::CCmmCtrlView() { m_bListCtrl = FALSE; m_bTreeCtrl = FALSE; m_bSlider = FALSE; } CCmmCtrlView::~CCmmCtrlView() { CheckWnd(); } ISLab ICE HUFS MFC Tutorial 412 Animation Control • • • • AVI 파일을 디스플레이 오디오가 있는 파일은 지원안 함 즉 하나의 Video Stream만 있는 avi file 만 지원 오디오를 지원하는 클래스 : OLE 컨트롤 중 마이크로소 프트 멀티미디어 컨트롤 ISLab ICE HUFS MFC Tutorial 413 ID_COMM_ANIMATE void CCmmCtrlView::OnCommAnimate() { CheckWnd(); // 이 함수의 용도는 앞에서 설명하였다. // AVI 파일을 입력받기 위한 다이얼로그를 띄운다. CFileDialog dlg( TRUE,_T("AVI"),_T("*.AVI"), OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, _T("Animation (*.AVI)|*.AVI|")); if (dlg.DoModal() != IDOK) // 사용자가 취소한 경우는 return; // 그대로 끝낸다. CString strFileName = dlg.GetPathName(); // AVI 파일 이름을 저장한다. CRect rectAnimateCtrl; GetClientRect(&rectAnimateCtrl); //뷰의 위치를 얻어둔다. // 애니메이트 컨트롤을 생성한다. m_wndAnimateCtrl.Create(WS_CHILD|WS_VISIBLE|WS_BORDER|ACS_CENTER, rectAnimateCtrl, this, IDC_ANIMATE); m_wndAnimateCtrl.Open(strFileName); InvalidateRect(NULL); UpdateWindow(); m_wndAnimateCtrl.Play(0,0xFFFF,1); // } ISLab ICE HUFS MFC Tutorial 414 Animation Control의 속성 ACS_CENTER 애니메이션 컨트롤의 중앙에서 AVI 파일을 플레이 한다. 이 스타일이 주어지지 않으면 AVI 파일의 크기에 맞춰 애니메이션 컨트롤의 크기가 변경된다 위의 예에서 바로 이 스타일을 사용하였다. ACS_TRANSPARENT AVI 파일의 배경색 대신에 원래 애니메이션 컨트롤 의 자리에 있던 배경색을 사용한다. ACS_AUTOPLAY AVI 파일이 오픈됨과 동시에 플레이되도록 하며 플레이가 계속 반복되도록 한다. ISLab ICE HUFS MFC Tutorial 415 CAnimateCtrl의 멤버 함수 Open Play Seek Stop Close AVI 파일이나 리소스를 읽어들여 첫 프레임을 윈도우에 표시한다. AVI 클립을 플레이한다. 첫번째 인자와 두번째 인자가 플레이할 프레임을 지칭 시작 프레임일 경우 0을 마지막 프레임일 경우 -1(0xFFFF) 마지막 인자는 반복횟수 AVI 클립의 지정된 프레임을 윈도우에 표시한다. AVI 클립의 표시를 중단한다. 오픈된 AVI 클립을 닫아 버린다. ISLab ICE HUFS MFC Tutorial 416 Animation Control의 Notification Code ACN_START ACN_STOP AVI 클립의 플레이가 시작되었음을 알린다. AVI 클립의 플레이가 다 끝났음을 알린다. • WM_COMMAND 메시지 발생 • ON_CONTROL 매크로 사용 ISLab ICE HUFS MFC Tutorial 417 Notification Code 처리함수 BEGIN_MESSAGE_MAP(CCmmCtrlView, CView) //{{AFX_MSG_MAP(CCmmCtrlView) ON_COMMAND(ID_COMM_ANIMATE, OnCommAnimate) ON_COMMAND(ID_COMM_IMAGE, OnCommImage) .... //}}AFX_MSG_MAP ON_CONTROL(ACN_STOP, IDC_ANIMATE, OnAnimateStop) END_MESSAGE_MAP() void CCmmCtrlView::OnAnimateStop() { AfxMessageBox("AVI 방영(?)이 끝났습니다."); m_wndAnimateCtrl.Close(); m_wndAnimateCtrl.DestroyWindow(); InvalidateRect(NULL); } ISLab ICE HUFS MFC Tutorial 418 Image List • Mask bitmap • 윈도우가 아님 • BOOL Create(int cx, int cy, BOOL bMask, int nInitial, int nGrow); – cx, cy ; 픽셀 단위로 각 이미지의 크기 – bMask : mask image를 사용할 것인지의 여부 – nInitial : 처음 이미지 리스트가 생성될 때 이미지 리스트에 들어 갈 이미지의 개수 – nGrow : 이미지 리스트의 크기가 변할 때 쓰이는 단위 ISLab ICE HUFS MFC Tutorial 419 ID_COMM_IMAGE(1) void CCmmCtrlView::OnCommImage() { CheckWnd(); m_wndImageList.Create(32, 32, TRUE, 2, 2); CBitmap bitmap, bitmap2, bitmap3, bitmap4, bitmap5; bitmap3.LoadBitmap(IDB_BITMAP3); // Load mask bitmap bitmap.LoadBitmap(IDB_BITMAP1); m_wndImageList.Add(&bitmap, (CBitmap *)&bitmap3); bitmap2.LoadBitmap(IDB_BITMAP2); m_wndImageList.Add(&bitmap2, (CBitmap *)&bitmap3); CClientDC dc(this); CPoint pt; for(int i = 0;i < m_wndImageList.GetImageCount();i++) { pt.x = 100 + 32*i; pt.y = 100; m_wndImageList.Draw(&dc, i, pt, ILD_NORMAL); ISLab ICE HUFS MFC Tutorial 420 ID_COMM_IMAGE(2) pt.y += 50; m_wndImageList.Draw(&dc, i, pt, ILD_BLEND50); pt.y += 50; m_wndImageList.Draw(&dc, i, pt, ILD_BLEND25); } m_wndImageList.DeleteImageList(); } IDB_BITMAP1 IDB_BITMAP2 IDB_BITMAP3 ISLab ICE HUFS MFC Tutorial 421 Image List의 멤버 함수(1) GetImageCount SetBkColor GetBkColor GetImageInfo DeleteImageList Add Remove Replace Extraction Read Write Image list에 들어있는 image의 개수 Image list의 image의 배경색을 설정. Mask image list의 경우에는 CLR_NONE을 주면 Mask를 갖고 그리기 때문에 원래 배경이 보존된다 현재 image list의 image의 배경색을 얻어온다 현재 image list의 image에 대한 정보를 얻음 Image list를 삭제한다 새로운 image를 image list에 추가한다. Image list에서 image를 삭제한다. Image list에서 한 image를 다른 image로 변경 Image list의 image를 icon handle로 만들려는 경우에 사용 Image를 파일에서 읽어 image list에 추가 Image를 image list에서 읽어 파일에 추가 ISLab ICE HUFS MFC Tutorial 422 Image List의 멤버 함수(2) Draw SetOverlayImage Image list의 image를 윈도우 위에 출력한다. Image list의 image를 overlay image list에 추가한다. Image list 당 4개까지의 image를 overlay mask로 사용할 수 있다. ISLab ICE HUFS MFC Tutorial 423 Draw 함수 BOOL Draw(CDC* pdc, int nImage, POINT pt, UINT nStyle); IDL_NORMAL IDL_TRANSPARENT IDL_BLEND50 IDL_BLEND25 IDL_OVERLAYMASK Image list에 지정된 배경색을 갖고 이미지를 출력한다. Mask image list의 경우에는 배경이 보존된 채 출력이 이루어진다. 지정된 배경색에 관계없이 배경을 유지한 채 image를 출력하는데 마스크된 image에만 적용 가능한 옵션 주어진 image가 선택되었음을 나타내기 위해 시스템 하이라이트 색상으로 혼합한 다음에 출력한다. 주어진 image가 입력포커스를 갖고 있음을 나타내며 출력한다. 주어진 image를 그리고 그 위에 이 스타일과 함께 지정된 overlay mask를 그린다. Overlay mask 지정은 INDEXTOOVERLAYMASK macro를 통해 이루 어진다. 연산자를 이용해 이 스타일과 함께 지정해준다. ISLab ICE HUFS MFC Tutorial 424 ID_COMM_PROGRESS(1) void CCmmCtrlView::OnCommProgress() { CheckWnd(); InvalidateRect(NULL); CRect rect; // Progress control의 위치를 지정한다 rect.left = rect.top = 100; rect.right = 400; rect.bottom = 150; // Progress control을 생성한다 m_wndProgressCtrl.Create(WS_CHILD|WS_VISIBLE|WS_BORDER,rect, this,IDC_PROGRESS); m_wndProgressCtrl.SetRange(0, 100); // 진행범위를 지정한다. m_wndProgressCtrl.SetPos(0); // 초기위치를 지정한다 ISLab ICE HUFS MFC Tutorial 425 ID_COMM_PROGRESS(2) for(int i = 1;i <= 10; i++) { ::Sleep(100); // 0.1초간 쉰다. m_wndProgressCtrl.SetPos(i*10); // 10만큼씩 진행한다. } AfxMessageBox("Progress Bar의 끝에 도달했군요."); m_wndProgressCtrl.DestroyWindow(); InvalidateRect(NULL); } ISLab ICE HUFS MFC Tutorial 426 Progress Control의 멤버함수 SetRange SetPos OffsetPos SetStep StepIt Progress Progress Progress Progress Progress bar의 bar의 bar의 bar의 bar의 범위값을 지정하고 그에 맞추어 다시 그림 현재 위치를 지정하고 그에 맞추어 다시 그림 현재 위치를 주어진 값만큼 보정하고 다시 그림 진행 단위를 지정한다. StepIt 함수에서 사용한다. 현재 위치를 SetStep에서 지정된 값만큼 진행시킨다. ISLab ICE HUFS MFC Tutorial 427 Slider Control • 불연속적인 값이나 어떤 범위의 값을 입력받고자 할 때 • WM_HSCROLL(혹은 WM_VSCROLL)로 특이하게 notification code를 발생시킨다. ISLab ICE HUFS MFC Tutorial 428 ID_COMM_SLIDER void CCmmCtrlView::OnCommSlider() { CheckWnd(); InvalidateRect(NULL); CRect rect; rect.SetRect(100, 100, 300, 200); m_wndSliderCtrl.Create(WS_VISIBLE|WS_CHILD |TBS_HORZ|TBS_BOTH|TBS_AUTOTICKS, rect, this, IDC_SLIDER); m_wndSliderCtrl.SetTicFreq( 2 ); // Set the interval of tick count m_wndSliderCtrl.SetLineSize( 2 ); // Set the size of line movement m_wndSliderCtrl.SetPageSize( 4 ); // Set the size of page movement m_wndSliderCtrl.SetRange( 0, 12, TRUE ); m_wndSliderCtrl.SetPos(0); } ISLab ICE HUFS MFC Tutorial 429 Slider Control의 윈도우 스타일 TBS_HORZ TBS_VERT TBS_AUTOTICKS TBS_NOTICKS TBS_BOTTOM TBS_TOP TBS_RIGHT 수평 slider control을 만든다. 이것이 디폴트이다. 수직 slider control을 만든다. 지정된 슬라이더 범위 내의 각 단위값 마다 눈금을 붙이다. 만일 이 스타일이 이용된 경우에는 SetTic, SetTicFreq와 같은 멤버함수를 이용해 눈금의 위치를 지정할 수 있다. 눈금이 없는 슬라이더를 만든다. 슬라이더의 하단에 눈금을 표시한다. TBS_TOP 스타일과 함께 사용되면 위아래 모두에 눈금을 붙일 수 있다. TBS_BOTTOM과 TBS_TOP 스타일은 수평 슬라이더에만 적용 가능하다. 수평 슬라이더의 상단에 눈금을 붙인다. 수직 슬라이더의 우단에 눈금을 붙인다. TBS_LEFT 스타일과 함께 사용되면 오른쪽, 왼쪽 모두에 눈금을 붙인다. ISLab ICE HUFS MFC Tutorial 430 TBS_LEFT TBS_BOTH TBS_ENABLESELRANGE 수직 슬라이더의 좌단에 눈금을 붙인다. 수평 슬라이더이면 위아래에 눈금을 붙이고 수직 슬라이더이면 왼쪽, 오른쪽에 눈금을 붙인다. 이 스타일을 주면 영역을 선택하는 것이 가능하다. 선택 영역의 시작과 끝 눈금이 삼각형 모양의 눈금으로 변하고 그 사이의 영역이 하이라이트된다. ISLab ICE HUFS MFC Tutorial 431 CSliderCtrl의 멤버 함수(1) SetRange SetRangeMin SetRangeMax GetRangeMax GetRangeMin GetRange GetLineSize SetLineSize GetPageSize SetPageSize GetPos SetPos Slider control의 양끝값을 설정한다. Slider control의 최소값을 설정한다. Slider control의 최대값을 설정한다. Slider control의 최대값을 얻어온다. Slider control의 최소값을 얻어온다. Slider control의 양끝값을 얻어온다. Slider control의 라인 크기를 얻어온다. TB_LINEUP, TB_LINEDOWN의 발생 시 이동량을 얻어오는 것이다. Slider control의 라인 크기를 설정한다. Slider control의 페이지 크기를 얻어온다. TB_PAGEUP, TB_PAGEDOWN의 발생시 이동량을 얻어오는 것이다. Slider control의 페이지 크기를 결정한다. Slider control의 슬라이더 위치를 얻어온다. Slider control의 슬라이더 위치를 새로 설정한다. ISLab ICE HUFS MFC Tutorial 432 CSliderCtrl의 멤버 함수(2) GetTic GetTicPos SetTic SetTicFreq ClearTics 주어진 눈금의 위치를 얻어온다. 주어진 눈금이 위치한 좌표를 얻어온다. 눈금이 생길 위치를 지정한다. 눈금이 생길 위치를 위치 단위로 지정한다. 예로 들면 2로 지정하면 0, 2, 4...의 위치에 눈금이 생긴다. Slider control에서 모든 눈금을 제거한다. ISLab ICE HUFS MFC Tutorial 433 Slider Control의 Notification Code TB_TOP TB_BOTTOM TB_LINEDOWN TB_LINEUP TB_PAGEDOWN TB_PAGEUP TB_THUMBPOSITION TB_THUMBTRACK TB_ENDTRACK HOME 키를 눌렀을 때 END 키를 눌렀을 때 VK_RIGHT이나 VK_DOWN 키를 눌렀을 때 VK_LEFT나 VK_UP 키를 눌렀을 때 마우스로 슬라이더의 오른쪽을 누르거나 PgDn 키 를 눌렀을 때 마우스로 슬라이더의 왼쪽을 누르거나 PgUp 키를 눌렀을 때 TB_THUMBTRACK의 끝에 따라와 슬라이더의 드래깅이 끝났음을 알린다. 사용자가 슬라이더를 드래그하면 그 때 계속적으로 발생한다. 각 notification code에 뒤이어 항상 발생한다. ISLab ICE HUFS MFC Tutorial 434 Slider Control의 WM_HSCROLL 처리 BEGIN_MESSAGE_MAP(CCmmCtrlView, CView) //{{AFX_MSG_MAP(CCmmCtrlView) .... //}}AFX_MSG_MAP ON_CONTROL(ACN_STOP, IDC_ANIMATE, OnAnimateStop) ON_WM_HSCROLL() END_MESSAGE_MAP() void CCmmCtrlView::OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar ) { int nCurPos = ((CSliderCtrl *)pScrollBar)->GetPos(); if (nCurPos==((CSliderCtrl *)pScrollBar)->GetRangeMax() && nSBCode==TB_ENDTRACK) { AfxMessageBox("Slider의 끝에 도달했군요."); m_wndSliderCtrl.DestroyWindow(); InvalidateRect(NULL); } } ISLab ICE HUFS MFC Tutorial 435 List View Control • 리스트의 한 아이템이 여러 항목으로 구성될 수 있다. • 항목의 일부로 비트맵이 들어갈 수 있다. • 각 항목의 제목을 나타내기 위해 헤더(Header) 컨트롤이 라는 것을 내부적으로 사용할 수 있다. • 항목마다 사용되는 아이콘을 따로 리스트로 유지하는데 앞서 살펴 본 image list를 사용하는 것이다. ISLab ICE HUFS MFC Tutorial 436 List View Control의 타입 아이콘뷰 스몰아이콘뷰 리스트뷰 리포트뷰 LVS_ICON 스타일을 지정하면 된다. 각 항목은 아이콘과 그 밑의 레이블로 구성된다. 각 항목은 드래깅으로 다른 위치에 갖다놓을 수 있다. LVS_SMALLICON 스타일을 지정하면 된다. 각 항목은 16X16 아이콘과 그 오른쪽의 레이블로 구성된다. 각 항목 은 드래깅으로 다른 위치에 갖다 놓을 수 있다. LVS_LIST 스타일을 지정하면 된다. 각 항목은 서브 항목별 로 정렬되어 디스플레이된다. LVS_REPORT 스타일을 지정하면 된다. LVS_NOCOLUMNHEADER 스타일이 명시되지 않으면 헤더 컨트롤이 사용되어 레이블과 각 서브 항목의 타이틀을 표시할 수 있다. 리스트뷰에서와 마찬가지로 각 항목들은 서브 항목별로 정렬되어 디스플레이된다. ISLab ICE HUFS MFC Tutorial 437 List View Control의 윈도우 스타일 LVS_BUTTON LVS_EDITLABELS Icon view에서 아이콘을 버튼처럼 디스플레이 되도록 한다. 각 항목의 레이블이 편집 가능하도록 한다. 부모 윈도우는 LVN_ENDLABELEDIT 알림코드를 처리할 수 있어야 한다. LVS_ICON List control을 아이콘뷰로 생성할 것을 지정한다 LVS_LIST List control을 리스트뷰로 생성할 것을 지정한다 LVS_REPORT List control을 리포트뷰로 생성할 것을 지정한다 LVS_SMALLICON List control을 스몰아이콘뷰로 생성할 것을 지정 LVS_NOCOLUMNHEADER List control을 리포트뷰로 만들 때 header control을 사용하지 말것을 지정 LVS_SORTASCENDING List control의 항목을 오름차순으로 정렬 LVS_SORTDESCENDING List control의 항목을 내림차순으로 정렬 LVS_SINGLESEL 단지 하나의 항목만이 선택가능 하도록 한다. 원래 디폴트는 여러 항목이 선택 가능하다. LVS_NOSCROLL 항목들이 윈도우 영역의 크기를 넘어가도 스크롤이 안되도록 한다. ISLab ICE HUFS MFC Tutorial 438 CListCtrl 클래스의 주요 멤버 함수(1) InsertColumn DeleteColumn InsertItem GetItem SelItem DeleteItem DeleteAllItems HitTest EnsureVisible Scroll EditLabel GetBkColor SetBkColor GetImageList 새로운 컬럼을 삽입한다. 컬럼을 하나 삭제한다. 새로운 항목을 하나 삽입한다. 항목의 속성을 얻어온다. 항목에 부항목을 붙이는 등의 속성변경 작업을 한다. 항목 하나를 삭제한다. 모든 항목을 삭제한다. 주어진 위치에 어떤 항목이 있는지 알아낸다. 주어진 항목이 보이도록 만든다. 내용을 스크롤시킨다. 항목 텍스트의 편집이 가능하도록 한다. 배경색을 얻어온다. 배경색을 설정한다. 사용되는 아이콘리스트를 얻어온다. ISLab ICE HUFS MFC Tutorial 439 CListCtrl 클래스의 주요 멤버 함수(2) SetImageList GetItemCount GetStringWidth 사용되는 icon list를 지정한다. 항목수를 얻어온다. 주어진 문자열을 표시하는데 필요한 최소한의 컬럼폭을 돌려준다. GetColumnWidth 리스트뷰와 리포트뷰의 컬럼폭을 얻어온다. SetColumnWidth 리스트뷰와 리포트뷰의 컬럼폭을 설정한다. GetItemText 리스트뷰의 특정항목의 레이블이나 부항목의 텍스트를 얻어온다. SetItemText 리스트뷰의 특정항목의 레이블이나 부항목의 텍스트를 설정한다. ISLab ICE HUFS MFC Tutorial 440 ID_COMM_LIST(1) void CCmmCtrlView::OnCommList() { CheckWnd(); CRect rect; GetClientRect(&rect); // 리스트 컨트롤을 리포트뷰로 생성한다. m_wndListCtrl.Create(LVS_REPORT| WS_VISIBLE | WS_CHILD, rect, this, IDC_LISTCTRL); // 16X16 이미지리스트를 만든다. m_wndSmallImageList.Create(16,16, FALSE, 1, 2); m_wndSmallImageList.Add(((CCmmCtrlApp *)AfxGetApp())>LoadIcon(IDI_ICON1)); m_wndSmallImageList.Add(((CCmmCtrlApp *)AfxGetApp())>LoadIcon(IDI_ICON2)); m_wndListCtrl.SetImageList(&m_wndSmallImageList, LVSIL_SMALL); ISLab ICE HUFS MFC Tutorial 441 ID_COMM_LIST(2) // 리스트 컨트롤의 헤더를 초기화한다. LV_COLUMN lvc; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_CENTER; // 첫 번째 칼럼을 만든다. lvc.pszText = (LPTSTR)_T("회사이름 "); lvc.cx = m_wndListCtrl.GetStringWidth(lvc.pszText) + 15; lvc.iSubItem = 0; m_wndListCtrl.InsertColumn(0, &lvc); // 두 번째 칼럼을 만든다. lvc.pszText = (LPTSTR)_T("제품이름 "); lvc.cx = m_wndListCtrl.GetStringWidth(lvc.pszText) + 15; lvc.iSubItem = 1; m_wndListCtrl.InsertColumn(1, &lvc); ISLab ICE HUFS MFC Tutorial 442 ID_COMM_LIST(3) // 세 번째 칼럼을 만든다. lvc.pszText = (LPTSTR)_T("가격 "); lvc.cx = m_wndListCtrl.GetStringWidth(lvc.pszText) + 15; lvc.iSubItem = 2; m_wndListCtrl.InsertColumn(2, &lvc); // 네 번째 칼럼을 만든다. lvc.pszText = (LPTSTR)_T("수량 "); lvc.cx = m_wndListCtrl.GetStringWidth(lvc.pszText) + 15; lvc.iSubItem = 3; m_wndListCtrl.InsertColumn(3, &lvc); // 첫 번째 항목을 리스트컨트롤에 붙인다. int nActualIndex; LV_ITEM lvItem; lvItem.mask = LVIF_TEXT | LVIF_IMAGE; lvItem.state = lvItem.stateMask = 0; lvItem.iImage = lvItem.lParam = 0; ISLab ICE HUFS MFC Tutorial 443 ID_COMM_LIST(4) lvItem.iItem = m_wndListCtrl.GetItemCount() + 1; lvItem.iSubItem = 0; lvItem.pszText = _T("삼성"); nActualIndex = m_wndListCtrl.InsertItem(&lvItem); lvItem.mask = LVIF_TEXT; lvItem.iImage = -1; lvItem.iItem = nActualIndex; lvItem.iSubItem = 1; lvItem.pszText = _T("매직 스테이션"); m_wndListCtrl.SetItem(&lvItem); lvItem.iItem = nActualIndex; lvItem.iSubItem = 2; lvItem.pszText = _T("2,500,000"); m_wndListCtrl.SetItem(&lvItem); ISLab ICE HUFS MFC Tutorial 444 ID_COMM_LIST(5) lvItem.iItem = nActualIndex; lvItem.iSubItem = 3; lvItem.pszText = _T("3,000"); m_wndListCtrl.SetItem(&lvItem); // 두 번째 항목을 리스트컨트롤에 붙인다. lvItem.mask = LVIF_TEXT | LVIF_IMAGE; lvItem.state = lvItem.stateMask = 0; lvItem.iImage = lvItem.lParam = 0; lvItem.iItem = m_wndListCtrl.GetItemCount() + 1; lvItem.iSubItem = 0; lvItem.pszText = _T("끝내기"); nActualIndex = m_wndListCtrl.InsertItem(&lvItem); m_bListCtrl = TRUE; } ISLab ICE HUFS MFC Tutorial 445 SetImageList • 두번째 인자 – LVSIL_NORMAL 큰 아이콘을 갖는 image list – LVSIL_SMALL 작은 아이콘을 갖는 image list – LVSIL_STATE 상태를 나타내는 아이콘을 갖는 image list ISLab ICE HUFS MFC Tutorial 446 헤더 • LV_COLUMN을 초기화해서 InsertColumn 함수를 호출 typedef struct _LV_COLUMN { UINT mask; int fmt; // 정렬방식 : LVCFMT_LEFT, LVCFMT_RIGHT, // LVCFMT_CENTER int cx; LPSTR pszText; int cchTextMax; int iSubItem; } LV_COLUMN • mask LVCF_FMT LVCF_SUBITEM LVCF_TEXT LVCF_WIDTH fmt 필드를 사용할 것이다 iSubItem 필드를 사용할 것이다. pszText 필드를 사용할 것이다. cx 필드를 사용할 것이다. ISLab ICE HUFS MFC Tutorial 447 항목 • LV_ITEM 스트럭처를 초기화 한 다음 InsertItem 함수 호 출 • 부항목은 InsertItem 함수의 리턴값(nActualIndex)을 갖 고 LV_ITEM 스트럭처를 초기화한 다음에 SetItem 함수 호출 • 원하는 부항목 수만큼 반복 ISLab ICE HUFS MFC Tutorial 448 LV_ITEM(1) typedef struct _LV_ITEM { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPTSTR pszText; int cchTextMax; int iImage; // index of the list view item’s icon LPARAM lParam; // 32-bit value to associate with item } LV_ITEM; ISLab ICE HUFS MFC Tutorial 449 LV_ITEM(2) • mask LVIF_TEXT LVIF_IMAGE LVIF_PARAM LVIF_STATE pszText 필드를 사용할 것이다. iImage 필드를 사용할 것이다. lParam 필드를 사용할 것이다. state 필드를 사용할 것이다. • iItem : list view control의 몇번째 항목인가 • iSubItem : 몇번째 부항목인가(0부터 시작) • state : stateMask 필드와 같이 사용 – LVIS_CUT, LVIS_DROPHILITED, LVIS_FOCUSED, LVIS_SELECTED – 항목의 외양을 나타냄 ISLab ICE HUFS MFC Tutorial 450 LV_ITEM(3) • pszText : 항목의 텍스트 • cchTextMax : pszText 필드의 버퍼 크기 • iImage : image list의 아이콘의 인덱스(-1이면 사용안함) – 만일 이 값이 I_IMAGECALLBACK 이면 디스플레이 할 순간에 부 모 윈도우로 LVN_GETDISPINFO notification message가 보내진 다. ISLab ICE HUFS MFC Tutorial 451 실행 모습 ISLab ICE HUFS MFC Tutorial 452 List View의 Notification Code LVN_BEGINDRAG LVN_BEGINRDRAG LVN_BEGINLABELEDIT LVN_ENDLABELEDIT LVN_DELETEITEM LVN_KEYDOWN LVN_COLUMNCLICK LVN_DELETEALLITEMS LVN_INSERTITEM LVN_ITEMCHANGING LVN_ITEMCHANGED 왼쪽 마우스버튼을 이용해 드래그 작업이 시작 할 때 발생한다. 오른쪽 마우스버튼을 이용해 드래그 작업이 시 작할 때 발생 레이블 편집이 시작될 때 발생 레이블 편집이 끝날 때 발생 항목이 삭제될 때 발생 키가 눌렸을 때 발생. 이는 리스트뷰 컨트롤이 입력 포커스를 갖고 있을 때만 발생 리스트뷰 컨트롤의 헤더가 클릭되었을 때 발생 모든 항목이 삭제되었을 때 발생 새로운 항목이 삽입되었을 때 발생 현재 선택된 항목이 다른 항목으로 변경될 때 현재 선택 항목이 다른 항목으로 변경된 다음 발생 ISLab ICE HUFS MFC Tutorial 453 LVN_ITEMCHANGED 처리 BEGIN_MESSAGE_MAP(CCmmCtrlView, CView) //{{AFX_MSG_MAP(CCmmCtrlView) .... //}}AFX_MSG_MAP ON_CONTROL(ACN_STOP, IDC_ANIMATE, OnAnimateStop) ON_WM_HSCROLL() ON_NOTIFY(LVN_ITEMCHANGED, IDC_LISTCTRL, OnListCtrlClick) END_MESSAGE_MAP() void CCmmCtrlView::OnListCtrlClick(NMHDR * pNotifyStruct, LRESULT * result) { NM_LISTVIEW* pListView = (NM_LISTVIEW *)pNotifyStruct; if (pListView->iItem == 1) { AfxMessageBox("끝이 눌렸습니다."); } *result = 0; } ISLab ICE HUFS MFC Tutorial 454 Tree View Control • 윈도우 스타일 TVS_HASLINES TVS_LINESATROOT TVS_HASBUTTONS TVS_EdITLABELS 듦 각 항목간(부모 자식간)을 선으로 이어준다. 루트를 만들어 최상위 레벨의 항목들과 연결 시켜준다. 각 항목의 좌측에 버튼을 붙여준다. Tree view control의 레이블을 편집 가능하게 만 ISLab ICE HUFS MFC Tutorial 455 CTreeCtrl의 멤버함수(1) InsertItem DeleteItem DeleteAllItems Expand SelectItem EditLabel HitTest SortChildren SortChildrenCB EnsureVisible GetCount GetIndent SetIndent 새로운 항목을 삽입한다. 항목 하나를 삭제한다. 모든 항목을 삭제한다. 주어진 항목의 자식 항목들을 모두 펼친다. 주어진 항목을 현재 선택 항목으로 만든다. 주어진 항목의 레이블을 편집 가능하게 만든다. 주어진 위치에 있는 항목의 핸들을 얻어온다. 주어진 항목의 자식 항목들을 정렬한다. 주어진 항목의 자식 항목들을 정렬한다. 따로 정렬함수를 제공해 주어야 한다. 지정된 항목이 트리뷰 컨트롤 내에서 보이도록 만든다. 항목의 총수를 얻어온다. 부모 항목과 자식 항목 간의 거리를 픽셀단위로 얻어온다. 부모 항목과 자식 항목 간의 거리를 픽셀단위로 설정한다. ISLab ICE HUFS MFC Tutorial 456 CTreeCtrl의 멤버함수(2) GetImageList SetImageList ItemHasChildren GetNextSiblingItem GetPrevSiblingItem GetParentItem GetSelectedItem GetRootItem GetItem SetItem GetItemText 트리뷰 컨트롤과 관련된 이미지리스트를 얻어온다. 트리뷰 컨트롤과 관련된 이미지리스트를 설정한다. 주어진 항목이 자식 노드를 갖고 있는지 여부를 알려준다. 트리구조에서 주어진 항목과 같은 레벨의 다음 항 목을 얻어준다. 트리구조에서 주어진 항목과 같은 레벨의 이전 항 목을 얻어준다. 트리구조에서 주어진 항목의 부모 항목을 얻음 현재 선택된 항목이 무엇인지 알려준다. 루트항목이 무엇인지 알려준다. 주어진 트리뷰 항목의 속성을 돌려준다. 주어진 트리뷰 항목의 여타 속성을 설정한다. 주어진 트리뷰 항목의 텍스트를 돌려준다. ISLab ICE HUFS MFC Tutorial 457 CTreeCtrl의 멤버함수(3) SetItemText GetVisibleCount GetItemImage SetItemImage GetItemRect 주어진 트리뷰 항목의 텍스트를 설정한다. 현재 트리뷰 컨트롤에서 보이는 항목의 수를 돌려 준다. 주어진 항목의 이미지가 무엇인지 알려준다. 주어진 항목의 이미지를 변경한다. 주어진 항목을 둘러싸는 사각형이 무엇인지 얻음 ISLab ICE HUFS MFC Tutorial 458 ID_COMM_TREE(1) void CCmmCtrlView::OnCommTree() { CheckWnd(); InvalidateRect(NULL); CRect rect; GetClientRect(&rect); m_wndTreeCtrl.Create(TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | WS_VISIBLE | WS_CHILD, rect, this, IDC_TREECTRL); m_wndImageList.Create(32, 32, FALSE, 1, 2); m_wndImageList.Add(((CCmmCtrlApp*)AfxGetApp())->LoadIcon(IDI_ICON1)); m_wndImageList.Add(((CCmmCtrlApp*)AfxGetApp())->LoadIcon(IDI_ICON2)); m_wndImageList.Add(((CCmmCtrlApp*)AfxGetApp())->LoadIcon(IDI_ICON3)); m_wndTreeCtrl.SetImageList(&m_wndImageList, TVSIL_NORMAL); TV_INSERTSTRUCT tvs; ISLab ICE HUFS MFC Tutorial 459 ID_COMM_TREE(2) memset(&tvs, 0, sizeof(TV_INSERTSTRUCT)); tvs.hParent = 0; tvs.hInsertAfter = TVI_SORT; tvs.item.iImage = 0; tvs.item.iSelectedImage = 2; tvs.item.pszText = _T("Tree Parent"); tvs.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT; m_treeRoot = m_wndTreeCtrl.InsertItem(&tvs); tvs.hParent = m_treeRoot; tvs.hInsertAfter = TVI_SORT; tvs.item.iImage = 1; tvs.item.iSelectedImage = 2; tvs.item.pszText = _T("Tree Child1"); tvs.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT; m_wndTreeCtrl.InsertItem(&tvs); ISLab ICE HUFS MFC Tutorial 460 ID_COMM_TREE(3) tvs.hParent = m_treeRoot; tvs.hInsertAfter = TVI_SORT; tvs.item.iImage = 1; tvs.item.iSelectedImage = 2; tvs.item.pszText = _T("Tree Child2"); tvs.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT; m_wndTreeCtrl.InsertItem(&tvs); m_bTreeCtrl = TRUE; } ISLab ICE HUFS MFC Tutorial 461 SetImageList • 두번째 인자 – TVSIL_NORMAL – TVSIL_STATE 항목의 선택시와 보통 때의 모습만을 담고 있은 경우 선택 유무 말고 사용자 나름대로의 기준으로 항목 상태 를 지정하려는 경우 IDI_ICON1 IDI_ICON2 IDI_ICON3 ISLab ICE HUFS MFC Tutorial 462 실행모습 ISLab ICE HUFS MFC Tutorial 463 TV_INSERTSTRUCT typedef struct _TV_INSERTSTRUCT { HTREEITEM hParent; // 지금 삽입되는 항목의 부모 항목이 무엇인가 // 나타내는 핸들이 들어가는 곳 // InsertItem 함수를 이용해 항목을 하나 추가 // 하면 그 항목의 핸들이 리턴되는데 그 값이 // hParent와 hInsertAfter 필드에서 사용된다 // 값이 0이거나 TVI_ROOT이면 루트 항목이 됨 HTREEITEM hInsertAfter; // 어느 항목 뒤에 삽입될 것인지 그 항목을 지정 // 여기서 위치는 hParent 필드가 가리키는 항목 // 의 자식 항목에서의 위치를 말함 // TVI_FIRST 첫번째 항목으로 삽입 // TVI_LAST 마지막 항목으로 삽입 // TVI_SORT 삽입되는 항목을 알파벳 순으로 // 정렬하여 삽입한다. TV_ITEM item; } TV_INSERTSTUCT, FAR *LPTV_INSERTSTRUCT; ISLab ICE HUFS MFC Tutorial 464 TV_ITEM(1) typedef struct _TV_ITEM { UINT mask; HTREEITEM hItem; UINT state; UINT stateMask; LPSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int cChildren; LPARAM lParam; } TV_ITEM, FAR *LPTV_ITEM; ISLab ICE HUFS MFC Tutorial 465 TV_ITEM(2) • mask – – – – – – – TVIF_CHILDREN TVIF_HANDLE TVIF_IMAGE TVIF_PARAM TVIF_SELECTEDIMAGE TVIF_STATE TVIF_TEXT cChildren 필드를 사용한다. hItem 필드를 사용한다. iImage 필드를 사용한다. lParam 필드를 사용한다. iSelectedImage 필드를 사용한다. state, stateMask 필드를 사용한다. pszText, cchTextMax 필드를 사용한다. • hItem : 이 스트럭처가 나타내고 있는 항목 – 새로운 항목의 삽입 시에는 0을 지정해야 ISLab ICE HUFS MFC Tutorial 466 TV_ITEM(3) • pszText : 항목에 들어갈 텍스트 – LPSTR_TEXTCALLBACK이면 항목의 디스플레이 책임은 부모 윈 도우가 진다. 이때 부모 윈도우에게 TVN_SETDISPINFO 메시지가 넘어간다. • cchTextMax : pszText 필드가 가리키는 버퍼의 크기 ISLab ICE HUFS MFC Tutorial 467 TV_ITEM(4) • iImage : 정상상태에 있을 때에 해당하는 이미지(이미지 리스트에서의 인덱스) • iSelectedImage : 선택상태에 있을 때에 해당하는 이미지 • cChildren : 자식 항목을 가질 것인지 여부를 지정 – 0 : 자식 항목이 없음 – 1 : 자식 항목이 있음 • lParam : 이 항목과 관련해서 따로 저장하고 싶은 32비트 값을 지정할 때 사용 ISLab ICE HUFS MFC Tutorial 468 트리뷰의 알림 메시지 TVN_BEGINDRAG TVN_BEGINRDRAG TVN_BEGINLABELEDIT TVN_ENDLABELEDIT TVN_DELETEITEM TVN_ITEMEXPANDING TVN_ITEMEXPANDED TVN_KEYDOWN TVN_SELCHANGING TVN_SELECTED 왼쪽 마우스버튼을 이용해 드래그 작업이 시작할 때 발생한다. 오른쪽 마우스 버튼을 이용해 드래그 작업이 시작 할 때 발생한다. 레이블 편집이 시작될 때 발생 레이블 편집이 끝날 때 발생 항목이 삭제될 때 발생 항목 하나가 펼쳐져야 함을 알리기 위해 발생 항목 하나가 펼쳐졌음을 알리기 위해 발생 키가 눌렸을 때 발생. 이는 트리뷰 컨트롤이 입력 포커스를 갖고 있을 때 발생한다. 현재 선택된 항목이 다른 항목으로 변경될 때 발생 현재 선택된 항목이 다른 항목으로 변경된 다음 발생 ISLab ICE HUFS MFC Tutorial 469 NM_DBLCLK BEGIN_MESSAGE_MAP(CCmmCtrlView, CView) //{{AFX_MSG_MAP(CCmmCtrlView) .... //}}AFX_MSG_MAP ON_CONTROL(ACN_STOP, IDC_ANIMATE, OnAnimateStop) ON_WM_HSCROLL() ON_NOTIFY(LVN_ITEMCHANGED, IDC_LISTCTRL, OnListCtrlClick) ON_NOTIFY(NM_DBLCLK, IDC_TREECTRL, OnTreeCtrlDblClick) END_MESSAGE_MAP() void CCmmCtrlView::OnTreeCtrlDblClick(NMHDR * pNotifyStruct, LRESULT * result) { HTREEITEM hItem = m_wndTreeCtrl.GetSelectedItem(); if (m_treeRoot == hItem) AfxMessageBox("루트가 더블 클릭되었군요."); *result = 0; } ISLab ICE HUFS MFC Tutorial 470