박 상 원 swpark@hufs.ac.kr 한국외국어대학교 정보통신공학과 Windows Programming 박 상 원 swpark@hufs.ac.kr 한국외국어대학교 정보통신공학과
서론
목차 객체지향이란? MFC의 역사 MFC를 위한 C++의 기초 MFC Tutorial
객체지향 개념의 등장 배경 프로그래밍 언어의 발전 함수 기반 프로그래밍 소프트웨어의 위기 객체지향 개념의 등장 기계어 -> 어셈블리어 -> 고급언어 함수 기반 프로그래밍 1970년대 - 1980년대 소프트웨어의 위기 생산성 향상의 한계 객체지향 개념의 등장 1980년대 MFC Tutorial
객체지향이란? 객체 메쏘드 호출 메시지 이벤트 MFC Tutorial
객체지향의 핵심 내용(1) 객체란 추상 데이타 타입(ADT;abstract data type) 계승(inheritance) 데이타(자료구조; 상태변수)와 오퍼레이터(함수)가 하나로 묶여있는 형태 추상 데이타 타입(ADT;abstract data type) 클래스를 이용하여 표현 계승(inheritance) 동적 바인딩(dynamic binding) cf) Static binding 다형성(polymorphism) Overloading : 동일한 함수의 이름 사용 가능 Overriding : 상위 클래스에서 정의된 함수를 하위 클래스에서 재 정의 Template : 타입을 인자로 하여 새로운 타입을 생성 MFC Tutorial
MFC를 위한 C++의 기초 클래스 계승 생성자 및 소멸자 Virtual Function을 이용한 동적 바인딩 MFC Tutorial
클래스란? 객체를 기술할 수 있는 수단을 제공 모델링 실세계 컴퓨터세계 자료 구조 (member data) 오퍼레이션 (member function) 모델링 실세계 컴퓨터세계 MFC Tutorial
클래스의 계승(1) 계승을 통한 코드의 재 사용 가능 이름 충돌(name conflict) 발생 다중 계승의 문제점 생산성 향상 이름 충돌(name conflict) 발생 다중 계승의 문제점 virtual base class로 계승 MFC Tutorial
클래스의 계승(2) A int x; B int y; C int z; D int z; class B : virtual public A { ... }; class C : virtual public A A int x; B int y; C int z; D int z; MFC Tutorial
생성자(1) 생성자(constructor) 호출 메모리 할당과 생성자는 별개 메모리 할당 new : 힙(heap)에 객체 생성 지역변수 : 스택(stack)에 객체 생성 전역변수 : 프로그램 코드 영역에 객체 생성 생성자는 메모리 할당이 끝난 객체의 각 데이타 부분을 초기화하는 역할 MFC Tutorial
생성자(2) A int m_nNo B char* ptr A* pA = new B(3); 3 500 500 힙/스택/코드 영역 A::A(int n) : m_nNo(n) { } B::B(int i) : A( i ) ptr = new char[ i ]; A int m_nNo B char* ptr A* pA = new B(3); 3 500 500 힙/스택/코드 영역 힙 (heap) 영역 MFC Tutorial
소멸자(1) 소멸자(destructor)의 virtual 함수화 소멸자는 객체 자체의 메모리 영역을 없애는 것이 아님 그 객체가 new 등을 이용하여 실행중에 만든 객체를 메모리에서 없애는 역할을 한다. MFC Tutorial
소멸자(2) 3 500 500 접근못하는 메모리 힙/스택/코드 영역 (garbage) 힙 (heap) 영역 A* ptr = new A; delete ptr; ptr = new B(3); delete ptr; <- 문제 발생. A의 소멸자만 불린다. 3 500 500 접근못하는 메모리 (garbage) 힙/스택/코드 영역 힙 (heap) 영역 MFC Tutorial
Virtual Function(1) 동적 바인딩(dynamic binding) 정적 바인딩(static binding) 프로그램의 수행 중에 실제 수행할 함수를 결정 vitual function table(hidden pointer) 정적 바인딩(static binding) MFC Tutorial
Virtual Function(2) DrawObj DrawObj* p_obj; p_obj = new Point; p_obj->Draw(); p_obj = new Line; p_obj = new PolyLine; int a virtual Draw() Point Line int x, y Point start, end virtual Draw() virtual Draw() virtual Calc() PolyLine Point[5] pt virtual Draw() MFC Tutorial
Virtual Function - 메모리 구조 p_obj = new DrawObj; p_obj->Draw(); p_obj = new PolyLine; p_obj->Draw(); 50 250 100 350 430 vtbl 50 vtbl 180 virtual function table int a int a 180 550 430 Point start Point end p_obj = new Line; p_obj->Draw(); Point[0] pt 250 DrawObj::Draw Point[1] pt pointer of virtual function table 350 vtbl 100 Point[2] pt Line::Draw int a Point[3] pt 430 Line::Calc Point start Point[4] pt Point end 550 PolyLine::Draw Code 영역 MFC Tutorial
Virtual Function 사용 예 List Line Point Line PolyLine Point CObList list; DrawObj* p_obj; p_obj = new Line; list.AddTail(p_obj); p_obj = new Point; . . . . POSITION pos = list.GetHeadPosition(); while(pos != NULL) { p_obj = (DrawObj*)list.GetNext(pos); p_obj->Draw(); } List Line Point Line PolyLine Point MFC Tutorial
MFC 기초
목차 SDK와 MFC의 비교 MFC 클래스 종류 AppWizard를 이용한 프로젝트 생성 Develop Studio 사용법 Hungarian 표기법 MFC Tutorial
Windows API Applicatoin Programming Interface Windows System Calls Win16 API Windows 95/NT Win32 API C 라이브러리 MFC Tutorial
SDK 프로그래밍 SDK(Software Development Kit) 윈도우 프로그래밍을 위한 여러 가지 툴과 라이브러리로 구성되어 있는 마이크로소프트에 의해 발표된 소프트웨어 패키지 윈도우 프로그래밍시 호출하여 사용할 수 있는 함수들이 포함 (윈도우 API) C 라이브러리 MFC Tutorial
메시지와 메시지 큐 메시지(message)? 메시지 큐(queue) 윈도우에서 발생하는 사건들의 표현 숫자 (winuser.h) 메시지 큐(queue) 하나의 프로그램에 하나씩 할당 윈도우에 사건이 발생하면 운영체제는 이를 메시지로 만들어 발생 순서대로 메시지 큐에 넣는다. MFC Tutorial
메시지 루프, 윈도우 프로시저 메시지 루프 윈도우 프로시저 메시지 큐에서 메시지를 하나씩 꺼내어 거기에 맞게 처리 메시지의 실제 처리 운영체제 응용 프로그랭 메시지를 하나씩 읽어다가 이를 처리할 윈도우의 윈도우 프로시저를 호출한다. MFC Tutorial
메시지에 의한 동작 Message-driven operations msg 메시지 큐 윈도우에 사건이 발생하면 int WinMain(HINSTANCE ......) { . . . InitApplication(hInstance); InitInstance(hInstance); while(GetMessage(....)) DispatchMessage(. . .); } 윈도우에 사건이 발생하면 운영체제는 이를 메시지로 만들어 발생 순서대로 메시지 큐에 넣는다. msg 메시지 큐 함수 MFC Tutorial
SDK 프로그램의 예 #include “windows.h” // SDK의 API와 각종 상수, 구조체가 정의된 헤더 화일 #include “generic.h” // 이 프로그램 내에서 사용할 상수가 정의되고 함수가 // 선언된 헤더 화일 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)) // 메인 윈도우를 생성한다. MFC Tutorial
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); // 메시지 루프에 진입한다. while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam); MFC Tutorial
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); // 이 윈도우 클래스를 등록한다. } MFC Tutorial
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; } MFC Tutorial
윈도우 스타일(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 윈도우에 수직 스크롤바를 붙여 생성한다. MFC Tutorial
윈도우 스타일(2) WS_POPUP 팝업 윈도우를 생성한다. 이것은 WS_CHILD와 함께 사용될 수 없다. WS_CLIPSIBLINGS 같은 레벨의 자식 윈도우간에 겹치는 영역이 있을 때 각각의 자식 윈도우가 다른 겹치는 자식 윈도우 의 영역으로 넘어가지 못하도록 한다. 이 스타일을 주지 않았을 경우 자식 윈도우끼리 겹칠 때 이상하 게 그려지는 상황이 발생할 수 있다. WS_CLIPCHILDREN 자식 윈도우가 차지하는 영역은 부모 윈도우의 영 역에서 제외된다. 부모 윈도우를 생성할 경우 주어 야 한다. #define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION \ | WS_SYSMENU | WS_THICKFRAME \ | WS_MINIMIZEBOX | WS_MAXIMIZEBOX) MFC Tutorial
윈도우 프로시저 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); MFC Tutorial
case WM_DESTROY: // 윈도우가 없어지기 직전에 발생하는 메시지 { PostQuitMessage(0); break; } default: // 처리하지 못한 메시지를 넘긴다. return DefWindowProc(hWnd, message, wParam, lParam); return 0; MFC Tutorial
generic.h & resource.h generic.h resource.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 MFC Tutorial
generic.rc #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS #include "afxres.h" #undef APSTUDIO_READONLY_SYMBOLS // Korean resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_KOR) #ifdef _WIN32 LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT #pragma code_page(949) #endif //_WIN32 // Menu EX_Menu MENU DISCARDABLE BEGIN POPUP "File" MENUITEM "Exit", ID_FILE_EXIT END #ifdef APSTUDIO_INVOKED #endif // Korean resources #ifndef APSTUDIO_INVOKED // Generated from the TEXTINCLUDE 3 resource. #endif // not APSTUDIO_INVOKED MFC Tutorial
핸들(Handle) 무엇인가를 구별하기 위해 붙인 번호 핸들 타입 앞에는 H가 붙는다. UINT로부터 재정의 예) 윈도우 핸들 (HWND) 윈도우가 여러 개 존재할 경우 이를 구별하기 위해 윈도우마다 번호를 하나씩 부여 핸들 타입 앞에는 H가 붙는다. UINT로부터 재정의 #define UINT HANDLE #define HANDLE HWND MFC Tutorial
타입 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으로부터 재정의. 메시지에 수반되는 부가 정보 표시 MFC Tutorial
주요 메시지(1) WM_CREATE 윈도우가 생성될 때 발생한다. 정확히 말하면 CreateWindow API가 호출되었을 때 발생한다. 이 메시지 처리부에서 초기화 작업을 수행하는 것이 일반적이다. 아직 윈도우가 보이지 않는다. WM_SIZE 윈도우의 크기가 변화하면 발생. 이 메시지가 발생하면 그 뒤에 WM_PAINT가 따라서 발생한다. WM_PAINT 윈도우의 사용자 영역이 가려졌다가 앞으로 나온다든가 해서 다시 그려질 일이 생기면 발생하는 메시지이다. InvalidateRect와 같은 API로 발생시키는 것도 가능하다. WM_COMMAND 사용자가 메뉴에서 명령을 선택하면 발생 WM_CLOSE 사용자가 윈도우의 시스템 메뉴에서 닫기(Close)를 택하면 발생. DefWindowProc 함수는 WM_CLOSE 메시지를 받으면 WM_DESTROY 메시지를 발생 MFC Tutorial
주요 메시지(2) WM_DESTROY 윈도우가 없어지기 직전에 발생한다. 여기서는 앞 서 윈도우 프로시저의 실행중에 할당한 자원들이 있다면 이를 운영체제에 반환하는 역할을 수행함. 메인 윈도우의 WM_DESTROY 메시지 처리부에서 는 끝부분에서 PostQuitMessage 함수를 호출하는 것이 일반적이다. WM_QUIT PostQuitMessage 함수를 호출하면 이 메시지가 만 들어져 메시지 큐에 들어가게 된다. 메시지 루프에 서 이 메시지를 읽어가면 GetMessage 함수의 리턴 값이 FALSE가 되기 때문에 메시지 루프가 끝나게 되고 프로그램이 종료된다. MFC Tutorial
MFC란 클래스 라이브러리 애플리케이션 프레임워크(application framework) 클래스의 집합 (함수의 집합이 아님) 애플리케이션 프레임워크(application framework) AppWizard ClassWizard Project Workspace MFC Tutorial
MFC 구조 응용프로그램 MFC SDK API 운영체제 MFC는 SDK API의 기능을 구분하여 클래스 계층구조를 입힌 것 “Handle”은 분류의 기준이 됨 응용프로그램 MFC SDK API 운영체제 MFC Tutorial
왜 MFC 인가? 이해가 쉬움 코드의 재사용성 향상 소프트웨어 개발의 용이성 연관된 함수와 데이타를 “클래스”를 이용하여 그룹화하였음 코드의 재사용성 향상 소프트웨어 개발의 용이성 애플리케이션 프레임워크(application framework) 제공 멤버 함수 나열 코드 삽입의 용이성 MFC Tutorial
Handle을 이용한 분류 - SDK(1) RECT rc; GetClientRect(hWnd, &rc); MoveWinodw(hWnd, x, y, x2, y2, TRUE); MFC Tutorial
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); MFC Tutorial
Handle을 이용한 분류 - SDK(2) HDC hDC = GetDC(hWnd); Rectangle(hDC, 10, 10, 100, 100); TextOut(hDC, 10, 10, “Sample”, 6); ReleaseDC(hWnd, hDC); MFC Tutorial
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); MFC Tutorial
SDK - 자원 획득 및 반환 SDK { HDC hDC; hDC = GetDC(hWnd); // 자원 획득 Rectangle(hDC,10,10,100,100); TextOut(hDC,10,10,“Sample”,6); ReleaseDC(hWnd, hDC); // 반드시 자원을 반환해야 한다. } MFC Tutorial
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를 해제한다. MFC Tutorial
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); MFC Tutorial
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 = a + b; c.right = a.right + b.right; c.top = a.top + b.top; c.bottom = a.bottom + b.bottom; MFC Tutorial
MFC 클래스 종류 일반 목적의 클래스 윈도우 API 클래스 애플리케이션 프레임워크 클래스 고 수준 추상화 클래스 운영체제 확장 클래스 MFC Tutorial
일반 목적의 클래스 CObject : 모든 클래스의 상위 클래스 예외 처리 클래스 콜렉션(collection) 클래스 CException, CArchiveException, CFileException, CMemoryException, CNotSupportedException, COleException, CDBException, CResourceException, CUserException 콜렉션(collection) 클래스 CByteArray, CWordArray, CDWordArray, CPtrArray, CObArray, CStringArray, CUintArray CObList, CPtrList, CStringList CMapPtrToWord, CMapPtrToPtr, CMapStringToOb, CMapStringToPtr, CMapStringToString, CMapWordToOb, CMapWordToPtr 동적 문자열 클래스 Cstring 파일 클래스 CFile, CStdioFile, CMemFile 시간 및 시간 간격(time span) 클래스 CTime, CTimeSpan 그외 CPoint, CSize, CRect등 MFC Tutorial
윈도우 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 등) MFC Tutorial
윈도우 API 클래스 (2) 다이얼로그 다이얼로그 DDX/DDV 콘트롤 클래스 GDI 및 그림 관련 클래스 CFileDialog, CColorDialog, CFontDialog, CPrintDialog, CFindReplaceDialog 다이얼로그 DDX/DDV CDataExchange 콘트롤 클래스 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 MFC Tutorial
애플리케이션 프레임워크 클래스 문서/뷰 관련 클래스 문맥 지원 도움말(context-sensitive help) CDocTemplate, CSingleDocTemplate, CMultiDocTemplate CDocument, Cview 문맥 지원 도움말(context-sensitive help) MFC Tutorial
고 수준 추상화 클래스 확장된 뷰(enhanced view) 분리 윈도우 콘트롤 바 CScrollView, CFormView 콘트롤 뷰 : CEditView, CListView, CRichEditView, CTreeView 분리 윈도우 CSplitterWnd 콘트롤 바 CControlBar CToolBar, CStatusBar, CDialogBar MFC Tutorial
운영체제 확장 클래스 (1) OLE 지원 OLE Document 클래스 팩토리(class factories) 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 MFC Tutorial
운영체제 지원 클래스(2) ODBC 지원 DAO 지원 MAPI 지원 Winsock 지원 펜 윈도우 지원 CDatabase, CRecordset, CFiledExchange, CLongBinary, CRecordView DAO 지원 CDaoWorkspace, CDaoDatabase, CDaoRecordset, CDaoRecordView, CDaoQueryDef, CDaoTableDef, CDaoException, CDaoFiledExchange MAPI 지원 Winsock 지원 CAsyncSocket, Csocket 펜 윈도우 지원 CHEdit, CBEdit 제한 : 16 비트 환경 MFC Tutorial
코드 재 사용 방법 Component Gallery MFC 확장 AppWizard 응용 프로그램 Custom MFC MFC Tutorial
AppWizard를 통한 Project 생성(1) Project 생성 (project 이름: Obedit) New 메뉴 (MFC AppWizard (.exe) Database, OLE 메뉴 None Multiple document 선택 MFC Tutorial
AppWizard를 통한 Project 생성(2) Advanced Options File extension : obe File type ID: Obedit.Document Main frame caption: Obedit Doc type name: Obedit Filter name: Obedit Files(*.obe) File new name: Obedit File type name: Obedit Document MFC library 사용 방법 As a shared DLL (MFC42.DLL 필요) Base class 선택 CObeditView 클래스의 상위 클래스로 CScrollView 선택 MFC Tutorial
Developer Studio Project Workspace 작업 영역 클래스 뷰(class view) 리소스 뷰(resource view, AppStudio 대신) 파일 뷰(file view) 인포 뷰(info view) 작업 영역 source code browser / wizard bar / resource editor online help MFC Tutorial
클래스 뷰/파일 뷰/리소스 뷰 MFC Tutorial
클래스 뷰(class view) 클래스에 함수 및 멤버 추가 특정 위치로 커서 이동 계승 관계 표시 클래스 이름에 마우스 커서를 위치시킨 후 오른쪽 버튼을 클릭 멤버 함수 추가 멤버 변수 추가 특정 위치로 커서 이동 계승 관계 표시 MFC Tutorial
파일 뷰(file view) 프로젝트에 있는 화일들을 열거 프로젝트에서 화일 삭제 (.net) 솔루션 탐색기 MFC Tutorial
Hungarian 표기법 Type Prefix 예 비고 char c cDirSeperator BOOL b bIsSending int n nVariableCount UINT n nMyUnsignedInt WORD w wListID LONG l lAxisRatio DWORD dw dwPackedmessage * (pointer) p pWnd FAR * lp lpWnd LPSTR lpsz lpszFileName z는 NULL로 끝남을 handle h hWnd 의미 callback lpfn lpfnHookProc 함수 포인터 MFC Tutorial
Hungarian 표기법 - MFC 확장 Type Prefix 예 CRect rect rectScroll CPoint pt ptMouseClick CSize sz szRectangle CString str strFind CWnd Wnd WndControl CWnd * pWnd pWndDialog MFC Tutorial
Hungarian 표기법 - Symbol Type Prefix 예 범위 여러 리소스에서 공유 IDR_ IDR_MAINFRAME 1-0x6FFF Dialog 리소스 IDD_ IDD_ABOUT 1-0x6FFF Dialog 리소스 Help context ID HIDD_ HIDD_HELP_ABOUT 0x2001- 0x26FF (for context-sensitive help) 비트맵 리소스 IDB_ IDB_SMILEY 1-0x6FFF 커서 리소스 IDC_ IDC_HAND 1-0x6FFF 아이콘 리소스 menu, toolbar command ID_ ID_CIRCLE_TOOL 0x8000-0xDFFF Command help context HID_ HID_CIRCLE_TOOL 0x1800-0x1DFF Message box prompt IDP_ IDP_FATALERROR 8-0xDFFF Message box help context HIDP_ HIDP_FATALERROR 0x3008-0x3DFF String 리소스 IDS_ IDS_ERROR12 1-0x7FFF 다이얼로그 템플릿의 control IDC_ IDC_COMBO1 8-0xDFFF MFC Tutorial
MFC의 기본 구조 이해
MFC의 철학(1) 예제 프로그램 컴파일 후 수행 화일 선택시 일반적인 절차에 대한 코딩 Open 메뉴 선택 화일 오픈 다이얼로그 박스를 띄운다. 사용자의 입력을 받아 해당 화일을 연다. 만일 MDI 프로그램이면 자식 윈도우를 하나 연다. SDI 프로그램이라면 전에 갖고 있던 자료 구조를 해제한다. 화일을 프로그램의 정의에 맞게 해석하여 읽어들인다. 즉 화일의 내용을 메모리 상의 자료구조로 변환한다. 읽어들인 내용을 윈도에 그린다. 이 부분의 구현은 대개 윈도를 무효화(invalidate)하여 이루어진다. MFC Tutorial
MFC의 철학(2) 실제 사용자가 해야 할 일 (3번) 장점 에러의 가능성 감소 프로그래밍 시간 및 노력 감소 MFC Tutorial
CDocument class CDocument : public CCmdTarget { ... void OnFileOpen(); // 파일오픈 명령을 실행하면 불려진다. BOOL GetOpenFileName(LPCTSTR); // 다이얼로그를 띄워 파일이름을 입력 // 화일 입출력을 담당하는 함수 (pure virtual function) virtual void Serialize(CFile cfile) = 0; CWnd* GetWindow(); // 현재 문서의 내용을 보여주는 윈도우 포인터를 리턴 } MFC Tutorial
CDocument::OnFileOpen void CDocument::OnFileOpen() { CString szFileName; // CString은 문자배열에 해당하는 클래스 if (!GetOpenFileName(szFileName)) // 다이얼로그 박스를 띄워 파일이름을 return; // 입력받는다. CFile cfile(szFileName); // CFile은 MFC에서 화일 I/O를 담당 cfile.Open(); // 화일을 오픈한다. Serialize(cfile); // 화일의 내용을 읽어들인다(user가 작성) cfile.Close(); // 화일을 닫는다. CWnd* pWnd = GetWindow(); // 이 문서의 내용을 보여주는 윈도의 핸들을 pWnd->Invalidate(NULL); // 얻어 그 내용을 그리도록 WN_PAINT 메시지 // 발생 } MFC Tutorial
CMyDocument 클래스 // CDocument는 실제 바로 사용하지 못함(MFC class) // 계승하여 사용하여야 class CMyDocument : public CDocument { // My data structure int m_nNumOfObjects; Objects obj[100]; public: void Serialize(CFile cfile); // virtual function }; MFC Tutorial
WinMain int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (!hPrevInstance) // 처음으로 실행되는 경우에는 InitApplication(hInstance); // 윈도우 클래스를 등록한다. InitInstance(hInstance); // 메인 윈도우를 생성한다. while(GetMessage(....)) // 메시지 루프 .... DispatchMessage(...); // 메시지를 윈도우 프로시저로 나눔 } // 프로그램이 종료되기 전에 청소 작업을 행한다. return msg.wParam; MFC Tutorial
MFC의 WinMain MFC\SRC\winmain.cpp CWinApp 클래스에 존재 CWinApp::InitApplication CWinApp::InitInstance CWinApp::Run CWinApp::ExitInstance InitInstance, ExitInstance 만 override 하여 사용 가능 가상 함수의 중요성 MFC Tutorial
SDI CObeditApp -> CWinApp CMainFrame -> CMDIFrameWnd CObeditDoc -> CDocument CObeditView -> CView MFC Tutorial
MDI CObeditApp -> CWinApp CMainFrame -> CMDIFrameWnd CChildFrame -> CMDIChildWnd CObeditDoc -> CDocument CObeditView -> CView MFC Tutorial
Document/View 구조 문서클래스 뷰클래스 2. 그 내용을 반영한다. 1. 사용자의 입력을 받는다 3. 윈도우로 출력한다. MFC Tutorial
전체 구조 CWinApp CDocument CView 하나의 document에는 여러 개의 view가 연관될 수 있음 하나의 응용 프로그램을 가리키는 클래스 CDocument 응용 프로그램의 자료구조를 저장하는 클래스 CView 응용 프로그램의 모습을 화면에 출력하는 클래스 하나의 document에는 여러 개의 view가 연관될 수 있음 예) 탐색기, Visual C++ 에디터 창 MFC Tutorial
CObeditApp 클래스 class CObeditApp : public CWinApp { public: //{{AFX_VIRTUAL(CObeditApp) virtual BOOL InitInstance(); // 프로그램의 초기화 //}}AFX_VIRTUAL //{{AFX_MSG(CObeditApp) afx_msg void OnAppAbout(); ... //}}AFX_MSG MFC Tutorial
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; MFC Tutorial
RegisterShellFileTypes(TRUE); // 화일의 icon, 확장자 등록 ... RegisterShellFileTypes(TRUE); // 화일의 icon, 확장자 등록 CCommandLineInfo cmdInfo; ParseCommandLine(cmdInfo); if (!ProcessShellCommand(cmdInfo)) return FALSE; pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->UpdateWindow(); return TRUE; } MFC Tutorial
Obedit.ini 화일 [Recent File List] File1=D:\obedit\step8\new.OBE File2=D:\obedit\step7\test4.OBE MFC Tutorial
레지스트리 작업 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 ); MFC Tutorial
레지스트리 void CObeditApp::LoadStdProfileSettings() { // 나름대로 초기화 값을 읽어다 저장한다. // GetProfileInt... // CWinApp::LoadStdProfileSettings(); // 선조 함수 호출 } MFC Tutorial
윈도우 생성 WM_CREATE OnCreate 함수 호출 MFC Tutorial
CMainFrame 클래스 class CMainFrame : public CMDIFrameWnd { DECLARE_DYNAMIC(CMainFrame) .... protected: CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; //{{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //}}AFX_MSG DECLARE_MESSAGE_MAP() // 메시지 맵 }; MFC Tutorial
OnCreate 함수 MFC Tutorial
MFC MDI 프로그램의 윈도우 구조 MDI 메인 윈도우 MDI 클라이언트 윈도우 MDI 자식 윈도우 뷰 윈도우 타이틀 파일 편집 MDI 클라이언트 윈도우 타이틀 MDI 자식 윈도우 뷰 윈도우 MFC Tutorial
CObeditView 클래스 MFC Tutorial class CObeditView : public CView { .... CObeditDoc* GetDocument(); // 뷰에 연결된 문서객체의 포인터 반환 //{{AFX_VIRTUAL(CObeditView) 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 MFC Tutorial
주요 CView 멤버함수 GetDocument 뷰와 연계된 문서 오브젝트에 대한 포인터를 돌려준다. AddDocTemplate 함수를 통해 m_pDocument 멤버는 MFC가 뷰를 생성할 때 알아서 초기화 OnInitialUpdate 뷰가 처음 만들어질 때 호출된다. OnDraw 뷰와 연계된 문서오브젝트의 내용을 윈도우 위에 그려준다. OnPrint 뷰와 연계된 문서오브젝트의 내용을 프린터로 출력 OnUpdate 문서오브젝트의 내용이 변경되었을 때 문서오브젝트 쪽에 불러준다. MFC Tutorial
CObeditDoc 클래스 class CObeditDoc : public CDocument { .... //{{AFX_VIRTAUL(CObeditDoc) public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); // file I/O //}}AFX_VIRTUAL }; MFC Tutorial
주요 CDocument 멤버 함수 IsModified 문서오브젝트의 내용이 마지막으로 저장된 후에 변경된 적이 있는지 알려준다. SetModifiedFlag 문서오브젝트의 내용이 변경되었음을 표시했다. UpdateAllViews 문서오브젝트의 내용이 바뀌었을 때 이 내용을 연계된 뷰에게 알려준다. 이 안에서는 뷰클래스의 OnUpdate 함수를 부른다. DeleteContent 문서오브텍트가 닫힐 때 불려진다. 이 때 문서오브젝트 의 청소 작업을 해야 한다. OnNewDocument 사용자가 File 메뉴의 New 명령을 수행하면 불린다. OnOpenDocument 사용자가 File 메뉴의 Open 명령을 수행하면 불린다. OnSaveDocument 사용자가 File 메뉴의 Save 명령을 수행하면 불린다. OnCloseDocument 사용자가 File 메뉴의 Close 명령을 수행하면 불린다. MFC Tutorial
모든 뷰 수정 Document class는 자신과 연관이 있는 view object를 리스트의 형태로 관리 View에서 수정 CPtrList m_viewList View에서 수정 Document 수정 UpdateAllViews 호출 MFC Tutorial
UpdateAllViews 뷰는 실제로 사용자와 가장 많은 접촉을 하는 윈도우이다. 그런 사용자의 조작은 프로그램이 유지해야 할 데이터의 변경을 가져오게 마련이다. 따라서 뷰는 데이터를 변경하기 위해 문서오브젝트에 대한 포인터를 필요로 하게 된다. 바로 GetDocument로 문서오브젝트에 대한 포인터를 얻어 자료구조를 변경한다. 뷰오브젝트는 문서오브젝트의 멤버 함수를 이용해 간접적으로 변경하거나 직접 문서오브젝트의 데이터멤버를 수정한다. 물론 전자의 방법이 좋다. 그리고 나서 이를 모든 뷰에 반영하기 위해 문서클래스의 UpdateAllViews라는 멤버함수를 직접 부른다. 그러면 UpdateAllViews라는 문서클래스의 함수는 자신이 내부적으로 유지하고 있는 뷰의 리스트를 뒤져 각 뷰의 OnUpdate함수를 호출한다. 만일 뷰와 문서오브젝트 사이의 관계가 1:1이라면 굳이 UpdateAllViews 함수를 부를 필요가 없다. 단순히 Invalidate같은 함수를 불러 화면을 갱신하거나 직접 화면을 갱신하면 그만이다. 각 뷰의 OnUpdate 함수는 문서오브젝트의 내용을 읽어 화면출력 등에 맞게 변경해주면 된다. OnUpdate 함수의 디폴트 코딩은 Invalidate 함수를 불러 화면을 다시 그리는 것으로 되어 있다. 위의 표는 뷰와 문서오브젝트간의 일반적인 연동 과정을 정리한 것이다. MFC Tutorial
UI 붙이기
메뉴 작성 File Object View Window Help New Line Toolbar New Window About Open Ellipse Status Bar Cascade Time Close Rectangle Color Bar Title Save --------- ---------- Arrange Icons Save As… Pen Attribute Zoom ---------- Print Print Preview Print Setup… Send Summary Info Recent File Exit MFC Tutorial
메뉴 리소스 작성 리소스 뷰에서 IDR_MAINFRAME(child window가 없을 때) IDR_OBEDITTYPE MFC Tutorial
메뉴 작성 풍선 도움말 MEMU ID 단축키 &Line ID_OBJECT_LINE Draw a line\nLine &Ellipse ID_OBJECT_ELLIPSE Draw a ellipse\nEllipse &Rectangle ID_OBJECT_RECTANGLE Draw a rectangle\nRectangle &Pen Attribute ID_OBJECT_PENATTR Change the attribute of a pen\nPen &Color Bar ID_VIEW_COLORBAR Show or hide color palette &Zoom\tCtrl+Z ID_VIEW_ZOOM Set zoom ratio ID_SEPARATOR(분리자 메뉴) MEMU ID 단축키 MFC Tutorial
단축키 작성 리소스 뷰의 Accelerator 이용 MFC Tutorial
아이콘 변경 MFC Tutorial
툴바의 수정 리소스 뷰에서 IDR_MAINFRAME MFC Tutorial
배율 설정 새로운 ToolBar 생성 MFC Tutorial
MyToolBar.h 수정 Class CMyToolBar : public CToolBarCtrl -> CToolBar로 수정 (.net에서는 바로 선택) { // Construction public: CMyToolBar(); // Attributes . . . . MFC Tutorial
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() MFC Tutorial
MainFrm.h 수정 #include “MyToolBar.h” // 추가 class CMainFrame : public CMDIFrameWnd { DECLARE_DYNAMIC(CMainFrame) public: CMainFrame(); . . . . protected: CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; -> CMyToolBar m_wndToolBar로 수정 MFC Tutorial
리소스 파일 obedit.rc 텍스트를 리소스 뷰에서 그래픽으로 나타냄 리소스 편집의 편리 MFC Tutorial
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 BUTTON ID_OBJECT_PENATTR BUTTON ID_FILE_PRINT BUTTON ID_APP_ABOUT SEPARATOR // 12번째 스태택바 붙일 위치 (0부터 세어서) SEPARATOR // 14번째 스태틱컨트롤을 붙일 위치 END 툴바의 버튼 뒤에 스크롤바가 자리잡을 곳을 마련하는 것이다. 이것은 툴바의 뒤에 ID_SEPARATOR를 붙여야 하는데 이것이 쉽지 않을 것이다. 가장 확실한 방법은 Obedit.rc를 에디터로 올려 직접 편집하는 것이다. File 메뉴의 Open 명령으로 Obedit.rc를 작업윈도우로 올린다. 이때 주의할 점은 파일 오픈 다이얼로그에서 Open As를 “Text”로 주어야 한다는 것이다. 그렇게 않하면 항상 RC 파일이 리소스뷰로 오픈될 것이다. 그런 다음 위와 같은 SEPARATOR를 네 개만 붙인다. 넷은 별 의미는 없다. 적당한 간격을 두고 스크롤바와 스태틱 콘트롤을 생성하기 위해서이다. 맨 마지막에 있는 SEPARATOR는 위에서부터 세었을 때 15번째이다(0부터 세어서). 13번째 SEPARATOR가 바로 스크롤 바를 붙일 자리이고 15번째 SEPARATOR가 스태틱 콘트롤을 붙일 자리이다. MFC Tutorial
MainFrame에 변수 추가 CMainFrame에 멤버 추가 CScrollBar m_zoomScroll; CStatic m_zoomStatic MFC Tutorial
CMainFrame::OnCreate 수정 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { . . . EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); CRect rect; // 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; 80 픽셀 Resource Symbol로 등록 MFC Tutorial
Resource Symbol로 등록 // 스태택 컨트롤 추가 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; return 0; } Resource Symbol로 등록 MFC Tutorial
리소스 심볼 등록 심볼 등록 #define ID_ZOOMSCROLL 101 // 리소스 심볼을 등록하는 것과 왼쪽과 같이 // 정의하는 것은 동일한 효과임 심볼 등록 MFC Tutorial
생성된 모습 MFC Tutorial
CToolBar 클래스의 주요 함수 CommandToIndex 버튼 ID를 주면 툴바의 좌측부터 세어 그에 해당하는 인덱스를 준다. 0부터 센다. GetItemID CommandToIndex와는 반대로 버튼의 인덱스로부터 버튼 ID를 얻어준다. Create 툴바를 생성한다. EnableDocking 도커블 툴바로 동작할 수 있도록 설정하며 프로임 윈도우의 어느 곳에 붙을 수 있는지도 명시한다. GetBarStyle 툴바의 스타일을 얻어온다. SetBarStyle 툴바의 스타일을 설정한다. GetButtonInfo 특정 버튼에 대한 정보를 얻어온다. SetButtonInfo 특정 버튼의 정보를 변경한다. GetCount 툴바 버튼의 총수를 얻어온다(SEPARATOR 포함). GetItemRect 버튼 ID를 주면 그 버튼의 툴바에서의 위치를 돌려준다. LoadBitmap 버튼 모양을 담고 있는 비트맵을 로드한다. SetHeight 툴바의 버튼 높이를 변경한다. SetSizes 툴바의 크기를 변경한다. MFC Tutorial
상태바(Status Bar) 생성 순서 CStatusBar 오브젝트를 만든다. CStatusBar 오브젝트의 Create 함수를 호출하여 상태바 윈도우를 생성 SetIndicator 함수를 호출하여 각 텍스트 출력창과 스트링 ID를 연결시킨다. static UINT indicators[ ] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; MFC Tutorial
클래스 위저드 클래스 이름 메뉴 가상함수 메시지 이미 만든 함수들 MFC Tutorial
Pane 텍스트 수정 SetWindowText 함수로 텍스트 갱신 Command UI 핸들러의 SetText 함수 호출 void CMainFrame::OnUpdateIndicatorTime(CCmdUI* pCmdUI) { pCmdUI->SetText(“Pane에 출력”); } SetPaneText 함수 이용 CStatusBar bar; bar.SetPaneText(0, “Pane에 출력”); MFC Tutorial
상태바의 수정(1) indicators 변수 수정(MainFrm.cpp) static UINT indicators [] = { ID_SEPARATOR, // status line indicator ID_SEPARATOR, // 추가 ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; MFC Tutorial
상태바의 수정(2) CMainFrame 클래스의 OnCreate 함수 수정 1은 상태바의 두 번째 창을 가리킨다. 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 등록 MFC Tutorial
시간 출력 클래스 위저드를 이용하여 명령 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); } 이벤트 발생시 마다 매번 함수 호출 MFC Tutorial
MFC의 주요 전역 함수 AfxGetApp 프로그램을 대표하는 프로그램 오브젝트에 대한 포인터를 돌려준다. AfxGetAppName 프로그램의 이름을 돌려준다. AfxGetInstanceHandle 프로그램의 인스턴스 핸들을 돌려준다. AfxGetMainWnd 메인 프레임 윈도우 오브젝트에 대한 포인터를 돌려준다. GetCurrentMessage 현재 처리 중인 메시지에 대한 메시지 스트럭처를 돌려준다. 메시지 핸들러 등에서 메시지 스트럭처 를 직접 접근하고 싶을 때 이용한다. AfxSocketInit 윈도우 소켓을 초기화하기 위해 부른다. AfxBeginThread 새로운 스레드를 시작한다. AfxEndThread 현재의 스레드를 끝낸다. AfxGetThread 현재 실행 중인 스레드에 대한 포인터 (CWinThread)를 돌려준다. MFC Tutorial
컬러 바 클래스 생성 클래스 위저드에서 새로운 클래스 생성 Add Class/New에서 CMyColorBar 클래스 생성 상위 클래스로 CToolBarCtrl을 선택 MyColorBar.cpp, MyColorBar.h에서 CToolBarCtrl을 CToolBar로 수정 정확한 색 선택: Image 메뉴의 Adjust Colors... 선택 후 숫자로 색 입력 MFC Tutorial
툴바 리소스 생성 리소스 뷰에서 새로운 Toolbar 생성 버튼의 자료구조 (MyColorBar.cpp에 정의) COLORREF color[16] = { RGB( 0, 0, 0), RGB(255,255,255), RGB(192,192,192), RGB(128,128,128), RGB(255, 0, 0), RGB(255,255, 0), RGB( 0,255, 0), RGB( 0,255,255), RGB( 0, 0,255), RGB(255, 0,255), RGB(128, 0, 0), RGB(128,128, 0), RGB( 0,128, 0), RGB( 0,128,128), RGB( 0, 0,128), RGB(128, 0,128) }; MFC Tutorial
색깔 선택 Image 메뉴 Adjust Colors... MFC Tutorial
ColorBar 생성 #include “MyColorBar.h” class CMainFrame : public CMDIFrameWnd { DECLARE_DYNAMIC(CMainFrame) ... protected: CToolBar m_wndToolBar; CMyColorBar m_wndColorBar; }; MFC Tutorial
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; MFC Tutorial
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(); MFC Tutorial
도형 처리 추가
사용자 클래스 디자인 CDrawObject CLine CEllipse CRectangle MFC Tutorial
사용자 클래스 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; // 도형의 위치를 나타낸다. WORD m_wObjType; // 이 오브젝트의 타입을 가리킨다. 이 타입을 가리키는 // 값은 밑에 있는 enum ObjectType의 objectLine, // objectRectangle, objectEllipse 중의 하나가 // 될 수 있다. MFC Tutorial
objectLine, objectEllipse, objectRectangle }; virtual ~CDrawObject(); enum ObjectType { objectLine, objectEllipse, objectRectangle }; virtual ~CDrawObject(); virtual void DrawObject(CDC *pDC) = 0; // pure virtual function virtual void SetStartPoint(CPoint pt) {m_rcRdct.TopLeft() = pt;} virtual void SetEndPoint(CPoint pt) {m_rcRect.BottomRight()=pt;} virtual CPoint& GetStartPoint() { return m_rcRect.TopLeft(); } virtual CPoint& GetEndPoint() { return m_rcRect.BottomRight(); } virtual void GetBoundingRect(CRect *pRect); virtual void Serialize(CArchive& ar); #ifdef _DEBUG virtual void AssertValid() const; // 유효성 여부 검사 virtual void Dump(CDumpContext& dc) const; // 객체의 내용을 디버그 // 윈도우로 #endif MFC Tutorial
class CLine : public CDrawObject { protected: DECLARE_SERIAL(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 }; MFC Tutorial
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 }; MFC Tutorial
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 }; MFC Tutorial
m_rcRect.SetRectEmpty(); } CDrawObject::~CDrawObject() #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); MFC Tutorial
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 MFC Tutorial
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); } MFC Tutorial
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 MFC Tutorial
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); } MFC Tutorial
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 MFC Tutorial
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); } MFC Tutorial
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 MFC Tutorial
GDI (Graphic Device Interface) 윈도우 운영체제에서의 출력 응용 프로그램 WIN32 API GDI (Graphic Device Interface) 디바이스 드라이버 실제 출력 장치 MFC Tutorial
DirectX 윈도우 3.1의 그래픽 출력 속도 저하 극복을 위해 DirectDraw DirectPlay DirectSound 게임 (WinG) DirectDraw DirectX의 그래픽 부분 라이브러리 DirectPlay 네트워크 게임을 만드는데 사용할 수 있는 라이브러리 DirectSound 사운드 기능을 제공해 주는 라이브러리 DirectInput 조이스틱 등의 제어에 사용할 수 있는 라이브러리 MFC Tutorial
디바이스 컨텍스트 Device Context 윈도우 운영체제에서 출력 대상을 지칭하는 것 논리적으로 볼 때 붓, 펜, 팔레트, 종이(비트맵), 폰트 등의 그림을 그리기 위한 도구의 집합 장치와 문관하게 GDI 함수 호출 가능 붓과 펜은 DC 내에 하나씩 존재 GetDC & ReleaseDC MFC Tutorial
DC의 종류 CClientDC CWindowDC CPaintDC 윈도우의 클라이언트 영역 윈도우 전체 디바이스 컨텍스트 윈도우의 경계선, 캡션 영역 등에도 그리기 가능 CPaintDC WM_PAINT 발생시에 사용 MFC Tutorial
출력할 장치의 디바이스 컨텍스트의 핸들을 얻는다. 윈도우 운영체제에서의 출력 절차 출력할 장치의 디바이스 컨텍스트의 핸들을 얻는다. GDI로 앞에서 얻은 핸들에 출력을 행한다. 디바이스 컨텍스트를 제거한다. MFC Tutorial
SDK에서의 붓과 펜의 변경 절차 1. 펜이나 붓을 생성한다(CreatePen, CreateSolidBrush). 2. 디바이스 컨텍스트를 얻는다(GetDC나 BeginPaint). 3. 2에서 얻은 디바이스149 컨텍스트의 드로잉 툴을 1에서 만든 드로잉 툴로 바꾼다(SelectObject). 교체하면서 원래 들어있던 펜이나 붓을 기억해야. 4. GDI를 이용해 출력 작업을 수행한다. 5. 3에서 기억해 놓았던 원래의 붓이나 펜을 원상복구 시킨다(SelectObject). 6. 디바이스 컨텍스트를 윈도우 운영체제로 반환한다. 7. 1에서 만든 펜이나 붓을 삭제한다(DeleteObject). MFC Tutorial
CDC 클래스의 주요 함수(1) CreateCompatibleDC 인자로 주어진 DC와 같은 속성을 갖는 DC를 메모리에 만든다. GetSafeHdc 현재 오브젝트가 둘러싸고 있는 디바이스 컨텍스트 핸들을 돌려준다. IsPrinting 프린트 DC인지 아닌지의 여부를 돌려준다. SetROP2 그리기모드를 변경하는데 사용된다. SetBkColor 글자출력 시의 배경색을 지정한다. SetTextColor 글자출력 시의 글자색을 지정한다. MoveTo, LineTo 직선을 긋는데 사용한다. Arc, ArcTo 원호를 그리는데 사용한다. PolyDraw 직선과 베지어 스프라인을 연속적으로 그림 PloyLine 직선을 연속적으로 그리는데 사용 Polygon 직선을 연속적으로 그리는데 처은 점과 마지막 점을 잇는다 MFC Tutorial
CDC 클래스의 주요 함수(2) PolyBezier 베이어 스프라인을 연속적으로 그리는데 사용 InvertRect 주어진 영역을 반전하는데 사용한다. DrawIcon 주어진 위치에 주어진 아이콘을 그려준다. Draw3dRect 입체적인 사각형을 그리는데 사용한다. Ellipse 타원(원 포함)을 그리는데 사용한다. Pie 부채꼴을 그리는데 사용한다. Rectangle 사각형을 그리는데 사용한다. RountRect 모서리가 둥근 사각형을 그리는데 사용한다. SetPixel 점을 찍는데 사용한다. BitBlt 한 디바이스 컨텍스트의 내용을 다른 디바이스 컨텍스트로 복사한다. TextOut 주어진 위치에 텍스트를 출력한다. DrawText 주어진 사각형 내에 텍스트를 출력한다. MFC Tutorial
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; // 현재 선택된 도형이 무엇인지 나타낸다. }; MFC Tutorial
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; } MFC Tutorial
메뉴 선택 코드 추가 클래스 위저를 통한 메뉴 함수 구현 MFC Tutorial
메뉴 선택 함수 void CObeditView::OnObjectLine() { m_wCurDrawObject = CDrawObject::objectLine; } void CObeditView::OnObjectRectangle() m_wCurDrawObject = CDrawObject::objectRectangle; void CObeditView::OnObjectEllipse() m_wCurDrawObject = CDrawObject::objectEllipse; MFC Tutorial
메뉴의 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); pCmdUI->SetCheck(m_wCurDrawObject == DrawObject::objectRectangle); MFC Tutorial
칼라 메뉴 void CObeditView::OnPalettecolor1() // 컬러 팔레트 메뉴 함수. 16번 반복 { m_nSelectedColorID = 0; m_crCurColor = color[0]; } void CObeditView::OnUpdatecolor1(CCmdIO* pCmdUI) pCmdUI->SetCheck(m_nSelectedColorID == 0); MFC Tutorial
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() MFC Tutorial
윈도우의 입력 메시지 종류 하드웨어적인 이유로 발생하는 메시지 키보드 메시지나 마우스 메시지를 해석하여 발생하는 메시지 키보드 타이머 키보드 메시지나 마우스 메시지를 해석하여 발생하는 메시지 캐릭터 스크롤 바 메뉴 MFC Tutorial
키보드 입력 메시지 종류 가상 키 코드 (virtual keycode) - lParam WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP 가상 키 코드 (virtual keycode) - lParam 비트 0 - 15 키의 반복 횟수 비트 16 - 23 키의 스캔 코드 (키보드 제조업체에 따라 다를 수 있다) 비트 24 확장 키 여부 (1 : 확장키, 0 : 아님) 비트 25 - 26 쓰이지 않음 비트 27 - 28 윈도우 운영체제가 내부적으로 사용 비트 29 컨텍스트 코드 (1 : Alt 키가 눌림, 0 : 안 눌림) 비트 30 키의 이전 상태 (1 : 키가 눌려져 있었음, 0 : 아님) 비트 31 키의 현재 전환 상태 (1 : 키가 떼어지는 것, 0 : 눌려지는 것) MFC Tutorial
문자 입력 메시지 종류 메시지 발생 순서 인자 WM_CHAR, WM_SYSCHAR 아스키 코드가 있을 때(SDK에서는 TranslateMessage 함수가 반드시 불려야 WM_KEYDOWN --> WM_CHAR --> WM_KEYUP 아스키 코드가 없을 때(예 : ENTER) WM_KEYDOWN --> WM_KEYUP 인자 wParam : 아스키 코드 lParam : WM_KEYDOWN, WM_KEYUP에서와 같음 MFC Tutorial
마우스 메시지의 처리 마우스 이벤트의 종류 넘어오는 좌표 : Pixel 단위 WM_LBUTTONDBLCLK WM_LBUTTONDOWN WM_LBUTTONUP WM_MOUSEMOVE WM_RBUTTONDBLCLK WM_RBUTTONDOWN WM_RBUTTONUP 넘어오는 좌표 : Pixel 단위 MFC Tutorial
마우스 메시지와 윈도우 1 t1에서 t2 사이에는 1번 윈도우로 마우스 메시지가 발생하고, t1 메시지가 발생한다. t1 t2 t3 2 마우스 커서의 이동 자취 MFC Tutorial
드래그시의 문제점 SetCapture, ReleaseCapture 1. 드래그 시작 2. 윈도우 바깥으로 나가면 마우스 메시지가 이 윈도우에게로 발생하지 않는다. MFC Tutorial
타이머 입력 메시지 종류 주기적으로 하고 싶은 일이 있을 때 사용되는 메시지 SetTimer, KillTimer WM_TIMER 주기적으로 하고 싶은 일이 있을 때 사용되는 메시지 예) 워드프로세서에서 주기 저장, 테트리스 게임에서 적당 시간 간격으로 블록을 떨어뜨릴 때 SetTimer, KillTimer MFC Tutorial
타이머 설정 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; } MFC Tutorial
WM_TIMER 메시지 처리 함수 CMainFrame이 아닌 다른 클래스에서 불릴때 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(); // 다른 클래스에서 MFC Tutorial
타이머 해제 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) MFC Tutorial
타이머 사용시 주의점 PC 타이머 칩이 발생시키는 최소 시간 간격 : 55 밀리초 메시지 큐에서 약간의 지연 발생 WM_TIMER 메시지 처리가 늦어지면 메시지가 쌓여 큐가 넘칠 수 있으므로 메시지 큐에서는 하나의 WM_TIMER 만 가능 (WM_PAINT도 마찬가지) MFC Tutorial
스크롤 바 입력 메시지 종류 WM_VSCROLL, WM_HSCROLL SB_PAGEUP SB_PAGEDOWN SB_LINEUP SB_LINEDOWN MFC Tutorial
메뉴 입력 메시지 종류 단축키 사용 가능 ASCII vs. VIRTKEY WM_COMMAND, WM_SYSCOMMAND MFC Tutorial
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); case CDrawObject::objectEllipse : m_pCurDrawObject = new CEllipse(m_crCurColor, m_nPenStyle, m_nPenWidth); } m_pCurDrawObject->SetStartPoint(point); // 객체의 시작위치 저장 m_pCurDrawObject->SetEndPoint(point); SetCapture(); // 모든 마우스 메시지가 CObeditView 객체로 온다. // 마우스 메시지 독점. 마우스 드래그를 지원하기 위해 } // ReleaseCapture 호출 때까지 MFC Tutorial
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 } MFC Tutorial
LButtonUp void CObeditView::OnLButtonUp(UINT nFlags, CPoint point) { if (GetCapture() == this) CClientDC dc(this); m_pCurDrawObject->SetEndPoint(point); m_pCurDrawObject->DrawObject(&dc); ReleaseCapture(); // 마우스 독점 해제 } MFC Tutorial
윈도우에서의 화면 복구 1 1 1 2 2 2 1번 윈도우에 의해 가려 졌던 2번 윈도우가 클릭 된다. 가려졌던 영역이 일단 WM_ERASEBKGND 메시지에 의해 지워진다. WM_PAINT 메시지에 의해 가려졌던 영역이 복구된다. MFC Tutorial
WM_PAINT 화면을 복구하는데 사용 윈도우가 처음 생성될 때도 한번 발생 새로 그려야 할 영역 고려 윈도우로 출력하는데 사용되는 메시지가 아니다. 윈도우가 처음 생성될 때도 한번 발생 새로 그려야 할 영역 고려 MFC Tutorial
WM_PAINT - SDK SDK에서 반드시 BeginPaint / EndPaint 함수를 이용하여야 한다. 그려야 할 영역을 PAINTSTRUCT 인자로 알 수 있기 때문 HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hWnd, &ps); // ps.rcPaint에 복구 영역의 좌표가 들어있다. // 이 부분만 딱 그려줄 수 있다면 가장 이상적이다. EndPaint(hWnd, &ps); MFC Tutorial
WM_PAINT OnDraw 함수 호출 void CView::OnPaint() { CPaintDC dc(this); OnPrepareDC(&dc); OnDraw(&dc); } MFC Tutorial
자료 구조 유지 다시 그리기 위한 자료 구조 유지 class CObeditDoc : public CDocument { .... // Attributes public: CObList m_objectList; } MFC Tutorial
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); } MFC Tutorial
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); } MFC Tutorial
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(); case WM_DESTROY : OnDestroy(); 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 } }; MFC Tutorial
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)) .... MFC Tutorial
MFC에서의 메시지 처리(2) CWnd 대부분의 메시지는 거의 모두 Default()를 부름 _AFXWIN_INLINE afx_msg int CWnd::OnCreate(LPCREATESTRUCT) { return (int)Default(); // DefWindowProc()을 부름 } 대부분의 메시지는 거의 모두 Default()를 부름 MFC Tutorial
명령 경로 배정(command routing) WM_COMMAND, WM_UPDATE_COMMAND_UI CCmdTarget로부터 계승받은 클래스만 받을 수 있다. 메뉴 처리 CWnd가 아닌 CDocument, CView에서 처리하는 것이 자연스러움 예) 화일 저장, 색 선택 MFC Tutorial
CCmdTarget 클래스 CObject CCmdTarget CWinApp CDocTemplate CWnd CDocument CMultiDocTemplate CSingleDocTemplate CFrameWnd CView CDialog MFC Tutorial
Routing 순서 Comand를 받은 오브젝트 routing 순서 프레임 윈도우 1. 활성화된 자식윈도우 혹은 뷰 프레임 윈도우 1. 활성화된 자식윈도우 혹은 뷰 2. 자기 자신 3. CWinApp 오브젝트 뷰(View) 1. 자기 자신 2. 자신과 연관된 문서오브젝트 문서(Document) 1. 자기 자신 2. 이 문서가 속한 문서템플릿 다이얼로그 1. 자기 자신 2. 이 다이얼로그를 소유한 윈도우 오브젝트 MFC Tutorial
CCmdUI의 멤버 함수 멤버함수 이름 기능 Enable 메뉴 항목의 상태를 활성화시키거나 그레이 상태로 만든다. 멤버함수 이름 기능 Enable 메뉴 항목의 상태를 활성화시키거나 그레이 상태로 만든다. SetCheck 메뉴 항목의 옆에 체크 표시를 만든다. 툴바 버튼의 경우에는 눌려진 상태로 표시한다. SetRadio 기능 자체는 SetCheck와 같은데 체크 표시 대신에 표시를 사용한다. SetText 메뉴 항목의 텍스트를 변경한다. 툴바 버튼에 대해서는 별 의미가 없다. MFC Tutorial
메시지 맵 매크로(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); MFC Tutorial
등록된 메시지(2) 등록된 메시지 콘트롤로부터의 알림(notification) 메시지 RegisterWindowMessage 함수를 이용해 메시지 값을 만든 경우 ON_REGISTERED_MESSAGE, 함수의 인자는 사용 자 정의 메시지와 동일 콘트롤로부터의 알림(notification) 메시지 ON_CONTROL(알림코드, 컨트롤ID, 처리함수 이름) void 처리함수이름(void); MFC Tutorial
사용자 정의 메시지 종류 메시지 전달 방법 WM_USER(0x7fff) 부터 SendMessage PostMessage 메시지를 발생시켜 해당 윈도우에서 그 메시지의 처리가 끝난 다음에야 리턴 PostMessage 메시지를 해당 윈도우가 소속된 메시지 큐에 집어넣고 바로 리턴 메시지 부가 인자로 다량의 데이타를 보낼 때는 사용자 데이타 타입을WPARAM이나 LPARAM로 캐스팅해서 보낸다. MFC Tutorial
사용자 정의 메시지 예 #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; ... } MFC Tutorial
메시지맵 매크로 종류 ON_COMMAND_RANGE ON_COMMAND_EX ON_UPDATE_COMMAND_UI_RANGE ON_CONTROL_RANGE MFC Tutorial
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() MFC Tutorial
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); MFC Tutorial
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); } MFC Tutorial
GDI 객체 GDI 객체 종류 GDI 존속기간 CBitmap, CBrush, CFont, CPalette, Cpen, CRgn 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)); MFC Tutorial
폰트 설정 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; } MFC Tutorial
스크롤 기능
목차 매핑 모드 좌표계 스크롤 기능 스크롤 바 논리 물리 좌표간 변환 MFC Tutorial
Mapping Mode 매핑 모드(mapping mode) MM_TEXT 윈도우 출력함수(GDI)에서 출력좌표를 해석하는 방법 디바이스 컨텍스트(device context)마다 존재 디폴트 매핑 모드는 MM_TEXT MM_TEXT 출력 원점이 윈도우 클라이언트 영역의 좌측 상단 출력 원점에서 X 좌표는 오른쪽으로 증가, Y 좌표는 아래 방향으로 증가 단위 : 픽셀(pixel) 단점 : 해상도에 따라 출력되는 내용의 크기가 달라진다. 예) 프린트 MFC Tutorial
Mapping Mode의 종류 매핑모드 단위 X 방향증가 Y방향증가 MM_TEXT 픽셀 오른쪽 아래쪽 MM_LOMETRIC 0.1 mm 오른쪽 위쪽 MM_HIMETRIC 0.01 mm 오른쪽 위쪽 MM_LOENGLISH 0.1 in 오른쪽 위쪽 MM_HIENGLISH 0.01 in 오른쪽 위쪽 MM_TWIPS 1/1440 in 오른쪽 위쪽 MM_ISOTROPIC 지정가능 지정가능 지정가능 MM_ANISOTROPIC 지정가능 지정가능 지정가능 MM_ISOTROPIC, MM_ANISOTROPIC 을 이용하여 화면 확대/축소 가능 MFC Tutorial
MM_TWIPS 프린터에 가장 많이 사용 1 twip은 1/20 포인트에 해당 (1포인트는 1/72 인치에 해당) 예 : 12포인트 문자 12 X 20 = 240 트윕 MFC Tutorial
매핑 모드의 변경 CDC 클래스의 SetMapMode 함수 이용 테스트중입니다.-1 500 CClientDC dc(this); dc.SetMapMode(MM_LOMETRIC); dc.TextOut(100, 500, “테스트중입니다.-1”); dc.TextOut(100, -500, “테스트중입니다.-2”); 테스트중입니다.-1 500 윈도우 밖으로 출력되어 보이지 않는다. 500 테스트중입니다.-2 100 MFC Tutorial
좌표계 디바이스(device) 좌표 논리(logical) 좌표 디바이스 좌표와 논리 좌표간의 변환이 필요 실제 출력 장치의 좌표 논리(logical) 좌표 출력함수에 사용하는 좌표 디바이스 좌표와 논리 좌표간의 변환이 필요 DPtoLP LPtoDP MFC Tutorial
좌표계의 원점 이동 SetWindowOrg SetViewportOrg 논리 좌표의 원점 이동 디바이스 좌표의 원점 이동 MFC Tutorial
(0,0) 1 cm 1 cm CClientDC dc(this); dc.SetMapMode(MM_LOMETRIC); dc.MoveTo(0,0); dc.LineTo(100, -100); (0,0) 1 cm 1 cm MFC Tutorial
(0,0) (100,100) 1 cm 1 cm 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 MFC Tutorial
변경된 원점 1 cm (0,0) 1 cm 1 cm 1 cm 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 MFC Tutorial
좌표계 사이의 좌표 변환 DPtoLP LPtoDP 디바이스 좌표를 현재 사용중인 매핑모드에 맞춰 논리 좌표로 변환 논리 좌표를 현재 사용중인 매핑모드에 맞춰 디바이스 좌표로 변환 예) 마우스 커서의 위치를 논리 좌표로 변환하는 경우 마우스 좌표는 디바이스 좌표와 동일한 특성을 갖는다. 즉 윈도우 클라이언트 영역의 좌측 상단을 기준으로 픽셀 단위의 좌표가 넘어온다. MFC Tutorial
단위 길이 계산 SetWindowExt / GetWindowExt SetViewportExt / GetViewportExt MFC Tutorial
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); } MFC Tutorial
SetScrollSize OnInitialUpdate 함수 SetScrollSize 뷰 오브젝트가 생성된 뒤에 바로 호출되는 함수 SetScrollSize void CScrollView::SetScrollSize(int nMapMode, SIZE sizeTotal, const SIZE& sizePage, const SIZE& sizeLine); 편집 문서의 크기, 매핑모드, 스크롤 작업의 크기를 알림 스크롤 작업의 크기 스크롤 바를 눌렀을 때 얼마나 스크롤할 것인지 그 양을 말함 실행 중에 매핑모드에 변경이 생기면 그때마다 SetScrollSize를 호출하여 변경사항을 반드시 반영해야 함 sizePage : PageDown을 눌렀을 때. 디폴트 값 = 문서 크기의 1/10 sizeLine : 스크롤 라인. 디폴트 값 = 문서 크기의 1/100 MFC Tutorial
문서 크기의 지정 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()); MFC Tutorial
스크롤 바 문서 영역 엄지(thumb) 현재 뷰가 보여주고 있는 부분이 편집문서에서 어디에 위치한 것인가 현재 보이는 부분이 전체적으로 볼 때 어느 정도의 부분을 차지하는지 비례 스크롤바(proportional scrollbar) MFC Tutorial
출력 원점의 보정 스크롤이 일어나면 편집 문서와 출력함수의 원점이 달라짐 이와 같은 일을 CScrollView가 알아서 한다. SetViewportOrg, SetWindowOrg을 이용하여 두 원점을 하나로 만듬 즉 CDC 클래스의 출력함수에서 사용하는 출력원점을 편집 문서의 원점으로 이동시킴 항상 편집 문서의 원점을 바탕으로 한 좌표를 사용하도록 하면 좌표의 변환없이 문서의 좌표를 그대로 출력에 이용할 수 있음 이와 같은 일을 CScrollView가 알아서 한다. MFC Tutorial
편집문서 500 100 윈도우 100 500 300 300 MFC Tutorial
마우스 좌표와 논리 좌표의 충돌 마우스가 넘겨주는 좌표 편집문서의 좌표 뷰 전체문서 MFC Tutorial
LButtonDown void CObeditView::OnLButtonDown(UINT nFlags, CPoint point) { CClientDC dc(NULL); OnPrepareDC(&dc); // 오브젝트의 매핑 모드와 원점을 현재의 스크롤 상태에 // 맞게 변환 // 즉 1. 매핑 모드 변환 // 2. 스크롤 바의 엄지 값을 읽어 그만큼 출력 장치의 // 원점을 뒤로 이동 dc.DPtoLP(&point); // 좌표 단위의 변환 및 원점의 위치까지 고려하여 좌표 // 좌표 변환 수행 // 즉, 마우스 좌표를 편집 문서의 원점으로부터의 // 좌표로 변환 switch(m_wCurDrawObject) case CDrawObject::objectLine : .......... } MFC Tutorial
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); } MFC Tutorial
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); } MFC Tutorial
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); MFC Tutorial
화면 확대/축소 기능
목차 익스텐트(extent)란? 배율 설정 다이얼로그 만들기 DDX/DDV SDK와의 비교 MFC Tutorial
익스텐트(extent)란 특정 매핑 모드에서의 단위 길이 MM_ISOTROPIC MM_ANISOTROPIC 현재 논리 좌표와 디바이스 좌표의 단위 길이를 구하거나 새로 설정 가능 논리 좌표와 디바이스 좌표는 단위 길이가 다를 수 있다. 익스텐트(extent) 조절 GetWindowExt 논리 좌표의 단위 길이 구함 GetViewportExt 디바이스 좌표의 단위 길이 구함 SetWindowExt 논리 좌표의 단위 길이 설정 SetViewportExt 디바이스 좌표의 단위 길이 설정 MFC Tutorial
간단한 배율 설정 방법 배율 : N% 단점 실수 연산 시 발생할 수 있는 값의 오차 문제 코드의 복잡도 증가 CClientDC dc(this); dc.MoveTo(100, 100); dc.LineTo(300, 400); dc.MoveTo((int)(float)100*N/100, (int)(float)100*N/100); dc.LineTo((int)(float)300*N/100, (int)(float)400*N/100); 단점 실수 연산 시 발생할 수 있는 값의 오차 문제 코드의 복잡도 증가 MFC Tutorial
익스텐트 조절을 통한 배율 디바이스좌표 = 논리좌표 X ED / EL ED : 디바이스 좌표의 단위 길이 CClientDC dc(this); dc.SetViewportExt(N, N); dc.SetWindowExt(100, 100); // 좌표 X N / 100 dc.MoveTo(100, 100); dc.LineTo(300, 400); MFC Tutorial
View 수정 CObeditView 클래스에 멤버 변수로 배율 추가 class CObeditView : public CScrollView { .... UINT m_zoomRatio; }; CObeditView::CObeditView() m_nSelectedColorID = 0; m_crCurColor = color[m_nSelectedColorID]; m_zoomRation = 100; // 초기값으로 100% 설정 } MFC Tutorial
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); } 익스텐트의 값을 음수로 주면 그림의 방향이 반대가 된다. MFC Tutorial
다이얼로그 박스 만들기 리소스 뷰에서 새로운 다이얼로그 추가 IDD_ZOOMDLG Spin Control의 Properties IDC_EDITZOOM IDC_SPINZOOM MFC Tutorial
다이얼로그 클래스 생성 클래스 위저드 이용 MFC Tutorial
DDX/DDV MFC Tutorial
데이타 맵 class CZoomDlg : public CDialog { ...... // Dialog Data //{{AFX_DATA(CZoomDlg) enum { IDD = IDD_ZOOMDLG }; CSpinButtonCtrl m_spinZoom; UINT m_editZoom; //}}AFX_DATA }; MFC Tutorial
DoDataExchange OnInitDialog에서 컨트 다이얼로그박스호출 롤의 값을 설정한다. 전에 값을 설정 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에서 컨트롤 의 값을 읽어온다. 다이얼로그박스의 실행이 정상적으로 끝나면 값을 읽어온다. MFC Tutorial
UpdateData UpdateData 함수를 이용하여 DoDataExchange 함수 호출 인자 TRUE : 컨트롤의 값을 데이타맵의 변수로 읽어옴 FALSE : 데이타맵의 변수 값을 컨트롤로 설정 MFC Tutorial
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; } MFC Tutorial
CSpinButtonCtrl SetBuddy 스핀 콘트롤이 증감시킨 값을 표시할 윈도우를 지정 GetDlgItem 함수를 이용하여 콘트롤 객체의 포인터를 구함 SetRange 스핀 콘트롤로 입력할 수 있는 최대값, 최소값을 지정 SetBase 스핀 콘트롤이 버디 윈도우에 값을 출력할 때 그 값의 형식 16이면 16진수, 10이면 십진수 SetPos 스핀 콘트롤에 표시할 값을 지정 MFC Tutorial
OnOK 클래스 위저드를 이용하여 함수 생성 가능 UpdateData 호출을 해야 한다. 생성시 UpdateDate(TRUE)를 OK 버튼이 눌려지면 UpdateData(FALSE)를 호출하여야 하나 이것은 모두 상위 클래스인 CDialog에 만들어져 있으므로 하위 클래스에서 생성하지 않아도 된다. MFC Tutorial
배율 메뉴 추가 메뉴 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(); } MFC Tutorial
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); } MFC Tutorial
Dialog 생성 방법 모든 다이얼로그는 CDialog로 부터 계승 생성 방법 Resource view에서 dialog template 생성 Class Wizard 호출 Control로부터의 노티피케이션(notification) 메시지 처리 각각의 다이얼로그 박스 컨트롤에서 입력되는 값 저장 및 컨트롤에서의 값을 읽어 오는 데이터 멤버도 만듦 (DDX) 데이타 값의 범위 지정 가능 (DDV) MFC Tutorial
Modal/Modeless Modal Modeless DoModal 함수 호출 Create 함수 호출 Dialog box를 resource view에서 그릴 때 dialog box의 프로퍼티로 VISIBLE을 반드시 주어야 한다. MFC Tutorial
SDK에서의 다이얼로그 생성 방법 IDD_TESTDIALOG IDOK IDCANCEL IDC_NUMBER MFC Tutorial
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 //{{AFX_MSG(CTestDialog) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; MFC Tutorial
GetDlgItem - 값 설정 반드시 cast 연산자 사용 SetFocus : 윈도우에 입력 포커스 설정 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 : 윈도우에 입력 포커스 설정 MFC Tutorial
GetDlgItem - 값 읽기 void CTestDialog::OnOK() { CString szStr; ((CEdit*)GetDlgItem(IDC_NUMBER))->GetWindowText(szStr); m_wInputVal = atoi(szStr); CDialog::OnOK(); // UpdateData(TRUE) 호출 // EndDialog(IDOK) 호출 } MFC Tutorial
SDK Dialog 사용시 { . . . CTestDialog testDlg(this); testDlg.m_wInputVal = nVal; if (testDlg.DoModal() == IDOK) nVal = testDlg.m_wInputVal; } MFC Tutorial
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); MFC Tutorial
모드리스 다이얼로그 생성 Visible 세팅 MFC Tutorial
DDX/DDV 사용시 MFC Tutorial
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 .... } MFC Tutorial
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 } MFC Tutorial
DDX/DDV 매크로 DDX_CBIndex, DDX_CBString, DDX_CBStringExact 콤보 박스 관련 DDX_LBIndex, DDX_LBString, DDX_LBStringExact 리스트 박스 관련 DDX_Check 체크 박스 관련 DDX_Radio 라디오 박스 관련 DDX_Scroll 스크롤바 관련 DDX_Text DDX_Control 에디트 콘트롤 관련 MFC Tutorial
다이얼로그 클래스 CDialog CCommonDialog CFileDialog CFontDialog CColorDialog CFindReplaceDialog CPrintDialog CPageSetupDialog MFC Tutorial
배율 설정 기능의 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); MFC Tutorial
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()); } MFC Tutorial
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); } MFC Tutorial
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; MFC Tutorial
case SB_RIGHT : nCurPos = nMax; break; case SB_LINELEFT : case SB_LINERIGHT : nCurPos += 10; case SB_PAGELEFT : nCurPos -= 50; case SB_PAGERIGHT : nCurPos += 50; case SB_THUMBTRACK : case SB_THUMBPOSITION : nCurPos = nPos; } MFC Tutorial
if (nCurPos < nMin) nCurPos = nMin; else if (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(); } MFC Tutorial
마우스 커서의 변환 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; MFC Tutorial
기타 Dialog Box 구현
목차 Owner Draw List Box Property Sheet MFC Tutorial
Owner-Draw List Box 펜 속성을 선택하는 dialog 각 펜의 모양을 그림으로 list box에 표현 MFC Tutorial
펜 속성 지정 다이얼로그 Static. IDC_STATIC Spin. IDC_SPINWIDTH Edit Box. IDC_EDITWIDTH Spin. IDC_SPINWIDTH List Box. IDC_LISTSTYLE 비트맵이 들어가기 때문 MFC Tutorial
CPenAttrDlg CPenAttrDlg 클래스 생성 Member Variable - Class Wizard m_editWidth Value UINT m_listStyle Control CListBox m_spinWidth Control CSpinButtonCtrl MFC Tutorial
CLineStyleListBox 클래스 생성 CListBox로부터 계승 Owner-Draw List Box를 위하여 다음 함수를 재정의 CompareItem 정렬의 대상이 명확하지 않기 때문에 이를 비교하기 위한 함수 DrawItem 리스트 박스의 항목을 그릴 때 각 항목마다 호출되는 함수 MeasureItem 항목의 높이를 정하기 위해 각 항목마다 호출되는 함수 MFC Tutorial
MeasureItem #define COLOR_ITEM_HEIGHT 20 void CLineStyleListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItem) { lpMeasureItem->itemHeight = COLOR_ITEM_HEIGHT; } MFC Tutorial
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); } MFC Tutorial
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)) MFC Tutorial
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; } MFC Tutorial
DRAWITEMSTRUCT typedef struct tagDRAWITEMSTRUCT { UINT CtlType; // Owner-Draw 리스트 박스의 경우에는 ODT_LISTBOX가 들어옴 UINT CtlID; // Control ID가 들어온다. UINT itemID; // List box에서 몇 번째 항목인지를 나타내는 인덱스가 들어옴 UINT 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라면 // 여기에 텍스트가 들어가게 된다. } DRAWITEMSTRUCT; MFC Tutorial
리스트 박스에 항목 추가 InsertString AddString 오너드로인 경우 그 항목을 그릴 때 사용할 수 있는 값을 줌 절렬 순서에 관계없이 항목을 지정한 곳에 넣는다. AddString 정렬한 다음에 리스트 박스에 추가 CompareItem 함수를 호출하여 정렬하게 된다. 오너드로인 경우 그 항목을 그릴 때 사용할 수 있는 값을 줌 예제에서는 펜의 스타일을 인자로 사용 직접 데이타 맵을 수정해야 MFC Tutorial
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 MFC Tutorial
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; } MFC Tutorial
OnOK void CPenAttrDlg::OnOK() { int index = m_listStyle.GetCurSel(); m_lineStyle = (UINT)m_listStyle.GetItemData(index); CDialog::OnOK(); } MFC Tutorial
메뉴 처리 함수 생성 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; } MFC Tutorial
Property Sheet 여러 개의 Property Page로 하나의 Property Sheet를 생성 MFC Tutorial
파일 정보 다이얼로그 생성 Static. IDC_APPNAME Edit. IDC_KEYWORDS Edit. IDC_AUTHOR List Box. IDC_COMMENTS Edit. IDC_TITLE Edit. IDC_SUBJECT IDD_SUMM_PAGE MFC Tutorial
Dialog Properties MFC Tutorial
CSummaryPage 클래스 생성 상위 클래스로 CPropertyPage 선택 Member Variables (Class Wizard) IDC_APPNAME m_AppName Value CString IDC_AUTHOR m_Author Value CString IDC_COMMENTS m_Comments Value CString IDC_KEYWORDS m_Keywords Value CString IDC_SUBJECT m_Subject Value CString IDC_TITLE m_Title Value CString MFC Tutorial
파일 통계 다이얼로그 IDC_REVNUM IDC_EDITTIME IDC_LASTPRINT IDC_CREATEDATE IDC_LASTSAVE MFC Tutorial
CFileStatPage 클래스 생성 상위 클래스로 CPropertyPage 선택 Member Variables (Class Wizard) IDC_CREATEDATE m_CreateDate Value CString IDC_EDITTIME m_EditTime Value CString IDC_LASTPRINT m_LastPrint Value CString IDC_LASTSAVE m_LastSave Value CString IDC_REVNUM m_RevNum Value CString MFC Tutorial
Document 클래스에 멤버 추가 class CObeditDoc : public CDocument { . . . CString m_AppName; CString m_Author; CString m_Comments; CString m_Keywords; CString m_Subject; CString m_Title; CString m_CreateDate; UINT m_EditTime; CString m_LastPrint; CString m_LastSave; UINT m_RevNum; CTime m_StartTime; MFC Tutorial
생성자 CObeditDoc::CObeditDoc() { m_sizeDoc = CSize(500, 500); m_AppName = _T(“도형편집기”); // 유니코드 혹은 ANSI 문자열 } MFC Tutorial
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; } MFC Tutorial
Property Sheet 생성 CPropertySheet 하나 이상의 Property Page로 구성 각 PropertyPage 객체를 AddPage 함수를 이용하여 등록 MFC Tutorial
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; MFC Tutorial
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; } MFC Tutorial
CProperySheet 클래스 보통의 윈도우임 일반적인 다이얼로그처럼 사용 Style CObject CCmdTarget DoModal Create Style Child Thin More Styles - Disabled CObject CCmdTarget CWnd CPropertySheet MFC Tutorial
CProperSheet 클래스 멤버 함수 AddPage RemovePage GetPageCount SetActivePage 특정 페이지를 전면으로 CPropertyPage* pPropPage = GetPage(0); OnCreate 프라퍼티시트에 다른 콘트롤을 달때 MoveWindow : 프로퍼티시트의 크기 확대시 GetWindowRect : 현재 윈도우의 크기와 위치를 알고자 할때 MFC Tutorial
적용 버튼 활성화 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() MFC Tutorial
적용 처리 함수 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)를 호출해야 } MFC Tutorial
Wizard 모드 SetWizardMode SetWizardButton SetFinishText MFC Tutorial
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; MFC Tutorial
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(); } MFC Tutorial
파일 I/O 기능의 추가
목차 MFC의 파일 I/O 구조 문서 변경 여부 CFile, CArchive Serialize MFC Tutorial
MFC의 파일 I/O 구조 CWinApp, CDocument 클래스에서 미리 일반화시켜 놓았다. 사용자는 필요한 부분의 가상 함수만 제공 New CWinApp::OnFileNew Open CWinApp::OnFileOpen Close CDocument::OnFileClose Save CDocument::OnFileSave Save As CDocument::OnFileSaveAs New, Open도 실제로는 CDocument 클래스 내에 정의된 부분을 호출 MFC Tutorial
OnFileNew MDI 프로그램의 경우라면 -> MDI 자식윈도우 클래스와 뷰 클래스의 오브젝트를 만든다. SDI 프로그램의 경우라면 -> 이미 만들어져 있는 뷰를 그대로 사용한다. 다음으로 문서클래스의 오브젝트를 생성한다. 그리고 나서 문서클래스(CDocument 클래스)의 OnNewDocument 멤버함수를 호출한다. 뷰클래스의 OnInitialUpdate 함수를 호출한다. MFC Tutorial
OnFileOpen 읽어 들일 파일 이름을 입력받기 위한 파일 열기 다이얼로그 박스를 띄운다. MDI 프로그램의 경우라면 -> MDI 자식윈도우 클래스의 오브젝트와 뷰클래스의 오브젝트를 만든다. SDI 프로그램의 경우라면 -> 이미 만들어져 있는 뷰를 그대로 사용한다. 다음으로 문서클래스의 오브젝트를 생성한다. 파일의 내용을 읽어들이기 위해 문서클래스의 OnOpenDocument 멤버함수를 호출한다. 뷰클래스의 OnInitialUpdate 함수를 호출한다. MFC Tutorial
파일 열기 다이얼로그 박스 MFC Tutorial
OnFileClose 현재 문서가 저장되지 않았으면(IsModified 함수 호출) 저장 여부를 묻는 메시지박스를 띄운다. 저장하겠다고 하면 파일 이름이 있는 경우, 문서클래스의 OnSaveDocument 함수를 불러 저장 저장하겠다고 했지만 파일 이름이 없는 경우, 파일 이름을 입력받기 위한 다이얼로그 박스를 띄워 이름을 입력받아 저장한다(역시 OnSaveDocument 호출) 문서 클래스의 OnCloseDocument 함수를 불러 이 문서와 관련된 청소 작업을 한다. MFC Tutorial
OnCloseDocument 현재 편집중이던 문서와 관련된 자료 구조 등을 정리하는 작업과 윈도우 등을 닫는 작업을 수행한다. 자료 구조를 정리하기 위해 문서클래스의 DeleteContents 함수를 호출한다. MFC Tutorial
문서 변경 여부 SetModifiedFlag IsModified 문서가 변경되었는지를 알아내는 함수. 이전에 SetModifiedFlag 함수를 불렀다면 TRUE가 아니면 FALSE가 반환된다. 파일을 저장하면 이 플래그는 다시 FALSE로 바뀐다. MFC Tutorial
OnFileSave 편집중인 문서의 파일 이름이 있으면 문서클래스의 OnSaveDocument 함수를 불러 저장 MFC Tutorial
OnFileSaveAs 파일 이름을 입력받기 위한 다이얼로그 박스를 띄운다. 이름이 입력되면 OnSaveDocument 함수를 불러 문서의 내용을 저장한다. MFC Tutorial
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(); // 파일을 닫는다. MFC Tutorial
CArchive 저장될 대상과 실제 저장 매체(storage medium) 사이의 매개체 역할을 수행 파일, 소켓, OLE 파일 저장대상이 되는 자료구조나 전송대상이 되는 자료구조 네트웍 CArchive 클래스 MFC Tutorial
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가 리턴 IsWriting CArchive 클래스의 오브젝트를 저장 작업을 위해 오픈한 경우에는 TRUE가 리턴 MFC Tutorial
Serialize void CObeditDoc::Serialize(CArchive& ar) { if (ar.IsLoading()) // TODO: add storing code here } else // TODO: add loading code here MFC Tutorial
직렬화(serialization) 디스크에 저장하거나 읽는 작업 디스크에 저장할 때는 순서대로 데이터를 저장해야 하므로 직렬화라는 이름을 붙임 Linked list의 멤버 함수에도 Serialize 함수가 있음. 이것은 각 노드에 있는 객체의 Serialize 함수를 불러준다. MFC Tutorial
CObeditDoc::Serialize(1) .... #include “stdafx.h” #include “Obedit.h” #include “ObeditDoc.h” #include “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; MFC Tutorial
CObeditDoc::Serialize(2) m_RevNum++; ar << m_AppName; ar << m_Author; ar << m_Comments; ar << m_Keywords; ar << m_Subject; ar << m_Title; ar << m_CreateDate; ar << m_EditTime; ar << m_LastPrint; ar << m_LastSave; ar << m_RevNum; ar << m_sizeDoc; } else { m_StartTime = CTime::GetCurrentTime(); ar >> m_AppName; ar >> m_Author; ar >> m_Comments; ar >> m_Keywords; ar >> m_Subject; ar >> m_Title; ar >> m_CreateDate; ar >> m_EditTime; ar >> m_LastPrint; ar >> m_LastSave; ar >> m_RevNum; ar >> m_sizeDoc; } m_objectList.Serialize(ar); MFC Tutorial
CLine::Serialize void CLine::Serialize(CArchive& ar) { CDrawObject::Serialize(ar); if (ar.IsLoading()) } else MFC Tutorial
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; MFC Tutorial
CObject::Serialize 호출하지 않으면 파일 입출력이 제대로 동작 안함 이 정보를 바탕으로 도형클래스를 따로 생성하지 않아도 자동으로 도형클래스를 생성하고 있다. MFC Tutorial
Serialize 함수 호출 순서 CDocument의 Serialize 함수 도형리스트의 Serialize 함수호출 일단 프로그램전체에 걸친 정보를 입출력 한다 도형리스트의 Serialize 함수호출 (m_objectList.Serialize) 도형별로 Serialize 함수를 호출 MFC Tutorial
SetModifiedFlag MFC Tutorial
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); } MFC Tutorial
DeleteContents void CObeditDoc::DeleteContents() { while(!m_objectList.IsEmpty()) delete m_objectList.RemoveHead(); } CDocument::DeleteContents(); MFC Tutorial
CArchive 클래스 연산자 <<, >>가 가능한 타입 CObject에 대한 포인터 CString SIZE, CSize, POINT, CPoint, RECT, CRect CTime, CTimeSpan float, double BYTE, WORD, DWORD, LONG CObject 포인터가 아닌 일반 객체는 Serialize 함수를 호출하여 입출력해야 한다. MFC Tutorial
프린터 관련 명령
목차 MFC의 프린트 구조 MFC에서의 미리보기 구조 MFC Tutorial
MFC에서의 프린터 관련 메뉴 CPrintDialog Print, Print Setup, Print Preview MFC Tutorial
프린트 관련 메뉴 메뉴 기능 처리함수 이름 및 정의 위치 Print 프린터로 인쇄 OnFilePrint(CView) 메뉴 기능 처리함수 이름 및 정의 위치 Print 프린터로 인쇄 OnFilePrint(CView) Print Setup 프린터의 환경 설정 OnFilePrintSetup(CWinApp) Print Preview 프린터 출력을 화면 OnFilePrintPreview(CView) 으로 MFC Tutorial
화면과 프린터출력의 비교 거의 모든 함수가 표준화되어 있다. 차이점 화면 출력에도 사용하는 그래픽 디바이스에 관계없이 단일한 하나의 함수 집합(GDI, Graphic Device Interface)을 이용할 수 있다. - CDC 클래스 그외 ODBC(Open Database Connectivity) MCI(Media Control Interface) 프린터 출력시에도 CDC 클래스를 이용하여 출력 차이점 여러 장의 종이에 출력 출력 상태 표시 MFC Tutorial
프린터 작업시 뷰클래스가 해야 하는 일 최대 몇페이지나 출력할 수 있는지, 어느 페이지서부터 어느 페이지까지 출력할 것인지를 결정 - 프린터 다이얼로그 박스를 띄워 선택을 입력받는다. 특정 페이지를 출력하도록 요구받았을 때 그 부분을 그릴 수 있어야 한다. 필요하다면 머리말과 꼬리말을 출력할 수 있어야 한다. 출력에 필요한 폰트와 다른 GDI 자원들을 할당하고 제거할 수 있어야 한다. 프린터 다이얼로그를 띄워 프린터 DC를 구함 일반적인 코딩은 가상함수로 제공 MFC Tutorial
CView::OnPreparePrinting CView::OnFilePrint CView::OnPreparePrinting 출력문서의 페이지 수를 결정해 준다. 다음으로 DoPreparePrinting 함수를 호출하여 프린트 다이 얼로그박스를 표시하고 DC를 생성한다. CView::OnBeginPrinting 프린트 작업동안 필요한 각종 리소스를 할당한다. CDC::StartDoc 프린트 작업이 시작됨을 프린터에 알린다. CView::OnPrepareDC 프린트와 관계된 여러가지 DC의 속성들을 바꾸어준다. 더 출력할 페이지가 있는지 검사한다. CDC::StartPage 프린트 디바이스 쪽에 새 페이지의 출력이 시작되었음을 알린다. CView::OnPrint 머릿말과 꼬릿말이 있으면 출력하고 지정된 페이지를 출력한다. CDC::EndPage 페이지의 출력이 끝났음을 알린다. CDC::EndDoc 문서 전체의 출력이 끝났음을 알린다. CView::OnEndPrinting OnBeginPrinting에서 할당했던 리소스들을 제거한다. MFC Tutorial
MFC의 프린트 기능의 구현 뷰클래스의 다음 함수의 구현을 어떻게 만드느냐에 달림 OnPreparePrinting OnBeginPrinting OnEndPrinting OnPrepareDC OnPrint 프린트 다이얼로그를 띄우고 프린트 DC를 만들고 프린트 취소 다이얼로그를 띄우고 하는 일은 MFC가 알아서 수행 MFC Tutorial
프린트 제어를 위한 CDC 클래스의 함수 Escape Sequence 함수 StartDoc StartPage EndPage 새로운 문서의 출력이 나감을 알린다. StartPage 새로운 페이지의 출력이 나감을 알린다. EndPage 페이지의 출력이 끝났음을 알린다. EndDoc 문서의 출력이 종료되었음을 알린다. MFC Tutorial
CPrintInfo(1) OnPreparePrinting 함수의 인자로 넘어옴 프린터와 관련한 사용자의 입력을 저장하거나 프린트, 미리보기 관련 정보를 보관 예 프린트 할 페이지의 범위 현재 프린트하고 있는 페이지의 번호 출력용지의 크기 등 MFC Tutorial
CPrintInfo(2) struct CPrintInfo // Printing information structure { 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 SetMinPage(UINT nMinPage); void SetMaxPage(UINT nMaxPage); UINT GetMinPage() const; // 출력가능한 페이지의 범위 UINT GetMaxPage() const; UINT GetFromPage() const; // 사용자가 입력한 출력 페이지의 UINT GetToPage() const; // 범위 }; MFC Tutorial
OnPrint의 디폴트 코딩 페이지의 개념이 없음 OnDraw를 조금 수정하여 프린트에도 적용 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의 경우 : 스크롤 상황에 맞추어 원점을 이동 MFC Tutorial
View 클래스 수정 출력이 나가는 종이의 높이 지정 class CObeditView : public CScrollView { ... int m_nPaperHeight; }; MFC Tutorial
OnPreparePrinting 사용자가 출력 용지를 설정하기 전까지는 몇 페이지에 걸쳐 출력이 일어날지 모름 BOOL CObeditView::OnPreparePrinting(CPrintInfo* pInfo) { pInfo->m_nNumPreviewPages = 1; // 미리보기 할 페이지 수를 1로 정함 return DoPreparePrinting(pInfo); } 사용자가 출력 용지를 설정하기 전까지는 몇 페이지에 걸쳐 출력이 일어날지 모름 워드 프로세서의 경우 미리 출력 용지를 결정하므로 pInfo->SetMaxPage 함수를 호출하여 출력할 페이지를 결정할 수 있음 MFC Tutorial
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); } MFC Tutorial
OnBeginPrinting(2) CDC::SetDeviceCaps 함수를 이용하여 출력 용지의 높이를 구함 프린트 중에 사용할 GDI 리소스(펜, 폰트, 브러쉬등)를 할당해 두는 일을 하는 곳 페이지 출력시마다 리소스 할당을 하지 않기 위해 즉, 프린트 작업에 들어가기에 앞서 전체적으로 필요한 GDI 리소스를 할당 OnEndPrinting에서 이 리소스들을 제거 MFC Tutorial
GetDeviceCaps의 인자 HORZRES 현재 선택된 출력용지의 폭을 픽셀 단위로 알고자 할 때 VERTRES 현재 선택된 출력용지의 높이를 픽셀 단위로 알고자 할 때 HORSIZE 현재 선택된 출력용지의 폭을 밀리미터 단위로 알고자 할 때 VERTSIZE 현재 선택된 출력용지의 높이를 밀리미터 단위로 알고자 할때 LOGPIXELSX 현재 프린터의 수평방향의 DPI(Dot Per Inch)를 알고자 할 때 LOGPIXELSY 현재 프린터의 수직방향의 DPI(Dot Per Inch)를 알고자 할 때 NUMCOLORS 프린터가 지원하는 색상의 수를 리턴한다. 흑백이면 2 TECHNOLOGY 현재 디바이스컨텍스트가 나타내는 출력장치가 무엇인지를 돌려준다. 예로 프린터의 경우에는 DT_RASPRINTER가 리턴될 것이다. DT_PLOTTER : 백터 플로터 DT_RASDISPLAY : 래스터 디스플레이 DT_RASPRINTER : 래스터 프린터 DT_RASCAMERA : 래스터 카메라 . . . . MFC Tutorial
OnEndPrinting 본 예제에서는 할당한 리소스들이 없으므로 OnEndPrinting에서 할 일이 없음 void CObeditView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { } MFC Tutorial
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); MFC Tutorial
OnPrepareDC에서의 주의점 인자로 넘어오는 CDC 클래스의 오브젝트에 대한 포인터에 대하여 출력을 할 경우 윈도우 출력의 경우 : 출력이 나감 프린터 출력의 경우 : 출력이 안 나감 프린터 출력시에는 OnPrepareDC의 호출이 끝난 다음에야 새 페이지의 출력을 프린터 드라이버에 알리는 CDC::StartPage를 호출하기 때문. 그 전에 호출한 것은 아무런 소용이 없다. 두번째 인자 pInfo NULL : 화면 출력 NULL이 아님 : 프린트 출력. 이때 프린트 쪽의 원점을 뒤로 이동하여 다음 페이지 출력 pInfo->m_nCurPage : 현재 출력이 나갈 페이지의 번호를 가리킴 MFC Tutorial
SetViewportOrg를 이용한 페이지의 출력 전체 편집문서 1. N 페이지만 프린트로 출력이 나가야한다. 3. 종이의 출력원점을 전체편집문서의 원점과 맞추어주기위해 그만큼 뒤로 이동하고 OnDraw를 호출한다. 그러면 1페이지부터 N-1 페이지까지의 출력은 종이밖으로 출력되기 때문에 무시된다. 1 페이지 2. 출력원점의 보정없이 OnDraw를 호출하면 항상 1 페이지가 출력된다. 종이의 원점에 전체편집문서의 원점이 바로 대응 되기 때문이다. N 페이지 출력용지 MFC Tutorial
편집 문서의 수정 출력 용지를 늘리기위해 CObeditDoc::CObeditDoc() { m_sizeDoc = CSize(1500, 5000); m_AppName = _T(“도형편집기”); } MFC Tutorial
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); MFC Tutorial
출력 용지 페이지 수 계산 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를 이용하여 오차를 없앰 MFC Tutorial
프린터로 아무것도 출력이 안되는 이유 +Y -X +X 출력원점 -Y 출력용지 MFC Tutorial
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); CSize size = pDC->GetViewportExt(); pDC->SetViewportExt(size.cx, -size.cy); // 반대방향으로 뒤집음 pDC->SetViewportOrg(0, -(pInfo->m_nCurPage-1)*m_nPaperHeight); MFC Tutorial
MFC에서의 미리보기 구조 MFC에서는 기본적인 프린터 출력루틴만 제대로 만들어졌다면 미리보기는 자연스럽게 구현이 된다. 차이점 미리보기는 윈도우로 출력되기 때문에 프린터 출력과는 달리 WM_PAINT를 처리할 수 있어야 한다. 사용자의 입력을 기다렸다가 페이지를 출력한다. CPreviewDC 두개의 DC를 사용 프린터 DC를 흉내낸 DC 출력이 실제로 표시되는 윈도우를 나타내는 DC MFC Tutorial
CPreviewView 클래스 CPreviewView 클래스 메인 프레임의 자식 윈도우로 존재 CPrintInfo의 m_bPreview가 TRUE이면 미리보기 중 MFC Tutorial
미리보기 창에 출력 두 페이지 모드일 때 나갈 문자열 분리자 한 페이지 모드일 때 나갈 문자열 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; } 두 페이지 모드일 때 나갈 문자열 분리자 한 페이지 모드일 때 나갈 문자열 MFC Tutorial
분리 윈도우
목차 분리 윈도우 동적 분리 윈도우 정적 분리 윈도우 MFC Tutorial
정적 동적 분리 윈도우(1) 동적 분리 윈도우 정적 분리 윈도우 MFC Tutorial
정적 동적 분리 윈도우(2) MFC Tutorial
분리 윈도우의 구현 CSplitterWnd 클래스를 이용 다음 클래스의 member data로 존재 CFrameWnd CMDIChildWnd MFC Tutorial
동적 분리 윈도우의 구현 class CChildWnd : public CMDIChildWnd { DECLARE_DYNCREATE(CChildFrame) public: CChildFrame(); // Attributes CSplitterWnd m_wndSplitter; // Operations // Overrides // ClassWizard generated virtual function overrides // {{AFX_VIRTUAL(CChildFrame) virtual BOOL PreCreateWindow(CREATESTRUCT& cs); .... MFC Tutorial
자식 윈도우 생성시 최대 4개의 동적 분리 윈도우 생성 가능 분리 윈도 우의 행 갯수 분리 윈도 우의 열 갯수 동적 분리 BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { return m_wndSplitter.Create(this, 2, 2, CSize(10, 10), pContext); } 분리 윈도 우의 행 갯수 분리 윈도 우의 열 갯수 동적 분리 윈도우의 창의 최소 크기 MFC Tutorial
분리 윈도우의 크기 변경 프로그램에서 변경시 SetColumnInfo,SetRowInfo 함수를 이용하여 크기 변경 void GetRowInfo( int row, int& cyCur, int& cyMin ); void GetColumnInfo( int col, int& cxCur, int& cxMin ); void SetRowInfo( int row, int cyIdeal, int cyMin ); void SetColumnInfo( int col, int cxIdeal, int cxMin ); MFC Tutorial
pContext struct CCreateContext { m_pNewViewClass // 생성하고자 하는 새로운 뷰의 CRuntimeClass m_pCurrentDoc // 새로 생성한 뷰가 연관된 이미 존재하는 도큐먼트 객체 m_pNewDocTemplate // 새로운 MDI 프레임 윈도우의 생성과 연관된 // 도큐먼트 템플릿 m_pLastView // 이미 존재하는 뷰 m_pCurrentFrame // 현재 생성하고 있는 프레임 윈도우 MFC Tutorial
다른 윈도우에 갱신이 안 되는 경우 MFC Tutorial
자신의 문서 내용을 출력하고 있는 모든 뷰에게 내용을 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); } 자신의 문서 내용을 출력하고 있는 모든 뷰에게 내용을 다시 그리라고 하는데 사용하는 함수 MFC Tutorial
UpdateAllViews CDocument 클래스의 멤버 함수 자신의 문서 내용을 출력하고 있는 모든 뷰에게 내용을 다시 그리라고 하는데 사용 void UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint = NULL); pSender : 도큐먼트를 변경한 뷰, NULL이면 모든 뷰 갱신 lHint : 변경 정보 pHint : 변경과 관계된 객체에 대한 포인터 CView 클래스의 OnUpdate 함수 호출 MFC Tutorial
OnUpdate UpdateAllView는 각 뷰 클래스의 OnUpdate 함수 호출 예제에서 OnUpdate가 불리는 경우 각각의 OnUpdate 함수는 Invalidate를 호출하여 윈도우 영역 전체를 다시 그린다. 이를 방지하기 위해 수정해야 한다. 즉 OnUpdate에 갱신된 정보를 포함하여 이 정보에 따라 그림을 수정해야 함 예제에서 OnUpdate가 불리는 경우 새로운 객체를 삽입하였을 때 객체 삽입을 알려주어야 할 때 배율 설정시에 모든 뷰에 배율이 변경되었다는 것을 알려주어야 할 때 MFC Tutorial
분리 윈도우의 배율의 불일치 MFC Tutorial
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(); 새로운 객체 추가 한 뷰에서 다른 뷰로 배율을 전파 MFC Tutorial
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); } 삽입된 객체 객체 사입 MFC Tutorial
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(); } 배율 변경 MFC Tutorial
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(); } 배율 변경 MFC Tutorial
정적 분리 윈도우 프레임 클래스의 OnCreateClient 함수를 오버라이드 해서 구현 서로 다른 뷰를 가지도록 만든다. MFC Tutorial
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)) // 두번째 정적 윈도우를 생성한다. 이 윈도우는 CInputView 클래스이다. if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CInputView), CSize(0, 0), pContext)) // 두번째 뷰를 활성화한다. SetActiveView((CView*)m_wndSplitter.GetPane(0, 1); return TRUE; } MFC Tutorial
세개의 정적 분리 윈도우 생성 MFC Tutorial
세 개의 정적 분리윈도우의 구현 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))) if (!m_wndSplitter2.CreateView(0, 0, RUNTIME_CLASS(CListView), CSize(100, 150), pContext)) if (!m_wndSplitter2.CreateView(1, 0, RUNTIME_CLASS(CTextView), CSize(100, 120), pContext)) SetActiveView((CView*)m_wndSplitter2.GetPane(0, 0)); MFC Tutorial
MFC 디버깅 매크로와 예외 처리
목차 메시지 출력 ASSERT 매크로 오브젝트의 유효성 검사 예외 처리 MFC Tutorial
컴파일 옵션 Debug 모드 _DEBUG Release 모드 NODEBUG MFC Tutorial
디버그 모드로 수행 MFC Tutorial
디버깅 모드로 수행 한 문장씩 수행 함수 안으로 들어가 수행 수행중인 함수밖으로 커서 위치까지 수행 Call Stack MFC Tutorial
TRACE 매크로 디버그 창으로 메시지 출력 디버그 모드로 컴파일할 때만 수행 TRACE(“Sample TRACE Output : %d == 0x%x\n”, i, i); MFC Tutorial
ASSERT 매크로 어떤 조건을 검사하여 거짓이면 그 위치(파일 이름과 행번호)를 출력하는데 사용 주로 프로그램 개발 기간 중에 함수의 인자로 들어온 값이 맞게 들어왔는지의 여부를 판단하는데 사용 디버그 모드로 컴파일 시에만 수행 ASSERT(prt != NULL); MFC Tutorial
VERIFY 매크로 ASSERT 매크로와 동일 단, 디버그 모드가 아닌 Release 모드로 컴파일 시에도 수행 VERIFY(LoadAccelTable(hWnd, “MainWnd”)); MFC Tutorial
오브젝트의 유효성 검사 CObject 클래스의 후손에만 적용 AssertValid Dump 디버그 모드에서만 수행 현재 오브젝트의 데이터멤버가 올바른 값을 갖고 있는지의 여부를 검사 Dump 현재 오브젝트의 데이터멤버를 출력하는데 사용 디버그 모드에서만 수행 _DEBUG MFC Tutorial
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); } MFC Tutorial
Dump afxDump는 CDumpContext 타입의 전역 변수. 출력이 윈도우의 Debug 탭으로 출력 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 } void f() CHorzLine* pLine = new CHorzLine; .... #ifdef _DEBUG pLine->Dump(afxDump); #endif afxDump는 CDumpContext 타입의 전역 변수. 출력이 윈도우의 Debug 탭으로 출력 MFC Tutorial
예외처리 체크 되어야 MFC Tutorial
공통 컨트롤(Common Control)
목차 Common Control의 종류 Control Message 처리 Animation Control Progress Control Slider Control List Control Tree Control MFC Tutorial
Common Control의 종류(1) CAnimateCtrl CHeaderCtrl CHotKeyCtrl CImageList CListCtrl MFC Tutorial
Common Control의 종류(2) CProgressCtrl CRichEditCtrl OLE 복합문서 컨테이너 MFC Tutorial
Common Control의 종류(3) CSliderCtrl CSpinButtonCtrl CStatusBarCtrl CTabCtrl MFC Tutorial
Common Control의 종류(4) CToolBarCtrl CToolTipCtrl CDragListBox CCheckListBox MFC Tutorial
Common Control의 종류(5) CTreeCtrl MFC Tutorial
Common Control Common contorl의 code는 윈도우의 system\COMCTL32.DLL에 있다. 각 컨트롤에 대한 윈도우 프로시저 각 컨트롤을 위한 윈도 클래스를 등록하는 코드가 포함 등록 코드는 DLL이 로드될 때 호출 다이얼로그를 초기화할 때 프로그램에서는 다이얼로그 리소스에서 기호 클래스 이름을 사용해서 DLL에 있는 윈도 프로시저를 연결 이렇게 함으로써 프로그램에서는 컨트롤의 윈도를 소유하게 되지만, 코드는 DLL에 존재 공통 컨트롤은 Class Wizard가 멤버 변수를 제공하지 않음 공통 컨트롤들로부터 통지 메시지들을 매핑하는 일에는 Class Wizard를 이용할 수 있다. MFC Tutorial
Common Control의 사용 Common control 역시 컨트롤이기 때문에 dialog box에서 사용할 수 있다. 보통 윈도우의 자식 윈도우로 존재할 수 있다. MFC Tutorial
Dialog Box에서 사용(1) Progress Control Slider Control List Control Spin Control Hotkey Control Tree Control Tap Control Animation Control MFC Tutorial
Dialog Box에서 사용(2) Resource view에 있는 control palette 이용 없는 것은 데이터 멤버로 만들어 놓은 다음 WM_INITDIALOG 메시지가 왔을 때 Create 같은 멤버함수를 이용해 직접 생성 Class wizard를 이용해 dialog box template에 해당하는 dialog class 생성 Add Member Variable 버튼을 택하여 common control에 해당하는 데이터 멤버를 만듦 강제적으로 Category가 CONTROL이 된다. MFC Tutorial
일반윈도우의 자식윈도우로 사용시 각 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(...); MFC Tutorial
Notification Message 처리 Control은 자신에게 무슨 일이 발생하면 부모 윈도우에게 알려준다. Control이 dialog box에서 사용된 경우라면 이 때 부모윈도우는 dialog box가 된다. MFC Tutorial
Notification Message WM_COMMAND WM_NOTIFY 원래의 window control들이 이용 표준 32비트 wParam, lParam 메시지 파라미터는 common control이 부모에게 보내는 정보를 위해 사용하기에는 부적절 WM_NOTIFY wParam은 control ID lParam은 control에 의해 운영되는 NMHDR 구조체 포인터이거나 이를 포함하는 더 큰 구조체 MFC Tutorial
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에 따라 달라지는 것 두 종류가 존재 MFC Tutorial
공통되는 Notification Code NM_CLICK 컨트롤을 좌측 마우스 버튼으로 클릭했을 때 NM_DBCLICK 컨트롤을 좌측 마우스 버튼으로 더블 클릭했을 때 NM_RCLICK 컨트롤을 우측 마우스 버튼으로 클릭했을 때 NM_RDBCLICK 컨트롤을 우측 마우스 버튼으로 더블 클릭했을 때 NM_RETURN 컨트롤이 입력 포커스를 갖고 있을 때 리턴키를 친 경우 NM_SETFOCUS 컨트롤에 입력 포커스가 갈 때 NM_KILLFOCUS 컨트롤이 입력 포커스를 잃을 때 NM_OUTOFMEMORY 메모리가 부족해서 하던 일을 끝내지 못할 때 MFC Tutorial
다양한 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; MFC Tutorial
Message Map에서의 Notification Message ON_NOTIFY 매크로 사용 ON_NOTIFY(wNotifyCode, ctrlID, memberFn) ctrlID를 공통 컨트롤 ID로 갖는 공통컨트롤로부터 wNotifyCode라는 알림코드가 오면 memberFn이라는 처리함수를 불러달라는 것 void memberFn(NMHDR* pNotifyStruct, LRESULT* result); 처리 결과를 돌려준다. 처리했으면 0을 리턴 공통 컨트롤에 따라 달라진다. MFC Tutorial
Message Map Macro ON_NOTIFY_RANGE, ON_NOTIFY_EX, ON_NOTIFY_EX_RANGE 동일한 종류의 여러 control로부터 오는 notification code를 처리하고자 할 때 매번 처리함수를 따로 만들지 않고 하나의 처리함수를 정의해 사용 MFC Tutorial
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; } 적절한 타입으로 캐스팅 하여 사용 MFC Tutorial
Message Reflection Notification message를 부모 윈도우로 보냈을 때 처리가 안 되었다면 이를 다시 컨트롤로 보내 자체에서 처리가 되도록 하는 기능 MFC 4.0에서 새로 제공해주는 기능 부모 윈도우의 의존성에서 벗어나 나름대로의 동작 방식을 더 가질 수 있게 됨 Message Reflection의 경우 컨트롤 자체의 message map에 등록해야 ON_NOTIFY_REFLECT 매크로 사용 ON_NOTIFY_REFLECT(wNotifyCode, memberFn) MFC Tutorial
예제 프로젝트 이름 : CmmCtrl SDI 데이터베이스 옵션은 주지 않음 Toolbar, status bar, 프린트 관련 옵션도 선택 않음 MFC Tutorial
메뉴 구성 Common Control Help Animate ID_COMM_ANIMATE Image List ID_COMM_IMAGE Slider ID_COMM_SLIDER Progress ID_COMM_PROGRESS Tree ID_COMM_TREE List ID_COMM_LIST ------------ Exit MFC Tutorial
Control ID 생성 Resource Symbol을 이용해도 됨 // CmmCtrlView.cpp #define IDC_ANIMATE 200 // Animation control ID #define IDC_PROGRESS 201 // Progress control ID #define IDC_SLIDER 202 // Slider control ID #define IDC_LISTCTRL 203 // List control ID #define IDC_TREECTRL 204 // Tree control ID Resource Symbol을 이용해도 됨 MFC Tutorial
컨트롤 멤버데이터 정의 CCmmCtrlView 클래스에 정의 CAnimateCtrl m_wndAnimateCtrl; // Animation control CImageList m_wndImageList; // Image list 1 CImageList m_wndSmallImageList; // Image list 2 CSliderCtrl m_wndSliderCtrl; // Slider control CProgressCtrl m_wndProgressCtrl; // Progress control CListCtrl m_wndListCtrl; // List control CTreeCtrl m_wndTreeCtrl; // Tree control HTREEITEM m_treeRoot; // Tree control에서 사용된다. // 루트 항목을 가리킨다. BOOL m_bListCtrl; // List control의 생성여부 BOOL m_bTreeCtrl; // Tree control의 생성여부 BOOL m_bSlider; // Slider control의 생성여부 MFC Tutorial
남아있는 객체 삭제를 위한 함수 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_wndTreeCtrl.DestroyWindow(); m_bTreeCtrl = FALSE; else if (m_bSlider) m_wndSliderCtrl.DestroyWindow(); m_bSlider = FALSE; MFC Tutorial
CCmmCtrlView의 생성자/소멸자 변경 CCmmCtrlView::CCmmCtrlView() { m_bListCtrl = FALSE; m_bTreeCtrl = FALSE; m_bSlider = FALSE; } CCmmCtrlView::~CCmmCtrlView() CheckWnd(); MFC Tutorial
Animation Control AVI 파일을 디스플레이 오디오가 있는 파일은 지원안 함 즉 하나의 Video Stream만 있는 avi file 만 지원 오디오를 지원하는 클래스 : OLE 컨트롤 중 마이크로소프트 멀티미디어 컨트롤 MFC Tutorial
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); // } MFC Tutorial
Animation Control의 속성 ACS_CENTER 애니메이션 컨트롤의 중앙에서 AVI 파일을 플레이 크기에 맞춰 애니메이션 컨트롤의 크기가 변경된다 위의 예에서 바로 이 스타일을 사용하였다. ACS_TRANSPARENT AVI 파일의 배경색 대신에 원래 애니메이션 컨트롤 의 자리에 있던 배경색을 사용한다. ACS_AUTOPLAY AVI 파일이 오픈됨과 동시에 플레이되도록 하며 플레이가 계속 반복되도록 한다. MFC Tutorial
CAnimateCtrl의 멤버 함수 Open AVI 파일이나 리소스를 읽어들여 첫 프레임을 윈도우에 표시한다. Play AVI 클립을 플레이한다. 첫번째 인자와 두번째 인자가 플레이할 프레임을 지칭 시작 프레임일 경우 0을 마지막 프레임일 경우 -1(0xFFFF) 마지막 인자는 반복횟수 Seek AVI 클립의 지정된 프레임을 윈도우에 표시한다. Stop AVI 클립의 표시를 중단한다. Close 오픈된 AVI 클립을 닫아 버린다. MFC Tutorial
Animation Control의 Notification Code ACN_START AVI 클립의 플레이가 시작되었음을 알린다. ACN_STOP AVI 클립의 플레이가 다 끝났음을 알린다. WM_COMMAND 메시지 발생 ON_CONTROL 매크로 사용 MFC Tutorial
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); } MFC Tutorial
Image List Mask bitmap 윈도우가 아님 BOOL Create(int cx, int cy, BOOL bMask, int nInitial, int nGrow); cx, cy ; 픽셀 단위로 각 이미지의 크기 bMask : mask image를 사용할 것인지의 여부 nInitial : 처음 이미지 리스트가 생성될 때 이미지 리스트에 들어갈 이미지의 개수 nGrow : 이미지 리스트의 크기가 변할 때 쓰이는 단위 MFC Tutorial
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); MFC Tutorial
ID_COMM_IMAGE(2) IDB_BITMAP1 IDB_BITMAP2 IDB_BITMAP3 pt.y += 50; m_wndImageList.Draw(&dc, i, pt, ILD_BLEND50); m_wndImageList.Draw(&dc, i, pt, ILD_BLEND25); } m_wndImageList.DeleteImageList(); IDB_BITMAP1 IDB_BITMAP2 IDB_BITMAP3 MFC Tutorial
Image List의 멤버 함수(1) GetImageCount Image list에 들어있는 image의 개수 SetBkColor Image list의 image의 배경색을 설정. Mask image list의 경우에는 CLR_NONE을 주면 Mask를 갖고 그리기 때문에 원래 배경이 보존된다 GetBkColor 현재 image list의 image의 배경색을 얻어온다 GetImageInfo 현재 image list의 image에 대한 정보를 얻음 DeleteImageList Image list를 삭제한다 Add 새로운 image를 image list에 추가한다. Remove Image list에서 image를 삭제한다. Replace Image list에서 한 image를 다른 image로 변경 Extraction Image list의 image를 icon handle로 만들려는 경우에 사용 Read Image를 파일에서 읽어 image list에 추가 Write Image를 image list에서 읽어 파일에 추가 MFC Tutorial
Image List의 멤버 함수(2) Draw Image list의 image를 윈도우 위에 출력한다. SetOverlayImage Image list의 image를 overlay image list에 추가한다. Image list 당 4개까지의 image를 overlay mask로 사용할 수 있다. MFC Tutorial
Draw 함수 BOOL Draw(CDC* pdc, int nImage, POINT pt, UINT nStyle); IDL_NORMAL Image list에 지정된 배경색을 갖고 이미지를 출력한다. Mask image list의 경우에는 배경이 보존된 채 출력이 이루어진다. IDL_TRANSPARENT 지정된 배경색에 관계없이 배경을 유지한 채 image를 출력하는데 마스크된 image에만 적용 가능한 옵션 IDL_BLEND50 주어진 image가 선택되었음을 나타내기 위해 시스템 하이라이트 색상으로 혼합한 다음에 출력한다. IDL_BLEND25 주어진 image가 입력포커스를 갖고 있음을 나타내며 출력한다. IDL_OVERLAYMASK 주어진 image를 그리고 그 위에 이 스타일과 함께 지정된 overlay mask를 그린다. Overlay mask 지정은 INDEXTOOVERLAYMASK macro를 통해 이루 어진다. 연산자를 이용해 이 스타일과 함께 지정해준다. MFC Tutorial
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); // 초기위치를 지정한다 MFC Tutorial
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); MFC Tutorial
Progress Control의 멤버함수 SetRange Progress bar의 범위값을 지정하고 그에 맞추어 다시 그림 SetPos Progress bar의 현재 위치를 지정하고 그에 맞추어 다시 그림 OffsetPos Progress bar의 현재 위치를 주어진 값만큼 보정하고 다시 그림 SetStep Progress bar의 진행 단위를 지정한다. StepIt 함수에서 사용한다. StepIt Progress bar의 현재 위치를 SetStep에서 지정된 값만큼 진행시킨다. MFC Tutorial
Slider Control 불연속적인 값이나 어떤 범위의 값을 입력받고자 할 때 WM_HSCROLL(혹은 WM_VSCROLL)로 특이하게 notification code를 발생시킨다. MFC Tutorial
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); } MFC Tutorial
Slider Control의 윈도우 스타일 TBS_HORZ 수평 slider control을 만든다. 이것이 디폴트이다. TBS_VERT 수직 slider control을 만든다. TBS_AUTOTICKS 지정된 슬라이더 범위 내의 각 단위값 마다 눈금을 붙이다. 만일 이 스타일이 이용된 경우에는 SetTic, SetTicFreq와 같은 멤버함수를 이용해 눈금의 위치를 지정할 수 있다. TBS_NOTICKS 눈금이 없는 슬라이더를 만든다. TBS_BOTTOM 슬라이더의 하단에 눈금을 표시한다. TBS_TOP 스타일과 함께 사용되면 위아래 모두에 눈금을 붙일 수 있다. TBS_BOTTOM과 TBS_TOP 스타일은 수평 슬라이더에만 적용 가능하다. TBS_TOP 수평 슬라이더의 상단에 눈금을 붙인다. TBS_RIGHT 수직 슬라이더의 우단에 눈금을 붙인다. TBS_LEFT 스타일과 함께 사용되면 오른쪽, 왼쪽 모두에 눈금을 붙인다. MFC Tutorial
TBS_LEFT 수직 슬라이더의 좌단에 눈금을 붙인다. TBS_BOTH 수평 슬라이더이면 위아래에 눈금을 붙이고 수직 슬라이더이면 왼쪽, 오른쪽에 눈금을 붙인다. TBS_ENABLESELRANGE 이 스타일을 주면 영역을 선택하는 것이 가능하다. 선택 영역의 시작과 끝 눈금이 삼각형 모양의 눈금으로 변하고 그 사이의 영역이 하이라이트된다. MFC Tutorial
CSliderCtrl의 멤버 함수(1) SetRange Slider control의 양끝값을 설정한다. SetRangeMin Slider control의 최소값을 설정한다. SetRangeMax Slider control의 최대값을 설정한다. GetRangeMax Slider control의 최대값을 얻어온다. GetRangeMin Slider control의 최소값을 얻어온다. GetRange Slider control의 양끝값을 얻어온다. GetLineSize Slider control의 라인 크기를 얻어온다. TB_LINEUP, TB_LINEDOWN의 발생 시 이동량을 얻어오는 것이다. SetLineSize Slider control의 라인 크기를 설정한다. GetPageSize Slider control의 페이지 크기를 얻어온다. TB_PAGEUP, TB_PAGEDOWN의 발생시 이동량을 얻어오는 것이다. SetPageSize Slider control의 페이지 크기를 결정한다. GetPos Slider control의 슬라이더 위치를 얻어온다. SetPos Slider control의 슬라이더 위치를 새로 설정한다. MFC Tutorial
CSliderCtrl의 멤버 함수(2) GetTic 주어진 눈금의 위치를 얻어온다. GetTicPos 주어진 눈금이 위치한 좌표를 얻어온다. SetTic 눈금이 생길 위치를 지정한다. SetTicFreq 눈금이 생길 위치를 위치 단위로 지정한다. 예로 들면 2로 지정하면 0, 2, 4...의 위치에 눈금이 생긴다. ClearTics Slider control에서 모든 눈금을 제거한다. MFC Tutorial
Slider Control의 Notification Code TB_TOP HOME 키를 눌렀을 때 TB_BOTTOM END 키를 눌렀을 때 TB_LINEDOWN VK_RIGHT이나 VK_DOWN 키를 눌렀을 때 TB_LINEUP VK_LEFT나 VK_UP 키를 눌렀을 때 TB_PAGEDOWN 마우스로 슬라이더의 오른쪽을 누르거나 PgDn 키 를 눌렀을 때 TB_PAGEUP 마우스로 슬라이더의 왼쪽을 누르거나 PgUp 키를 눌렀을 때 TB_THUMBPOSITION TB_THUMBTRACK의 끝에 따라와 슬라이더의 드래깅이 끝났음을 알린다. TB_THUMBTRACK 사용자가 슬라이더를 드래그하면 그 때 계속적으로 발생한다. TB_ENDTRACK 각 notification code에 뒤이어 항상 발생한다. MFC Tutorial
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); } MFC Tutorial
List View Control 리스트의 한 아이템이 여러 항목으로 구성될 수 있다. 항목의 일부로 비트맵이 들어갈 수 있다. 각 항목의 제목을 나타내기 위해 헤더(Header) 컨트롤이라는 것을 내부적으로 사용할 수 있다. 항목마다 사용되는 아이콘을 따로 리스트로 유지하는데 앞서 살펴 본 image list를 사용하는 것이다. MFC Tutorial
List View Control의 타입 아이콘뷰 LVS_ICON 스타일을 지정하면 된다. 각 항목은 아이콘과 그 밑의 레이블로 구성된다. 각 항목은 드래깅으로 다른 위치에 갖다놓을 수 있다. 스몰아이콘뷰 LVS_SMALLICON 스타일을 지정하면 된다. 각 항목은 16X16 아이콘과 그 오른쪽의 레이블로 구성된다. 각 항목 은 드래깅으로 다른 위치에 갖다 놓을 수 있다. 리스트뷰 LVS_LIST 스타일을 지정하면 된다. 각 항목은 서브 항목별 로 정렬되어 디스플레이된다. 리포트뷰 LVS_REPORT 스타일을 지정하면 된다. LVS_NOCOLUMNHEADER 스타일이 명시되지 않으면 헤더 컨트롤이 사용되어 레이블과 각 서브 항목의 타이틀을 표시할 수 있다. 리스트뷰에서와 마찬가지로 각 항목들은 서브 항목별로 정렬되어 디스플레이된다. MFC Tutorial
List View Control의 윈도우 스타일 LVS_BUTTON Icon view에서 아이콘을 버튼처럼 디스플레이 되도록 한다. LVS_EDITLABELS 각 항목의 레이블이 편집 가능하도록 한다. 부모 윈도우는 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 항목들이 윈도우 영역의 크기를 넘어가도 스크롤이 안되도록 한다. MFC Tutorial
CListCtrl 클래스의 주요 멤버 함수(1) InsertColumn 새로운 컬럼을 삽입한다. DeleteColumn 컬럼을 하나 삭제한다. InsertItem 새로운 항목을 하나 삽입한다. GetItem 항목의 속성을 얻어온다. SelItem 항목에 부항목을 붙이는 등의 속성변경 작업을 한다. DeleteItem 항목 하나를 삭제한다. DeleteAllItems 모든 항목을 삭제한다. HitTest 주어진 위치에 어떤 항목이 있는지 알아낸다. EnsureVisible 주어진 항목이 보이도록 만든다. Scroll 내용을 스크롤시킨다. EditLabel 항목 텍스트의 편집이 가능하도록 한다. GetBkColor 배경색을 얻어온다. SetBkColor 배경색을 설정한다. GetImageList 사용되는 아이콘리스트를 얻어온다. MFC Tutorial
CListCtrl 클래스의 주요 멤버 함수(2) SetImageList 사용되는 icon list를 지정한다. GetItemCount 항목수를 얻어온다. GetStringWidth 주어진 문자열을 표시하는데 필요한 최소한의 컬럼폭을 돌려준다. GetColumnWidth 리스트뷰와 리포트뷰의 컬럼폭을 얻어온다. SetColumnWidth 리스트뷰와 리포트뷰의 컬럼폭을 설정한다. GetItemText 리스트뷰의 특정항목의 레이블이나 부항목의 텍스트를 얻어온다. SetItemText 리스트뷰의 특정항목의 레이블이나 부항목의 텍스트를 설정한다. MFC Tutorial
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); MFC Tutorial
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.iSubItem = 1; m_wndListCtrl.InsertColumn(1, &lvc); MFC Tutorial
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.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; MFC Tutorial
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.iSubItem = 2; lvItem.pszText = _T("2,500,000"); MFC Tutorial
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; } MFC Tutorial
SetImageList 두번째 인자 LVSIL_NORMAL 큰 아이콘을 갖는 image list LVSIL_SMALL 작은 아이콘을 갖는 image list LVSIL_STATE 상태를 나타내는 아이콘을 갖는 image list MFC Tutorial
헤더 LV_COLUMN을 초기화해서 InsertColumn 함수를 호출 mask LVCF_FMT fmt 필드를 사용할 것이다 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 fmt 필드를 사용할 것이다 LVCF_SUBITEM iSubItem 필드를 사용할 것이다. LVCF_TEXT pszText 필드를 사용할 것이다. LVCF_WIDTH cx 필드를 사용할 것이다. MFC Tutorial
항목 LV_ITEM 스트럭처를 초기화 한 다음 InsertItem 함수 호출 부항목은 InsertItem 함수의 리턴값(nActualIndex)을 갖고 LV_ITEM 스트럭처를 초기화한 다음에 SetItem 함수 호출 원하는 부항목 수만큼 반복 MFC Tutorial
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; MFC Tutorial
LV_ITEM(2) mask iItem : list view control의 몇번째 항목인가 LVIF_TEXT pszText 필드를 사용할 것이다. LVIF_IMAGE iImage 필드를 사용할 것이다. LVIF_PARAM lParam 필드를 사용할 것이다. LVIF_STATE state 필드를 사용할 것이다. iItem : list view control의 몇번째 항목인가 iSubItem : 몇번째 부항목인가(0부터 시작) state : stateMask 필드와 같이 사용 LVIS_CUT, LVIS_DROPHILITED, LVIS_FOCUSED, LVIS_SELECTED 항목의 외양을 나타냄 MFC Tutorial
LV_ITEM(3) pszText : 항목의 텍스트 cchTextMax : pszText 필드의 버퍼 크기 iImage : image list의 아이콘의 인덱스(-1이면 사용안함) 만일 이 값이 I_IMAGECALLBACK 이면 디스플레이 할 순간에 부모 윈도우로 LVN_GETDISPINFO notification message가 보내진다. MFC Tutorial
실행 모습 MFC Tutorial
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 현재 선택 항목이 다른 항목으로 변경된 다음 발생 MFC Tutorial
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; MFC Tutorial
Tree View Control 윈도우 스타일 TVS_HASLINES 각 항목간(부모 자식간)을 선으로 이어준다. TVS_LINESATROOT 루트를 만들어 최상위 레벨의 항목들과 연결 시켜준다. TVS_HASBUTTONS 각 항목의 좌측에 버튼을 붙여준다. TVS_EdITLABELS Tree view control의 레이블을 편집 가능하게 만듦 MFC Tutorial
CTreeCtrl의 멤버함수(1) InsertItem 새로운 항목을 삽입한다. DeleteItem 항목 하나를 삭제한다. DeleteAllItems 모든 항목을 삭제한다. Expand 주어진 항목의 자식 항목들을 모두 펼친다. SelectItem 주어진 항목을 현재 선택 항목으로 만든다. EditLabel 주어진 항목의 레이블을 편집 가능하게 만든다. HitTest 주어진 위치에 있는 항목의 핸들을 얻어온다. SortChildren 주어진 항목의 자식 항목들을 정렬한다. SortChildrenCB 주어진 항목의 자식 항목들을 정렬한다. 따로 정렬함수를 제공해 주어야 한다. EnsureVisible 지정된 항목이 트리뷰 컨트롤 내에서 보이도록 만든다. GetCount 항목의 총수를 얻어온다. GetIndent 부모 항목과 자식 항목 간의 거리를 픽셀단위로 얻어온다. SetIndent 부모 항목과 자식 항목 간의 거리를 픽셀단위로 설정한다. MFC Tutorial
CTreeCtrl의 멤버함수(2) GetImageList 트리뷰 컨트롤과 관련된 이미지리스트를 얻어온다. SetImageList 트리뷰 컨트롤과 관련된 이미지리스트를 설정한다. ItemHasChildren 주어진 항목이 자식 노드를 갖고 있는지 여부를 알려준다. GetNextSiblingItem 트리구조에서 주어진 항목과 같은 레벨의 다음 항 목을 얻어준다. GetPrevSiblingItem 트리구조에서 주어진 항목과 같은 레벨의 이전 항 GetParentItem 트리구조에서 주어진 항목의 부모 항목을 얻음 GetSelectedItem 현재 선택된 항목이 무엇인지 알려준다. GetRootItem 루트항목이 무엇인지 알려준다. GetItem 주어진 트리뷰 항목의 속성을 돌려준다. SetItem 주어진 트리뷰 항목의 여타 속성을 설정한다. GetItemText 주어진 트리뷰 항목의 텍스트를 돌려준다. MFC Tutorial
CTreeCtrl의 멤버함수(3) SetItemText 주어진 트리뷰 항목의 텍스트를 설정한다. GetVisibleCount 현재 트리뷰 컨트롤에서 보이는 항목의 수를 돌려 준다. GetItemImage 주어진 항목의 이미지가 무엇인지 알려준다. SetItemImage 주어진 항목의 이미지를 변경한다. GetItemRect 주어진 항목을 둘러싸는 사각형이 무엇인지 얻음 MFC Tutorial
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; MFC Tutorial
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.item.iImage = 1; tvs.item.pszText = _T("Tree Child1"); m_wndTreeCtrl.InsertItem(&tvs); MFC Tutorial
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; } MFC Tutorial
SetImageList 두번째 인자 IDI_ICON1 IDI_ICON2 IDI_ICON3 TVSIL_NORMAL 항목의 선택시와 보통 때의 모습만을 담고 있은 경우 TVSIL_STATE 선택 유무 말고 사용자 나름대로의 기준으로 항목 상태 를 지정하려는 경우 IDI_ICON1 IDI_ICON2 IDI_ICON3 MFC Tutorial
실행모습 MFC Tutorial
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; MFC Tutorial
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; MFC Tutorial
TV_ITEM(2) mask hItem : 이 스트럭처가 나타내고 있는 항목 새로운 항목의 삽입 시에는 0을 지정해야 TVIF_CHILDREN cChildren 필드를 사용한다. TVIF_HANDLE hItem 필드를 사용한다. TVIF_IMAGE iImage 필드를 사용한다. TVIF_PARAM lParam 필드를 사용한다. TVIF_SELECTEDIMAGE iSelectedImage 필드를 사용한다. TVIF_STATE state, stateMask 필드를 사용한다. TVIF_TEXT pszText, cchTextMax 필드를 사용한다. hItem : 이 스트럭처가 나타내고 있는 항목 새로운 항목의 삽입 시에는 0을 지정해야 MFC Tutorial
TV_ITEM(3) pszText : 항목에 들어갈 텍스트 cchTextMax : pszText 필드가 가리키는 버퍼의 크기 LPSTR_TEXTCALLBACK이면 항목의 디스플레이 책임은 부모 윈도우가 진다. 이때 부모 윈도우에게 TVN_SETDISPINFO 메시지가 넘어간다. cchTextMax : pszText 필드가 가리키는 버퍼의 크기 MFC Tutorial
TV_ITEM(4) iImage : 정상상태에 있을 때에 해당하는 이미지(이미지리스트에서의 인덱스) iSelectedImage : 선택상태에 있을 때에 해당하는 이미지 cChildren : 자식 항목을 가질 것인지 여부를 지정 0 : 자식 항목이 없음 1 : 자식 항목이 있음 lParam : 이 항목과 관련해서 따로 저장하고 싶은 32비트 값을 지정할 때 사용 MFC Tutorial
트리뷰의 알림 메시지 TVN_BEGINDRAG 왼쪽 마우스버튼을 이용해 드래그 작업이 시작할 때 발생한다. TVN_BEGINRDRAG 오른쪽 마우스 버튼을 이용해 드래그 작업이 시작 할 때 발생한다. TVN_BEGINLABELEDIT 레이블 편집이 시작될 때 발생 TVN_ENDLABELEDIT 레이블 편집이 끝날 때 발생 TVN_DELETEITEM 항목이 삭제될 때 발생 TVN_ITEMEXPANDING 항목 하나가 펼쳐져야 함을 알리기 위해 발생 TVN_ITEMEXPANDED 항목 하나가 펼쳐졌음을 알리기 위해 발생 TVN_KEYDOWN 키가 눌렸을 때 발생. 이는 트리뷰 컨트롤이 입력 포커스를 갖고 있을 때 발생한다. TVN_SELCHANGING 현재 선택된 항목이 다른 항목으로 변경될 때 발생 TVN_SELECTED 현재 선택된 항목이 다른 항목으로 변경된 다음 발생 MFC Tutorial
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; } MFC Tutorial