MFC 기초 정리

C++ 2011. 1. 21. 09:44

 

 

Win32 Project 자동 생성되는 중요(기본) 함수 구성

    MyRegisterClass()    : 생성할 윈도우 구조체 완성 및 윈도우 클래스 등록

    InitInstance()        : 윈도우 생성

    GetMessage()        : 응용 프로그램의 메시지 큐를 검사하여 신규 메세지가 있는지 확인

    TranslateAccelerator()    : 액셀러레이터키 테이블의 단축키 입력시 해당 메뉴 실행

    TranslateMessage()    : 메시지 해석

    DispatchMessage()    : 메세지 프로시저 호출

 

MFC SDI project 생성시 기본 클래스

    CMainFrame    : 윈도우 프레임, 타이틀, 메뉴 등을 관리하는 메인 프레임 클래스

    CXXXXApp    : 응용 프로그램 자체에 대한 클래스

    CXXXXDoc    : 데이터 관리를 위한 클래스

    CXXXXView    : 사용자 입력이나 화면에 보여주는 부분에 대한 클래스

 

CWnd 클래스 : 모든 윈도우의 Base Class

    주요 멤버 함수

        Create()/CreateEx()    : 윈도우 생성 함수

        PreCreateWindow()    : 윈도우 생성 직전에 호출되는 함수

        GetStyle()/GetExStyle(): 윈도우 기본/확장 스타일 반환 함수

        PreSubclassWindow()    : Sub classing 직전에 호출되는 virtual 함수

        GetSafeHwnd()    : 생성된 윈도우의 핸들 반환 함수

    기본 윈도우 스타일

        WS_BORDER    : 테두리 생성

        WS_CAPTION    : 제목 표시줄 및 테두리 생성

        WS_CHILD,WS_CHILDWINDOW: 자식 윈도우. WS_POPUP과 같이 쓸 수 없음

        WS_DISABLED    : 비활성화 시킴

        WS_HSCROLL, WS_VSCROLL    : scroll bar 생성

        WS_ICONIC,WS_MINIMIZE    : 윈도우 최소화 생성

        WS_MAXMIZE    : 윈도우 최대화 생성

        WS_POPUP    : 화면에 독립적인 윈도우 생성.

        WS_SYSMENU    : 제목 표시줄에 시스템 메뉴 생성

        WS_MINIMIZEBOX, WS_MAXIMIZEBOX: 최소화,최대화 버튼 생성. WS_CAPTION과 같이 사용해야 함

        WS_SIZEBOX,WS_THICKFRAME(동일) : 크기변경을 위한 테두리 생성

        WS_OVERLAPPED,WS_TILED(동일) : 다른 윈도우와 겹칠 수 있는 윈도우. 제목 표시줄과 테두리를 갖음.

 

CWinApp 클래스 : CXXXXApp의 Base Class

    주요 멤버 변수

        m_hInstance    : 현재 응용 프로그램의 인스턴스 핸들. (WinMain()의 hInstance와 동일)

        m_lpCmdLine    : WinMain()의 lpCmdLine과 동일

        m_mCmdShow    : WinMain()의 nCmdShow와 동일

        m_pActiveWnd: 최상위 프레임 윈도우의 포인터. SDI의 경우 CMainFrame의 포인터.

        m_pszAppName : 응용 프로그램의 제목. 문자열 테이블의 AFX_IDS_APP_TITLE 값

        m_pszExeName : 실행파일의 확장자를 제외한 파일명

 

MFC 메시지 호출 흐름

    01: Function: CSdiSeqApp::CSdiSeqApp()

    02: Function: CSdiSeqApp::InitInstance()

    03: Function: CSdiSeqDoc::CSdiSeqDoc(void)

    04: Function: CMainFrame::CMainFrame(void)

    05: Function: CMainFrame::LoadFrame()

    06: Function: CMainFrame::PreCreateWindow()

    07: Function: CMainFrame::PreCreateWindow()

    08: Function: CMainFrame::OnCreate()

    09:     Function: CMainFrame::OnCreateClient()

    10:         Function: CSdiSeqView::CSdiSeqView()

    11:         Function: CSdiSeqView::Create()

    12:         Function: CSdiSeqView::PreCreateWindow()

    13:         Function: CSdiSeqView::OnCreate()

    14:         Function: CSdiSeqView::OnShowWindow()

    15:     CMainFrame::OnCreateClient() - Return

    16: CMainFrame::OnCreate() - Return

    17: Function: CSdiSeqDoc::OnNewDocument()

    18: Function: CSdiSeqView::OnInitialUpdate()

    19: Function: CMainFrame::OnActivateApp()

    20: Function: CMainFrame::OnActivate()

    21: Function: CMainFrame::OnShowWindow()

    22: Function: CSdiSeqView::GetDocument()

    23: Function: CSdiSeqApp::Run()

    24:     Function: CMainFrame::OnClose()

    25:         Function: CMainFrame::OnShowWindow()

    26:         Function: CMainFrame::OnActivate()

    27:         Function: CMainFrame::OnActivateApp()

    28:         Function: CMainFrame::DestroyWindow()

    29:         Function: CMainFrame::OnDestroy()

    30:         Function: CSdiSeqView::OnDestroy()

    31:         Function: CSdiSeqView::PostNcDestroy()

    32:         Function: CSdiSeqView::~CSdiSeqView()

    33:         Function: CMainFrame::OnNcDestroy()

    34:             Function: CMainFrame::PostNcDestroy()

    35:             Function: CMainFrame::~CMainFrame()

    36:         CMainFrame::OnNcDestroy() - Return

    37:         Function: CSdiSeqDoc::~CSdiSeqDoc()

    38:     CMainFrame::OnClose() - Return

    39:     Function: CSdiSeqApp::ExitInstance()

    40: CSdiSeqApp::Run() - Return

    41: The program '[3764] SdiSeq.exe: Native' has exited with code 0 (0x0)

 

MFC 응용 프로그램 시작 흐름

    01: Function: CSdiSeqApp::CSdiSeqApp()

    02: Function: CSdiSeqApp::InitInstance()

    03: Function: CSdiSeqDoc::CSdiSeqDoc(void)

    04: Function: CMainFrame::CMainFrame(void)

    05: Function: CMainFrame::LoadFrame()

    06: Function: CMainFrame::PreCreateWindow()

    07: Function: CMainFrame::PreCreateWindow()

    08: Function: CMainFrame::OnCreate()

    09:     Function: CMainFrame::OnCreateClient()

    10:         Function: CSdiSeqView::CSdiSeqView()

    11:         Function: CSdiSeqView::Create()

    12:         Function: CSdiSeqView::PreCreateWindow()

    13:         Function: CSdiSeqView::OnCreate()

    14:         Function: CSdiSeqView::OnShowWindow()

    15:     CMainFrame::OnCreateClient() - Return

    16: CMainFrame::OnCreate() - Return

    17: Function: CSdiSeqDoc::OnNewDocument()

    18: Function: CSdiSeqView::OnInitialUpdate()

    19: Function: CMainFrame::OnActivateApp()

    20: Function: CMainFrame::OnActivate()

    21: Function: CMainFrame::OnShowWindow()

    22: Function: CSdiSeqView::GetDocument()

    23: Function: CSdiSeqApp::Run()

 

MFC 응용 프로그램 종료 흐름

    23: Function: CSdiSeqApp::Run()

    24:     Function: CMainFrame::OnClose()

    25:         Function: CMainFrame::OnShowWindow()

    26:         Function: CMainFrame::OnActivate()

    27:         Function: CMainFrame::OnActivateApp()

    28:         Function: CMainFrame::DestroyWindow()

    29:         Function: CMainFrame::OnDestroy()

    30:         Function: CSdiSeqView::OnDestroy()

    31:         Function: CSdiSeqView::PostNcDestroy()

    32:         Function: CSdiSeqView::~CSdiSeqView()

    33:         Function: CMainFrame::OnNcDestroy()

    34:             Function: CMainFrame::PostNcDestroy()

    35:             Function: CMainFrame::~CMainFrame()

    36:         CMainFrame::OnNcDestroy() - Return

    37:         Function: CSdiSeqDoc::~CSdiSeqDoc()

    38:     CMainFrame::OnClose() - Return

    39:     Function: CSdiSeqApp::ExitInstance()

    40: CSdiSeqApp::Run() - Return

    41: The program '[3764] SdiSeq.exe: Native' has exited with code 0 (0x0).

 

메시지 흐름과 PostMessage(), Send Message()

    PostMessage() 를 사용한 메시지 처리 과정

Message queue

Message loop

CMainFrame::PreTranslateMessage()

CMainFrame::WindowProc()

CMainFrame message handler function (정의한 메시지 함수)

SendMessage() 를 사용한 메시지 처리 과정

CMainFrame::WindowProc()

CMainFrame message handler function (정의한 메시지 함수)

    SendMessage()는 WindowProc()을 바로 호출하기 때문에 PostMessage()처럼 그 이전 처리를 하지 않아

    문제가 발생할 수 있다. 가급적이면 PostMessage()만 쓰도록 권장된다.

 

키보드 관련

    WM_SYSKEYDOWN, WM_SYSKEYUP    : alt, F10 키 입력시 발생되는 메시지

    WM_KEYDOWN, WM_KEYUP    : 키 입력시 발생. ASCII 코드 문자인 경우 TranslateMessage()가 WM_CHAR 메시지도 발생시킴

        OnKeyDown()의 nChar 인자    : 눌린 키의 가상 키 값

        OnKeyDown()의 nRepCnt 인자 : 키의 반복 횟수(보통 1). 키를 누르고 있는 경우 2나 3이 될 수 있음

        OnKeyDown()의 nFlags 인자    : 키보드 상세 정보.

0~7 bit    : scan code. H/W적인 키 식별 값. 키보드 제조사별로 다를 수 있음.

8 bit    : extended key. 1이면 확장 키.

9~10 bit: 미사용

11~12 bit: OS 사용 영역

13 bit    : context code. 1이면 alt 키가 눌린 상태.

14 bit    : previous key state. nChar의 이전 상태. 1이면 이전 키가 눌려있음을 의미.

15 bit    : transition code. 0이면 키룰 누른 상태. 항상 0.

마우스 관련

    OnMouseMove()의 nFlgs 인자가 MK_LBUTTON이면 마우스 왼쪽 버튼이 눌린 상태를 의미

    SetCapture(), ReleaseCapture() : 마우스가 윈도우 영역을 벗어나도 마우스 메시지 수신

    _TrackMouseEvent() : SetCapture()와 동일한 동작이지만 사용방법은 다름.

        OS에 자신의 윈도우 등록하면 마우스가 해당 영역을 벗어나면 WM_MOUSELEAVE 메시지 발생 시킴.

        버튼 같은 윈도우에 마우스가 올라왔을때와 빠져나갈 때 효과 처리시 SetCapture()보다 좋은 처리 방법.

        사용예)

1 예를 위해 CWnd 상속한 CXXXXWnd 클래스 생성 후 생성(Create)

2 CXXXXWnd::OnMouseMove() 에서 _TrackMouseEvent()로 마우스 추적 사용.

(MouseMove 이므로 마우스가 해당 윈도우 위에 올라왔음을 때의 처리가 됨)

If (m_bTrack == FALSE)

{

TRACKMOUSEEVENT MouseEvent;

::ZeroMemory(&MouseEvent, sizeof(MouseEvent));

MouseEvent.cbSize        = sizeof(MouseEvent);

MouseEvent.dwFlags        = TME_LEAVE;

MouseEvent.hwndTrack    = m_hWnd;

MouseEvent.dwHoverTime    =0;

m_bTrack = ::_TrackMouseEvent(&MouseEvent);

if (m_bTrack) SetWindowText(_T("Tracking"));    

}

3 CXXXXWnd::OnMouseLeave()로 마우스가 빠져나갔을 때(WM_MOUSELEAVE) 동작 처리 및 마우스 추적 중단

TRACKMOUSEEVENT MouseEvent;

::ZeroMemory(&MouseEvent, sizeof(MouseEvent));

MouseEvent.cbSize        = sizeof(MouseEvent);

MouseEvent.dwFlags        = TME_CANCEL;

MouseEvent.hwndTrack        = m_hWnd;

::_TrackMouseEvent(&MouseEvent);

 

m_bTrack = FALSE;

SetWindowText(_T("WM_MOUSELEAVE"));

 

자주 사용되는 함수

    SetWindowPos()    : 윈도우 위치, 크기, Z-order 변경 함수.

        pWndInsertAfter 인자 : Z-order 설정.(CWnd::wndBottom, wndTop, wndTopMost, wndNoTopMost)

        x, y    : 위치 지정

        cx, cy    : 크기 지정

        nFlags    : 함수 동작 설정. (SWP_HIDEWINDOW, SWP_SHOWWINDOW, SWP_NOACTIVATE, SWP_NOMOVE,

SWP_NOREDRAW, SQPNOSIZE, SWP_NOZORDER)

    SetWindowText(), GetWindowText() : 윈도우 텍스트 변경/획득

    ::GetKeyState()    : 특정 키의 상태 정보 리턴. HIBYTE()로 키가 누른 상태인지 확인. LOBYTE()로 토글(toggle)정보 확인

                토글(toggle) 키 : Caps Lock, Number Lock, Scroll Lock 키 등..

    RedrawWindow()    : WM_PAINT 메시지 호출하여 Client View 윈도우를 다시 그림.

CRect 클래스

        PtInRect(Point point)    : point가 CRect 영역 안에 있는지 확인

::GetSysColor(COLOR_3DSHADOW)    : 주어진 인덱스에 해당하는 시스템 색상 반환

 

GDI (Graphic Device Interface)

    일반 함수에서 그리기 수행시 redraw를 못하는 문제 가 있으므로 OnPaint()에서 작성하도록 한다.

        Ex) CXXXXView::OnLButtonDown(UINT nFlags, CPoint point) 함수 에서 그리기

            CDC* pDC = GetDC();

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

            ReleaseDC(pDC);

        Ex) CXXXXView::OnPaint() 에서 그리기

            CPaintDC dc(this);

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

    CDC 파생 클래스

        CPaintDC    : CClientDC와 비슷. BeginPaint()/EndPaint() 호출로 WM_ERASEBKGND메시지 발생.(OnPaint()에서 사용)

        CClientDC    : 윈도우 클라이언트 영역에 대한 그리기의 경우 사용.

        CWindowDC    : 윈도우 모든 영역에 대한 그리기의 경우 사용. (다른 윈도우에 대해서도 그리기 가능. 화면 캡쳐시 사용)

        CMetaFileDC    : WMF(Window Meta File), EMF(Enhanced Meta File) 파일에 대한 그리기시 사용.

    CDC의 Draw3dRect() : 왼쪽/위, 오른쪽/아래의 선 색을 지정할수 있는 테두리 없는 사각형을 그림

        Ex) dc.Draw3dRect(CRect(10,10,100,100), ::GetSysColor(COLOR_3DLIGHT), ::GetSysColor(COLOR_3DSHADOW));

    사각형 그리기

        CPaintDC dc(this);

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

CDC의 FillSolidRect() : 펜/브러시 필요 없이 지정한 색의 테두리 없는 사각형을 그림

dc.FillSolidRect(CRect(10, 10, 100, 100), ::GetSysColor(COLOR_BTNFACE));

    CPen : 선에 대한 스타일 지정

        CPaintDC dc(this);

DWORD stype[] = {6, 3, 9};

LOGBRUSH lb;

lb.style = BS_SOLID;

lb.lbColor = RGB(255, 0, 0);

CPen NewPen;

NewPen.CreatePen(PS_GEOMETRIC | PS_USERSTYLE | PS_ENDCAP_FLAT, 10, &lb, 2, style);

/* 간단한 CPen NewPen(PS_SOLID, 10, RGB(255,0,0)); 도 있음 */

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

dc.MoveTo(40, 40);

dc.LineTo(240, 40);

dc.SelectObject(pOldPen);

 

    CBrush : 면에대한 스타일 지정

        //특정 패턴 적용

        CPaintDC dc(this);

        CBrush NewBrush(HS_CROSS, RGB(192, 0, 0));

        CBrush* pOldBrush = dc.SelectObject(&NewBrush);

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

        dc.SelectObject(pOldBrush);

 

        //이미지 적용

        CPaintDC dc(this);

        CBitmap Bmp;

        Bmp.LoadBitmap(IDB_BITMAP1);

        CBrush NewBrush;

        NewBrush.CreatePatternBrush(&Bmp);

        CBrush* pOldBrush = dc.SelectObject(&NewBrush);

        CRect Rect;

        GetClientRect(&Rect);    //클라이언트 뷰의 크기 구함

        dc.Rectangle(&Rect);

        dc.SelectObject(pOldBrush);

    다각형 그리기

        CPaintDC dc(this);

        dc.BeginPath();

            dc.MoveTo(190, 40);

            dc.LineTo (290, 190);

            dc.LineTo (90, 190);

            dc.LineTo (190, 40);

        dc.EndPath();

        dc.StrokeAndFillPath();

        혹은

        POINT arPt[3] = {{190,40}, {290,190}, {90,190}};

        dc.Polygon(arPt, 3);

    타원 그리기 : dc->Ellipse(20, 20, 140, 140);

    부채꼴 그리기

        CPaintDC dc(this);

        CRect PieRect(20, 20, 140, 140);

        dc.Pie(PieRect, CPoint(PieRect.right, PieRect.CenterPoint().y), CPoint(PieRect.CenterPoint().x, PieRect.top));

    모서리가 둥근 네모 : dc.RoundRect(CRect(20, 20, 140, 140), CPoint(20, 20));

    Font 설정과 TextOut()

        LOGFONT lf;

        ::ZeroMemory(&lf, sizoof(lf));

        lf.lfHeight = 20;

        wsprintf(lf.lfFace.Name, _T("%s"), _T("Arial"));

        CFont Font;

        Font.CreateFontIndirect(&lf);

        CFont* pOldFont = dc.SelectObject(&Font);

        dc.TextOut(10, 10, _T("Test String"));

        dc.SelectObject(pOldFont);

        Font.DeleteObject();

    CDC의 SetTextColor() : 출력할 문자열 색 지정

         dc.SetTextColor(RGB(255,0,0));

    TabbedTextOut() : 탭 크기 설정

        Int arrTabStop[] = {20, 40};    //첫번째 탭은 20, 두번째 탭은 40 픽셀의 크기 지정

        dc.TabbedTextOut(20, 20, _T("\t\tTest String"), 2, arrTapStop, 20);

    DrawText() : 지정된 사각형 안에 문자열 출력

        CRect Rect(10, 10, 100, 100);

dc.DrawText(_T("Test String"), &Rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER);

 

    Bitmap 출력 : BitBlt() – 이미지 출력

        CPaintDC dc(this);

        CDC MemDC;

        MemDC.CreateCompatibleDC(&dc); //dc와 호환되는 메모리 DC 생성

        CBitmap bmp;

        bmp.LoadBitMap(IDB_Test_Image);    //Bitmap 리소스 로딩

        BITMAP bmpInfo;

        Bmp.GetBitmap(&bmpInfo);    //Bitmap 정보 획득

        CBitmap* pOldBmp = MemDC.SelectObject(&bmp);    //메모리 DC 선택

        dcBitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &MemDC, 0, 0, SRCCOPY); //메모리DC의 bitmap을 화면DC로 출력

 

    Bitmap 출력: StretchBlt() - 이미지 확대/축소 가능

        dc.Stretch(10, 10,    //출력 좌표

            bmpInfo.bmWidth*2, bmpInfo.bmHeight*2,    //폭,높이 2배 확대

            &MemDC,

            350, 200,    //원본 이미지 좌표

            bmpInfo.bmWidth, bmpInfo.bmHeight,    //원본 이미지 폭,높이

            SRCCOPY);

 

    Bitmap 출력 : TransparentBlt() – 특정색 투명 처리하여 이미지 출력

        dc.TransparentBlt(10, 10,

            bmpInfo.bmWidth*2, bmpInfo.bmHeight*2,

            &MemDC,

            0, 0,

            bmpInfo.bmWidth, bmpInfo.bmHeight,

            RGB(0,0,0));    //검은색 투명 처리

 

    Bitmap 출력 : AlphaBlend() – 반투명 이미지 출력

        BLENDFUNCTION bf;

        bf.BlendOp    = AC_SRC_OVER;    //배경과 이미지를 섞음

        bf.BlendFlags    = 0;            //항상 0

        bf.SourceConstantAlpha = 50;    //0~255 투명도 지정

        bf.AlphaFormat = 0;    //이미지가 32bit인 경우 AC_SRC_ALPHA

        dc.AlphaBlend(10, 100,

            bmpInfo.bmWidth*2, bmpInfo.bmHeight*2,

            &MemDC,

            0, 0,

            bmpInfo.bmWidth, bmpInfo.bmHeight,

            bf);

 

    CImage 클래스 : bmp, jpg, png, gif 이미지 출력/저장을 위한 클래스

        CImage 클래스로 이미지 출력

             #include <atlimage.h>

            ..

            CImage Image;

                HRESULT hResult = Image.Load(_T("이미지파일.jpg"));    //이미지 로딩

                If (FAILED(hResult)) 이미지 로딩 실패..

            또는

                Image.LoadFromResource(AfxGetInstanceHandle(), IDB_Image_Test);    //이미지 리소스에서 로딩

            Image.BitBlt(dc.m_hDC, 0, 0);        //이미지 출력

            ..

        CImage의 이미지 DC사용시 GetDC()와 ReleaseDC()는 한 쌍을 이룬다.

        이미지 위에 다른 이미지나 글자 출력시 속도 향상을 위해 사용.

            CImage Image;

            Image.LoadFromResource(AfxGetInstanceHandle(), IDB_Image_Test);    //이미지 리소스에서 로딩

            CDC* pDC = CDC::FromHandle(Image.GetDC());    //비트맵 이미지의 DC 생성

            pDC->SetBkMode(TRANSPARENT);    //배경은 투명게 함

            PDC->TextOut(10, 10, _T("Test String"));

            Image.ReleaseDC();

            Image.BitBlt(dc.m_hDC,0,0);

 

        바탕화면 일부 캡쳐 및 흑백 변환 출력 : CXXXXView::OnLButtonDown()에서 작성

            CWnd* pWndDesktop = GetDesktopWindow();    //바탕화면 윈도우 객체 포인터 획득

            CWindowDC SrcDC(pWndDesktop);            //바탕화면 윈도우 DC

            CClientDC dc(this);                    //뷰 윈도우 DC

 

            CImage Image;

            Image.Create(300, 300, SrcDC.GetDeviceCaps(BITSPIXEL);    //바탕화면 이미지 300*300 획득

 

//이미지DC,화면DC에 윈도우DC 출력

            CDC* pDC = CDC::FromHandle(Image.GetDC());

            pDC->BitBlt(0,0,300,300,&SrcDC,0,0,SRCCOPY);

            Image.ReleaseDC();

            

            //200*200만 흑백으로 변환

            COLORREF rgb;

            for (int x=0; x<200; x++)

{

    for(int y=0; y<200; ++y)

    {

        rgb = Image.GetPixel(x, y);

        RGBtoGray(rgb);

        Image.SetPixel(x, y, rgb);

    }

}

            Image.BitBlt(dc.m_hDC, 0, 0);    //이미지 화면DC에 출력

            ..

            Inline void RGBtoGray(COLORREF& rgb)    //픽셀 흑백 변환 함수

            {

                BYTE by Gray = (GetRValue(rgb)*30+GetGValue(rgb)*59+GetBValue(rgb)*11)/100;

                Rgb = RGB(byGray, byGray, byGray);

            }

 

        바탕화면 캡쳐하여 jpg 저장

            CWnd* pWndDesktop = GetDesktopWindow();    //바탕화면 윈도우 객체 포인터 획득

            CWindowDC SrcDC(pWndDesktop);            //바탕화면 윈도우 DC

            CClientDC dc(this);                    //뷰 윈도우 DC

 

            CRect Rect;

            pWndDesktop->GetWindowRect(&Rect);    //바탕화면 크기 획득

            int cx = Rect.Width();

            int cy = Rect.Height();

 

            CImage Image;

            Image.Create(cx, cy, SrcDC.GetDeviceCaps(BITSPIXEL);    //바탕화면 이미지 300*300 획득

 

//이미지DC,화면DC에 윈도우DC 출력

            CDC* pDC = CDC::FromHandle(Image.GetDC());

            pDC->BitBlt(0,0,cx,cy,&SrcDC,0,0,SRCCOPY);

            Image.ReleaseDC();

 

            Image.Save(_T("desktop.jpg"), GdiPlus::ImageFormatJPEG);    //jpg로 저장

            ::ShellExecute(NULL, _T("open"), _T("desktop.jpg"), NULL, NULL, SW_SHOW);    //실행

 

    CRgn 클래스 : 윈도우 영역 설정을 객체화한 클래스

        사용 예) OnPaint()

            CPaint DC(this);

            //상자 2개 그리기

            CRect rectLeft = CRect(50, 50, 250, 150);

            CRect rectRight = CRect(250, 50, 450, 150);

            dc.FillSolidRect(&rectLeft, RGB(192, 0, 0));

            dc.FillSolidRect(&rectRight, RGB(192, 192, 192));

 

            //상자 2개 크기로 영역 만들기

            CRgn rgnLeft, rgnRight;

            rgnLeft.CreateRectRgnIndirect(rgnLeft);

            rgnRight. CreateRectRgnIndirect(rgnRight);

 

            //Font 변경

            LOGFONT lf;

            ::ZeroMemory(&lf, sizeof(lf));

            lf.lfHeight = 72;

            wprintf(lf.lfFaceName, _T("%s"), _T("Arial Blak"));

            CFont NewFont;

            NewFont.CreateFontIndirect(&lf);

            CFont* pOldFont = dc.SelectObject(&NewFont);

 

            dc.SetBkMode(TRANSPARENT);

            //dc.TextOut(60, 65, _T("TEST STRING"));

 

            dc.SetTextColor(RGB(192,192,192));

            dc.SelectClipRgn(&rgnLeft);    //출력할 영역 설정

            dc.TextOut(60, 65, _T("TEST STRING"));

 

            dc.SetTextColor(RGB(192, 0, 0));

            dc.SelectClipRgb(&rgnRight);    //출력할 영역 설정

            dc.TextOut(60, 65, _T("TEST STRING"));

 

            dc.SelectObject(pOldFont);

 

        타원모양의 영역 지정시

            CRect Rect(10, 10, 100, 100);

            CRgn Rgn;

            Rgn.CreateEllipticRgb(Rect.left, Rect.top, Rect.right, Rect.bottom);

            dc.SelectClipRgn(&Rgn);

 

        두영역의 조합된 영역 지정시 : 아래 예는 OnCreate()에서 윈도우 전체의 그리기 영역지정임.

            CRgn RgnRect1, RgnRect2, RgnTotal;

            RgnRect1.CreateRectRgn(0, 0, 100, 100);    //영역1

            RgnRect2.CreateRectRgn(70, 70, 170, 170);    //영역2

            RgnTotal.CreateRectRgn(0, 0, 0, 0);        //영역1,2가 조합될 영역이므로 좌표가 무의미하여 0지정

            

            RgnTotal.CombineRgn(&RgnRect1, &RgnRect2, RGN_XOR);    //XOR로 두 영역 조합

            SetWindowRgn((HRGN)RgnTotal, TRUE);    //조합된 영역을 CMainFrame윈도우 영역으로 지정

 

    CDC의 SetROP2() : DC의 그리기 모드 변경 (기본 R2COPYPEN)

        dc.SetROP2(R2_NOT);    //그리기 모드를 반전 모드로 변경

 

Mapping 모드 변경

    Ex) OnPaint()에서

    CPaintDC dc(this);

    dc.SetMapMode(MM_ISOTROPIC);

    dc.SetWindowExt(100, 100);    //논리적인 화면CD 크기를 100*100으로 고정

    dc.SetViewportExt(50, 50);    //뷰 포트 크기 변경

    dc.SetViewportOrg(300, 300);    //픽셀단위좌표로 (300, 300)이 논리적 좌표(0,0)이 되도록 함

    … 그리기 작업 ...

 

프린터 출력

    OnPaint() : 화면 출력용

    OnPrint() : 페이지 단위의 프린터 출력시 각 페이지 출력시 마다 호출되는 함수

    OnDraw() : 화면 출력 및 프린트 출력시 동통적으로 사용되는 함수

    OnPreparePrinting()    : 인쇄 대화 상자 출력 직전에 호출되는 함수

    OnBeginPrinting()    : 인쇄 작접 전 초기화 작업을 위해 호출되는 함수

    OnEndPrinting()    : 인쇄 작업 후 정리 작업을 위해 호출되는 함수

 

    OnDraw() 함수에선 pDC->IsPrinting()을 통해 프린터 출력인지 구분할 수 있다.

        Ex) OnDraw(CDC* pDC) 에서

            CXXXXDoc* pDoc = GetDocument();

            ASSERT_VALID(pDoc);

            If (!pDoc) return;

 

            //화면 정보

            CString strtmp = _T("");

            Strtmp.Format(_T("Pixel(HORZRES:%d, VERTRES:%d), mm(HORZSIZE:%d, VERTSIZE:%d)"),

                pDC->GetDeviceCaps(HORZRES),    //픽셀 단위 수평 해상도

                pDC->GetDeviceCaps(VERTRES),    //픽셀 단위 수직 해상도

                pDC->GetDeviceCaps(HORZSIZE),    //mm 단위 수평 길이

                pDC->GetDeviceCaps(VERTSIZE));    //mm 단위 수직 길이

 

            if (pDC->IsPrinting())    //프린터 출력이라면..

            {    //6배 확대 (출력시 대략적인 경험치임)

                pDC->SetMapMode(MM_ISOTROPIC);

                pDC->SetWindowExt(100, 100);

                pDC->SetViewportExt(600, 600);

            }

            … 그리기 작업 …

 

Visual C++ 2008 추가된 컨트롤

네트워크 주소 컨트롤 (CNetAddressCtrl)

링크 컨트롤 (CLinkCtrl, SysLink Control)

스플릿 버튼(CSplitButton) : Vista 전용이라 비권장됨. Feature Pack의 기능 사용 권장.

명령 버튼 컨트롤 (CButton의 새로운 스타일)

 

메뉴/바로가기키/도구모음/상태표시줄

    메뉴는 CMainFrame안에 있지만 독립된 윈도우는 아니며 메뉴 클릭시 나오는 목록은 윈도우이다.

    

    리소스 편집에서 메뉴를 추가.

    메뉴 단축키 지정

        메뉴의 속성창에서 Caption에 "파일(&F)…\tCtrl+O" 와 같이 단축키 지정 가능

        또는

        리소스뷰의 Accelator에서 직접 추가 및 단축키 지정으로 메뉴ID와 연결

 

    메뉴 이벤트 지정

        (WinProc)메뉴 선택시 WM_COMMAND 메시지 발생. LOWORD(wParam) 로 선택된 메뉴ID 구분

        COMMAND 이벤트 : 메뉴 클릭시 실행 코드를 작성. CMainFrame의 Events에서 추가

        UPDATE_COMMAND_UI이벤트 : 하나의 메뉴가 선택되면 UPDATE_COMMAND_UI가 구현된 함수들이 모두 호출됨.

CMainFrame의 Events에서 추가, 인자로 받는 pCmdUI를 통해 Enable(), SetText(), SetCheck()등 사용 가능.

        **.보통 이벤트 등록은 CMainFrame에서 하며(접근 용의성 때문..) View에 의존적인 것만 View 클래스에 정의한다.

            View -> Doc -> CMainFrame -> App 클래스 순으로 메시지 처리 함수를 찾는다.

            Dialog의 경우 CDialog -> CDialog를 소유한 윈도우 ->CWinApp 순이다.

 

    툴바 아이콘과 메뉴 연결

        툴바의 버튼 선택 후 속성에서 메뉴 ID 지정으로 연결

 

    TrackPopupMenu()로 오른쪽 마우스 팝업 메뉴 작성

        Ex) CXXXView::OnRButtonDonw(…)에서

        CMenu* pMainMenu = AfxGetMainWnd()->GetMenu();    //CMainFrame의 메뉴 포인터 획득

        CMenu* pSubMenu = pMainMenu->GetSubMenu(40);    //메인메뉴의 4번째 sub메뉴 포인터 획득

 

        CPoint ptMenu = point;

        ClientToScreen(&ptMenu);    //스크린 기준으로 좌표 변환

        //팝업 메뉴 출력 : 마지막 AfxGetMainWnd()를 통해 CMainFrame에게 WM_COMMAND를 보낸다.

        //만약 this를 주게 되면 View에 WM_COMMAND를 보내며 View에 메뉴처리 함수가 없으면 동작하지 않음

        pSubMenu->TrackPopupMenu(TPM_LEFTBUTTON|TPM_LEFTALIGN, ptMenu.x, ptMenu.y, AfxGetMainWnd());

 

    툴바 : 툴바는 CToolBarCtrl을 사용하는데 새로 나온 2008 Feature Pack 때문에 구식 유물(?)이 되어가고 있다.

    상태 표시줄 : CStatusBar 를 사용하며 SetIndicator()로 표시할 정보를 설정한다.

        기능이 빈약하므로 사용한다면 CControlBar 클래스의 파생 클래스를 직접 만들어 사용하길 권장된다.

    

Static Text (스태틱 텍스트) : CStatic

    Ex) CStatic m_wndStatic;

    m_wndStatic.Create(_T("CStatic Test"), WS_CHILD | WS_VISIBLE, CRect(10, 10, 100, 100), this, 1234);

 

    Ex) static text에 아이콘 이미지 출력 (비권장)

    m_wndStatic.Create(_T("CStatic Test"), WS_CHILD | WS_VISIBLE | SS_ICON | SS_CENTERIMAGE, CRect(10, 10, 100, 100), this, 1234);

    CWinApp* pApp = AfxGetApp();    //App 획득

    m_wndStatic.SetIcon(pApp->LoadIcon(IDR_MAINFRAME));    //ICON 출력

 

    ex) static text에 Bitmap 출력

    SS_ICON 대신 SS_BITMAP 설정. SetBitmap() 메서드 사용하여 HBITMAP를 인자로 줌. (CBitmap의 LoadBitmap() 사용)

 

Edit Control (에디트 컨트롤) : CEdit

    Ex) CEdit m_wndEdit;

    M_wndEdit.Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL, CRect(10, 10, 100, 100), this, 1234);

 

대화상자 기반 프로그램

    리소스에서 각종 컨트롤을 UI로 배치 및 속성 설정 가느ㅏㅇ

    DDX/DDV 메커니즘 지원. UpdateDate(TRUE); 면 컨트롤 값을 변수에 반영. UpdateDate(FALSE);면 변수 값을 컨트롤에 반영.

    탭 순서(Tab Order) : Ctrl+D 로 확인후 순서대로 컨트롤 선택하여 순서 지정

 

Link Control(링크 컨트롤) : CLinkCtrl

    Caption 속성에 "<a href="www.google.co.kr">google</a>" 지정 후 NM_CLICK 컨트롤 이벤트 함수 등록.

    NM_CLICK 컨트롤 이벤트 함수에서 다음과 같이 코딩

        CString strUrl = _T("");

        CLinkCtrl* pLinkCtrl = (CLinkCtrl*)GetDlgItem(IDC_SYSLINK1);

        pLinkCtrl->GetItemUrl(0, strUrl);

        ::ShellExecute(NULL, _T("open"), strUrl, NULL, NULL, SW_SHOW);

        *pResult = 0;

 

Notification Message(통지 메시지)

    자식 윈도우가 부모 윈도우에게 보내는 메시지. NM_ 으로 시작함

    컨트롤의 "이벤트 처리기 추가(A)"로 함수 등록후 CXXXXDlg 에서 OnNotify() 이벤트 함수 추가.ㅏ

    OnNotify()의 wParam 로 컨트롤 ID가 오며 lParam으로 NMHDR 구조체 포인터가 온다.

    ( LPNMHDR pHdr = (LPNMHDR)lParam; )

    NMHDR의 멤버 :

hwndFrom은 컨트롤 윈도우의 핸들

idFrom은 컨트롤 윈도우의 리소스 ID

code는 통지메세지(NM_CLICK같은..)

 

Button Control (버튼 컨트롤) : CButton

    엔터시 해당 버튼이 실행되게 하려면 Default Button 속성을 True로 설정한다.

 

Check Box (체크 박스)

    BOOL 변수로 연결가능.

Ex) BOOL m_bCheckBox;

m_bCheckBox = TRUE;

UpdateData(FALSE);

    활성/비활성화

Ex) GetDlgItem(IDC_Check_Box1)->EnableWindow(FALSE);

 

Radio Buddon (라디오 버튼)

    라디오 버튼 그룹은 항상 연속된 탭 순서를 갖어야 하며 첫 번째 라디오 버튼은 WS_GROUP 스타일을 갖어야 함.

 

Command Button (명령 버튼) : CButton

    윈도우 모습이 fade-in 되는 효과를 갖는 버튼.

    ICON 설정 가능

        CButton m_Command_Button; 변수로 연결했다면..

        m_Command_Button.SetIcon(AfxGetApp()->LoadIcon(IDR_MAINFRAME));

 

List Box (목록 상자) : CListBox

    CListBox m_List; 로 연결

    InsertString(), AddString(), DeleteString(), ResetContent()으로 항목 추가/삭제.

    FindString(), FindStringExact()로 검색

    SelectString() : FindString()과 SetCurSel()을 합친 함수

    LBN_SELCHANGE 통지 메시지 : 항목 변경시 발생하는 통지 메시지

        EX) CXXXDlg::OnLbnSelChangeList1()

        int nIndex = m_List.GetCurSel();    //선택된 인덱스 획득

        if (nIndex != LB_ERR)

        {

            CString str = _T("");

            m_List.GetText(nIndex, str);    //선택된 인덱스의 문자열을 str에 저장

        }

 

Combo Box (콤보 박스) : CComboBox

    내장 목록 상자로 ListBox 사용

    CComboBo, CString형 변수 연결 동시 사용 가능.

    AddString()으로 추가. SetEditSel()로 수정. Clear()는 SetEditSel()로 선택한 문자열 삭제.

    Type 속성으로 스타일 지정. (CBS_DROPDOWN, CBS_SIMPLE, CBS_DROPDOWNLIST)

    CBN_SELCHANGE 통지 메세지로 선택된 항목 확인 가능.

    CBN_EDITCHANGE 통지 메시지로 문자열 변경 확인 가능.

 

확장 콤보 상자 : CComboBoxEx

    내장 목록 상자로 CListCtrl 사용하여 항목에 아이콘 사용 가능. (CImageList 사용)

    //이미지 리스트 생성

    CBitmap Bmp;

    Bmp.LoadBitmap(IDB_Imagelist);    //이미지 리스트 생성

    

    CImageList m_ImgList;

    m_ImgList.Create(16, 16, ILC_COLOR24, 7, 7); //16*16 크기의 24bit 이미지 7개이며 추가로 7개 등록 가능

    m_ImgList.Add(&Bmp, RGB(255, 0, 0));

 

    CComboBoxEx m_ComboEx;

    m_ComboEx.SetImageList(&m_ImgList);

 

    //항목 추가

    CString strTmp = _T("");

    COMBOBOXEXITEM cbi;    //항목추가를 위한 구조체

    ::ZeroMemory(&cbi, sizeof(cbi));

    cbi.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE | CBEIF_TEXT;    //iImage, iSelectedImage, pszText 멤버 사용을 명시

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

{

    strTmp.Format(_T("%dth Item"), i);

    cbi.iItem        = i;    //항목 인덱스

    cbi.iImage        = i;    //항목 이미지 인덱스

    cbi.iSelectedImage    = I;    //항목 선택시 이미지

    cbi.pszTest = (LPWSTR)(LPCTSTR)strTmp;    //항목 문자열

    m_ComboEx.InsertItem(&cbi);    //항목 추가

}

m_ComboEx.SetCurSel(0);    //첫번째 항목 선택

 

Progress Control (프로그레스 컨트롤) : CProgressCtrl

    기능이나 UI가 미약하므로 서브 클래싱/확장 컨트롤 사용 필요.

    CProgressCtrl m_Progress; 로 연결.

    m_Progress.SetRange(0, 100);    //전체 범위 지정

    m_Progress.SetPos(50);    //현재 위치 지정

 

Slider Control (슬라이더 컨트롤) : CSliderCtrl

    범위를 입력받는 컨트롤

    CSliderCtrl m_Slider; 로 연결

    m_Slider.SetRange(0, 20);    //20단계 범위 지정

    m_Slider.SetPos(10);        //위치 지정

    m_Slider.SEtTicFreq(2);        //2단계씩 이동

    m_Slider.GetPos();        //현재 단계 획득

    NM_RELEASECAPTURE 통지 메시지 함수 : 슬라이더의 지시자(thumb)가 선택 완료된 후 호출됨. (이동시엔 호출 안됨)

    

    슬라이더의 지시자(Thumb) 이동시 메시지를 받아 처리하는 방법

        방법1) TRBN_THUMBPOSCHANGING 통지 메시지 함수 등록. Vista 이상 가능.

        방법 2) CSliderCtrl의 파생 클래스 생성후 직접 구현

            Ex) CSliderCtrl 파생 클래스가 CMySliderCtrl 인 경우

            CMySliderCtrl::OnLButtonDown(..)

            {

                CRect Rect;

                GetThumbRect(&Rect);    //슬라이더 지시자(thumb)의 위치 획득

                If (Rect.PtInRect(point)        //슬라이더 지시자(thumb) 클릭한 경우

                    m_bSelected = TRUE;

                else

                    m_bSelected = FALSE;

                ..

}

CMySliderCtrl::OnLButtonUp(..)

{

    m_bSelected = FASLE;

    ..

}

CMySliderCtrl::OnMouseMove(..)

{

    ..

    If (m_bSelected)

    {

        //슬라이더 지시자(thumb) 움직일때 필요한 처리 작성

}

}

 

Splin Control (스핀 컨트롤) : CSpinCtrl

    보통 Edit 컨트롤과 함께 사용. 탭 순서는 Edit 컨트롤 다음으로 반드시 연속적이어야 함.

    Alignment 속성    : 버디(buddy)로 연결된 컨트롤 기준으로 어디에 위치할지 지정 (Right Align)

    AutoBuddy 속성    : 탭 순서로 Edit 컨트롤 자동 지정 (True)

    Set Buddy Interger 속성: 버디(buddy)로 연결된 Edit 컨트롤 값이 정수가 되도록 설정

 

    CSpinButtonCtrl m_Spin; 로 연결.

    m_Spin.SetRange(0, 100);     //범위 지정

    m_Spin.SetPos(50);        //현재 위치 지정

 

    Edit 컨트롤의 EN_UPDATE 통지 메시지 함수를 등록하여 Edit 컨트롤 변경시 스핀 컨트롤의 값을 변경하도록 설정

    Ex) CXXXDlg::OnEnUpdateEditValue()

    If (m_Spin.GetSafeHwnd())

    {

        int nPos = m_Spin.GetPos();    //현재 스핀 컨트롤 값 획득

        //필요한 처리 코드 작성

    }

 

List Control (리스트 컨트롤) : CListCtrl

    탐색기의 폴더 내용이 나오는 오른쪽 스플릿 부분을 나타내는 컨트롤.

    리스트 컨트롤은 기능이 많아 무겁고 항목의 개수가 많아지면 성능이 급격히 떨어진다.

    많은 항목 개수를 사용시 성능이 중요하다면 리스트 컨트롤 대신 직접 컨트롤을 작성하여야 한다.

 

    [리스트 컨트롤 Style]

Icon Style에선 32*32나 48*48(visata) 크기의 아이콘과 Text를 사용하며

List/Report Style은 16*16 아이콘과 Text, Column header(CHeaderCtrl)를 사용한다.

아이콘 이미지는 CImageList 를 통해 등록.

View 속성을 통해 초기 속성을 정할 수 있다.

 

[변수 생성]

CListCtrl m_List; 로 연결.

    

    [큰/작은 이미지 등록]

    CImageList ImgList;        //멤버변수로 등록

    ImgList.Create(48, 48, ILC_COLOR32, 5, 0);    //큰 아이콘 이미지 리스트

    CImageList ImgListSmall;    //멤버변수로 등록

    ImgListSmall.Create(16, 16, ILC_COLOR32, 5, 0);    //작은 아이콘 이미지 리스트

 

    CString strItem = _T("");

    For (int i=0; i<5; ++i)

    {

        ImgList.Add(AfxGetApp()->LoadIcon(IDI_ICON1+i));        //큰 아이콘 이미지 리스트 추가

        ImgListSmall.Add(AfxGetApp()->LoadIcon(IDI_ICON1+i));    //작은 아이콘 이미지 리스트 추가

        strItem.Format(_T("%dth Item"), i);

 

        m_List.InsertItem(i, strItem, i);    //항목 추가. i번째 항목을 strItem 문자열로 i번째 이미지 추가

    }

    //리스트 컨트롤에 이미지 리스트 등록

    m_List.SetImageList(&ImgList, LVSIL_NORMAL);    //큰 아이콘 : LVSIL_NORMAL

    m_List.SetImageList(&ImgListSmall, LVSIL_SMALL);    //작은 아이콘 : LVSIL_SMALL, 상태 이미지 : LVSIL_STATE

 

    [InsertItem(항목 추가 함수) 에 사용되는 LVITEM 구조체]

    InsertItem()은 4가지 오버로딩 함수가 제공되며 그중 1개는 LVITEM 구조체를 사용하는 함수가 있는데

LVITEM 구조체는 상세한 정보를 기술하여 항목을 추가할 수 있게 해주며 추가와 동시에 설정한 상태로 표시.

LVITEM 구조체 멤버

mask        : LVITEM 구조체 멤버중 사용할 멤버를 지정

iItem        : 추가할 항목의 인덱스

iSumItem    : 하나의 항목에 여러 컬럼 존재시 하위 컬럼 인덱스 지정.ex) 0번 항목의 2번 하위 항목 지정

state, stateMask: 항목의 상태 설정. 상태 설정시 state와 이에 해당하는 stateMask를 bit 연상하여 사용.

pszText    : 항목의 문자열 포인터

cchTextMax    : pszText의 길이 지정. 보통 무시하며 읽기전용인 경우 사용

iImage        : 이미지 인덱스

lParam        : 통지 메시지에 따라 다른 의미로 활용됨. 정렬시 사용.

iGroupId    : 항목이 속할 그룹 ID. (Xp 이후 가능)

cColumns, puColumns : 타일 뷰일 경우 하위 컬럼 수(최대20개)와 속성 정보를 담은 UINT 배열 포인터

Ex)

    LVITEM item;

    ::ZeroMemory(&item, sizeof(item));

    item.mask    = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;    //사용할 LVITEM 멤버 변수

    item.pszText    = _T("Test Item");        //항목 문자열

    item.iItem    = 5;                //추가할 항목인덱스

    item.iImage    = 1;                //사용할 이미지 인덱스

    item.state    = LVIS_SELECTED | LVIS_FOCUSED;    //선택된 상태 및 포커스를 받도록 설정

    m_List.InsertItem(&item);

    **. 리스트 컨트롤의 Always Show Selection 속성을 True로 주면 포커스가 없어도 선택된 상태로 표시한다.

 

[Column Header 추가 : Report Style의 경우]

m_List.InsertColumn(0, _T("Name"), LVCFMT_LEFT, 200);        //첫번째 컬럼 헤더 설정

m_List.InsertColumn(1, _T("Description"), LVCFMT_LEFT, 300);        //두번째 컬럼 헤더 설정

 

m_List.SetItemText(0, 0, _T("New Name"));    //첫번째 아이템의 첫번째 컬럼 문자열 설정

m_List.SetItemText(0, 1, _T("New Desc"));    //첫번째 아이템의 두번째 컬럼 문자열 설정

 

[리스트 컨트롤 스타일 변경 : ModifyStyle()]

m_List.ModifyStyle(LVS_TYPEMASK, LVS_REPORT);    //기존스타일, 새로 적용할 스타일 지정

 

    [UI에서 직접 항목(item) 문자열 변경시 적용시키는 방법]

    실행시 문자열 편집이 되지만 저장되지 않고 이전 문자열로 돌아온다.

    이럴땐 LVN_ENDLABELEDIT 통지 메시지 함수를 등록하고 다음과 같이 코딩한다.

    CXXXDlg::OnLvnEndlabeleditList(…)

    {

        NMLVDISPINFO* pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);

        CString strText = _T("");

        CEdit* pEdit = m_List.GetEditControl();    //항목의 Edit 컨트롤을 가져옴

        pEdit->GetWindowText(strText);        //입력된 문자열 획득

 

        m_List.SetItemText(pDispInfo->item.iItem, 0, strText);    //변경된 아이템의 0번째 컬럼에 문자열 지정

        *pResult = 0;

    }

 

    [확장 스타일 사용]

    좀 더 화려한 스타일 설정 가능.

    LVS_EX_CHECKBOXES    : 체크박스를 주어 여러 항목 선택 기능 제공

    LVS_EX_BORDERSELECT: 선택된 항목에 대한 border 처리 제공

    LVS_EX_TRACKSELECT    : 마우스가 머물러 있는 항목이 자동 선택

    LVS_EX_GRIDLINES    : 테이블의 border를 그려 줌.

    LVS_EX_FULLROWSELECT : 한 행의 컬럼들이 같이 선택 됨.

 

    Ex) 체크박스 및 border 추가하기

        DWORD dwExStyle = m_List.GetExtendedStyle();    //확장 스타일을 가져옴

        m_List.SetExtendedStyle(dwExStyle | LVS_EX_CHECKBOXES | LVS_EX_BORDERSELECT);    //추가 스타일 적용

    

    [체크된 항목 삭제 예제]

    확장 스타일 LVS_EX_CHECKBOXES 적용하여 선택된 아이템 지우는 방법.

    CXXXDlg::OnBnClickedButtonDelete()    //삭제 버튼 클릿기

    {

        int nCount = m_List.GetItemCount();

        for (int i = nCount; i>=0; --i)    //i를 0부터 시작하여 지우게 되면 삭제된 항목 다음의 인덱스가 업데이트 되므로

        {                //반드시 뒤 인덱스부터 삭제하도록 한다.

            If (m_List.GetCheck(i)) m_List.DeleteItem(i);

        }

}

    

    [그룹 관리 : Xp 이상 사용 가능]

    그룹별 항목 분류 기능

        //그룹 생성 및 추가

        LVGROUP group;

        ::ZeroMemory(&group, sizeof(group));

        group.cbSize        = sizeof(group);

        group.mask        = LVFG_HEADER | LVFG_GROUPID;    //사용할 LVGROUP 멤버 지정

        group.pszHeader    = _T("First Group");            //그룹 이름

        group.iGroupId        = 10;                    //그룹 ID

        m_List.InsertGroup(-1, &group);    //First Group 추가. -1은 그룹인덱스로 추가 순서데로 인덱스 사용을 의미

 

        group.pszHeader    = _T("Second Group");

        group.iGroupId        = 20;

        m_List.InsertGroup(-1, &group);    //Second Group 추가

 

        //아이템 추가

    LVITEM item;

    ::ZeroMemory(&item, sizeof(item));

    item.mask    = LVIF_TEXT | LVIF_IMAGE | LVIF_GROUPID;    //그룹 사용 : LVIF_GROUPID

    item.pszText    = _T("Test Item");        //항목 문자열

    item.iItem    = 0;                //추가할 항목인덱스

    item.iImage    = 0;                //사용할 이미지 인덱스

    item.iGroupId    = 10;                //10 번 그룹에 등록

m_List.InsertItem(&item);

 

        //그룹 뷰 활성화

        m_List.EnableGroupView(TRUE);

 

    [컬럼 헤더 컨트롤(Column Header)의 컬럼 정렬 : CHeaderCtrl]

    Report style의 컬럼 클릭시 오름차순/내림차순 정렬 기능 구현 및 컬럼 이동 구현 방법

 

//아이템 추가

CString strItem = _T("");

DWORD dwSeed = ::GetTickCount();    //OS 부팅후 경과 시간(ms)

LVITEM item;

::ZeroMemory(&item, sizeof(item));

item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;    //LVITEM의 lParam 멤버 변수 사용

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

{

    ImgList.Add(AfxGetApp()->LoadIcon(IDI_ICON1 + i));

    ImgListSmall.Add(AfxGetApp()->LoadIcon(IDI_ICON1 + i));

    strItem.Format(_T("%dth item"), i);

    

    item.pszText = strItem.GetBuffer();

    item.iItem = I;

    item.iImage = I;

    item.lParam = dwSeed + I;    //정렬을 위한 항목의 유니크한 ID 값으로 쓰임

    m_List.InsertItem(&item);    //항목 추가

 

    strItem.Format(_T("%dth Data"), i);

    m_List.SetItemText(I, 1, strItem);    //두번째 컬럼 세팅

 

    strItem.Format(_T("%dth Desc"), i);

    m_List.SetItemText(I, 2, strItem);    //세번째 컬럼 세팅

}

    //확장 컨트롤 스타일 사용

    DWORD dwExStyle = m_List.GetExtendedStyle();

    m_List.SetExtendedStyle(dwExStyle | LVS_EX_HEADERDRAGDROP);    //헤더 컬럼의 drag&drop으로 위치 이동 기능 제공

                                        //drag&drop 되도 헤더 컬럼의 인덱스는 안바뀜

 

    m_bAscending = FALSE;    //현재 정렬 상태 : 오름차순

    m_List.SortItems(&CXXXDlg::CompareItem, (DWORD_PTR)this);    //CompareItem() 이라는 static 함수에서 정렬 수행

                //CompareItem()의 세번째 인자로 (DWORD_PTR)this)를 넘김

    UpdateArrow();

    ..

    void CXXXDlg::UpdateArrow(void)    //헤더 컬럼의 오름/내림차순 정렬에 따른 화살표 표시

    {

        CHeaderCtrl* pHeaderCtrl = m_List.GetHeaderCtrl();    //헤더 컨트롤 획득

        HDITEM hdItem;

        TCHAR szBuffer[256];

        ::ZeroMemory(&hdItem, sizeof(hdItem));

        ::ZeroMemory(szBuffer, 256);

        

        hdItem.mask    = -1;    //구조체를 0으로 초기화후 -1 설정은 모든 비트를 1로 설정한 효과 : 모든 정보를 가져옴

        hdItem.pszText = szBuffer;    //헤더 컬럼 문자열을 담을 변수

        hdItem.cchTextMax = 256;    //pszText 길이

        pHeaderCtrl->GetItem(0, &hdItem);    //0번 컬럼의 정보를 hdItem에 저장

        hdItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);    //정렬 화살표 삭제 초기화

        if (m_bAscending)     hdItem.fmt | = HDF_SORTDOWN;    //오름차순이면 아래 화살표

        else            hdItem.fmt | = HDF_SORTUP;        //내림차순이면 위 화살표

        pHeaderCtrl->SetItem(0, &hdItem);    //변경된 정보를 첫번째 헤더 컬럼에 반영

    }

    

    void CXXXDlg::OnHdnItemclickList1(…)    //리스트 컨트롤의 헤더 클릭시 발생하는 HDN_ITEMCLICK 통지 메시지 함수

    {

        LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);

        if (phdr->iItem == 0)    //사용자가 누른 헤더 컬럼의 인덱스가 0이라면..

        {

            m_bAsending = !m_bAsending;    //정렬방식 변환

            UpdateArrow();            //헤더 컬럼 화살표 반전

            m_List.SortItems(&CXXXDlg::CompareItem, (DWORD_PTR)this);    // static CompareItem() 함수로 정렬 수행

                        //CompareItem()의 세번째 인자로 (DWORD_PTR)this)를 넘김

        }

        *pResult = 0;

    }

 

    //SortItems()에서 호출하는 CompareItem()의 원형

    //int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

    //리턴 값이 0이상이면 항목은 위치변경 안함. 리턴 값이 음수이면 항목 위치 변경

    //lParam1, lParam2는 항목의 lParame 값 (GetTickCount()로 생성한 유니크한 값이 들어옴)

    //lParamSort 는 SortItems()의 두번째 인자로 준 값 (CXXXDlg 클래스 포인터)이 들어옴.

    int CALLBACK CXXXDlg::CompareItem(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)

{

    CXXXDlg* pDlg = (CXXXDlg*)lParamSort;

 

    LVFINDINFO lvFind1, lvFind2;        //FindItem()시 사용될 구조체

    lvFind1.flags    = LVFI_PARAM;    //항목 검색시 사용할 구조체 멤버 변수 지정

    lvFind1.lParam    = lParam1;        //항목의 lParam값 지정(GetTickCount()로 생성한 유니크한 값)

    lvFind2.flags    = LVFI_PARAM;

    lvFind2.lParam    = lParam2;

 

    int nIndex1 = pDlg->m_List.FindItem(&lvFind1);    //항목의 인덱스 찾기(목찾으면 -1)

    int nIndex2 = pDlg->m_List.FindItem(&lvFind2);

    

    CString strText1 = pDlg->m_List.GetItemText(nIndex1, 0);    //항목의 첫번째 컬럼 문자열 획득

    CString strText2 = pDlg->m_List.GetItemText(nIndex2, 0);

    

    int nResult = 0;

    if (pDlg->m_bAscending)    nResult = strText2.Compare(strText1);    //비교하야 정렬 여부 결정

    else                nResult = strText1.Compare(strText2);

    return nResult;

}

 

    [시스템 이미지 목록 사용]

    ::SHGetFileInfo()    : 시스템 이미지 목록 획득

    SHFILEINFO 구조체    : 파일 정보를 담을 구조체

    **.CListCtrl의 CImageList가 소멸시 이미지 목록도 사라지는데 시스템 이미지 사용시엔

"Share Image Lists" 속성을 True로 두어 시스템 이미지를 소멸시키지 않도록 한다. (NT 이상은 OS에서 방지해줌)

 

    SHFILEINFO ShellInfo;

    //시스템 큰 아이콘

    ::ZeroMemory(&ShellInfo, sizeof(ShellInfo));

    HIMAGELIST hSysImage = reinterpret_cast<HIMAGELIST>(

::SHGetFileInfo(_T("C:\\"), 0, &ShellInfo, sizeof(ShellInfo),

        SHGFI_LARGEICON | SHGFI_SYSICONINDEX));        //큰 아이콘

 

    //시스템 작은 아이콘

    ::ZeroMemory(&ShellInfo, sizeof(ShellInfo));

    HIMAGELIST hSysImageSmall = reinterpret_cast<HIMAGELIST>(

::SHGetFileInfo(_T("C:\\"), 0, &ShellInfo, sizeof(ShellInfo),

        SHGFI_SMALLICON | SHGFI_SYSICONINDEX));        //작은 아이콘

 

//리스트 컨트롤에 시스템 이미지 목록 핸들 등록

/*

ListView_SetImageList() 매크로는 SendMessage()를 이용해 리스트 컨트롤에 LVM_SETIMAGELIST를 직접 전송.(코드 단축효과)

ListView_SetImageList() 매크로를 안쓴다면 CImageList의 FromHandle()에 HIMAGELIST 핸들을 넘겨주어

CImageList 클래스 객체를 구하여 CListCtrl의 SetImageList()를 호출해야 함.

*/

    ListView_SetImageList(m_List.m_hWnd, hSysImage, LVSIL_NORMAL);

    ListView_SetImageList(m_List.m_hWnd, hSysImageSmall, LVSIL_SMALL);

 

    //아이템 추가

    CString strItem = _T("");

strItem = _T("c:\\");

    m_List.InsertItem(0, strItem, GetIconIndexFromFile(strItem);    //항목 등록. GetIconIndexFromFile()는 사용자 정의 함수

strItem = _T("c:\\Windows");

    m_List.InsertItem(1, strItem, GetIconIndexFromFile(strItem);

strItem = _T("c:\\Windows\\notepad.exe");

    m_List.InsertItem(2, strItem, GetIconIndexFromFile(strItem);

    ..

    //주어진 경로에 해당하는 시스템 이미지 리스트의 인덱스 반환

    int CXXXDlg::GetIconIndexFromFile(CString strFilePath)

    {

        SHFILEINFO ShellInfo;

        ::ZeroMemory(&ShellInfo, sizeof(ShellInfo));

        //인덱스는 똑같으니 SHGFI_LARGEICON이나 SHGFI_SMALLICON이나 동일.

        ::SHGetFileInfo(strFilePath.GetBuffer(), 0, &ShellInfo, sizeof(ShellInfo), SHGFI_LARGEICON | SHGFI_SYSICONINDEX);

        return ShellInfo.iIcon;

}

 

Tree Control (트리 컨트롤) : CTreeCtrl

    탐색기의 왼쪽 폴더 트리 생성시 사용되는 컨트롤

 

    [기본 세팅 속성]

    Has Buttons 속성 True, Has Lines 속성 True

 

    [ICON]

    보통때와 선택시 아이콘을 사용. 사이즈는 16*16

 

    [변수 생성]

    CTreeCtrl m_Tree; 로 연결.

 

    [생성 방법]

    CBitmap Bmp;

    Bmp.LoadBitmap(IDB_TreeImageList);

    

    static CImageList ImgList;

    ImgList.Create(16, 16, ILC_COLOR24, 6, 0);

    ImgList.Add(&Bmp, RGB(255, 0, 0));

    m_Tree.SetImageList(&ImgList, TVSIL_NORMAL);    //이미지 리스트 설정

 

    HTREEITEM hItem = NULL;

    hItem = m_Tree.InsertItem(_T("바탕화면"), 0, 0, TVI_ROOT);    //보통땐 0번, 선택시 0번 이미지 사용. TVI_ROOT : 루트 아이템

    hItem = m_Tree.InsertItem(_T("내 문서"), 1, 5, hItem); //보통땐 1번, 선택시 5번 이미지 사용. 마지막 인자 : 부모 아이템을 지정

    m_Tree.InsertItem(_T("내 그림), 2, 5, hItem);

    m_Tree.InsertItem(_T("내 비디오), 3, 5, hItem);

    hItem = m_Tree.InsertItem(_T("Sample folder), 4, 5, hItem);

    hItem = m_Tree.InsertItem(_T("Sub folder), 4, 5, hItem);

    m_Tree.EnsureVisible(hItem);        //마지막 hItem이 화면에 보이도록 expand 하도록 함.

 

    [CMFCShellTreeCtrl : Visual c++ 2008 Feature Pack]

    윈도우 탐색기의 폴더 트리를 생성해주는 클래스. 직접 구현시 복잡함.

 

    [TVN_SELCHANGED 통지 메시지]

    아이템 선택시 발생하는 메시지

    void CXXXDlg::OnTvnSelchangedTree(…)

    {

        //pNMTreeView는 이전 선택항목, 새로운 선택항목(itemNew)에 대한 정보를 담고 있음

        LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);

        CString strItem = m_Tree.GetItemText(pNMTreeView->itemNew.hItem);    //새로 선택한 항목의 문자열 획득

        GetDlgItem(IDC_Static_Selected)->SetWindowText(strItem);            //static 에 문자 세팅

        *pResult= 0;

}

 

    [Check Boxes 속성]

    트리 컨트롤에서 Check Boxes 속성을 True로 할경우 트리의 각 아이템 앞에 체크 박스가 생성된다.

 

    [자식 항목 처리 샘플]    

    void CXXXDlg::OnBnClickedButtonCheckupchild()

    {

        HTREEITEM hItem = m_Tree.GetRootItem();    //ROOT 아이템 획득

        if(m_Tree.GetCheck(hItem))    //ROOT 아이템이 체크 되어 있다면 출력

            AfxMessageBox(m_Tree.GetItemText(hItem));

        CheckupChild(m_Tree.GetRootItem());    //자식 아이템에 대한 검사 수행

    }

    

    void CXXXDlg::CheckupChild(HTREEITEM hItem)

    {

        HTREEITEM hChildItem = m_Tree.GetChildItem(hItem);    

        while(hChildItem != NULL)

        {

            if(m_Tree.GetCheck(hChildItem))

                AfxMessageBox(m_Tree.GetItemText(hChildItem));

            if(m_Tree.ItemHasChildren(hChildItem))    //차일드 아이템이 있으면 재귀호출.

                CheckupChild(hChildItem);

            hChildItem = m_Tree.GetNextItem(hChildItem, TVGN_NEXT);    //다음 자식 아이템 지정

        }

    }

 

리스트 컨트롤에서의 Drag and drop (드래그 앤 드롭) 효과 실습

    [목표]

    왼쪽 리스트 컨트롤의 아이템을 DragNDrop으로 오른쪽 리스트 컨트롤로 복사하는 UI 처리

 

    [필요한 기술]

    이미지 드래그 시 반투명 이미지 표현. - CListCtrl의 CreateDragImage() 사용

    이미지 선택시 좌표 보정 필요.

    

    [변수 정의 및 초기화]

    CListCtrl m_List_Left;        //왼쪽리스트컨트롤

    CListCtrl m_List_Right;        //오른쪽리스트컨트롤

 

    CImageList*    m_pImgListDrag;    //Drag시투명이미지:NULL 초기화

    int        m_nIndexLeftSel;    //: -1 초기화

 

    //생성자 함수에서 초기화

    m_pImgListDrag    = NULL;

    m_nIndexLeftSel    = -1;

 

    [OnInitDialog() 에서 리스트 컨트롤들 초기화]

    // TODO: 여기에추가초기화작업을추가합니다.

    //아이콘이미지로딩

    CBitmap Bitmap;

    Bitmap.LoadBitmap(IDB_ImageList);

 

    //이미지리스트생성

    static CImageList ImgList;

    ImgList.Create(32, 32, ILC_COLOR32 | ILC_MASK, 5, 0);

    ImgList.Add(&Bitmap, RGB(0, 0, 0));

 

    m_List_Left.SetImageList(&ImgList, LVSIL_NORMAL);    //왼쪽리스트컨트롤이미지리스트등록

    m_List_Right.SetImageList(&ImgList, LVSIL_NORMAL);    //오른쪽리스트컨트롤이미지리스트등록

 

    //왼쪽리스트컨트롤에항목추가

    CString strItem = _T("");

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

    {

        strItem.Format(_T("%dth item"), i);

        m_List_Left.InsertItem(i, strItem, i);

    }

    

    //왼쪽리스트컨트롤확장스타일적용

    DWORD dwExStyleLeft = m_List_Left.GetExtendedStyle();

    m_List_Left.SetExtendedStyle(dwExStyleLeft | LVS_EX_BORDERSELECT);    //아이템선택지테두리효과

    

    //오른쪽리스트컨트롤확장스타일적용

    DWORD dwExStyleRight = m_List_Right.GetExtendedStyle();

    m_List_Right.SetExtendedStyle(dwExStyleRight | LVS_EX_BORDERSELECT);//아이템선택지테두리효과

 

    [Drag 시작 : 왼쪽 리스트 컨트롤의 LVN_BEGINDRAG 메시지 핸들러 함수 구현]

    LVN_BEGINDRAG는 사용자가 아이템에 대한 Drag를 시작했음을 알려주기 때문에

    WM_LBUTTONDOWN을 사용하지 않고 LVN_BEGINDRAG를 사용합니다.

 

void CListCtrlDragDropDlg::OnLvnBegindragList1(NMHDR *pNMHDR, LRESULT *pResult)

{

    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

 

    // TODO: Add your control notification handler code here

    CPoint ptDrag;    //Drag시항목의좌표(리스트컨트롤기준좌표)

    CPoint ptAction;//Drag시마우스클릭좌표(리스트컨트롤기준좌표)

 

    m_nIndexLeftSel = pNMLV->iItem;    //드레그가시작된항목의인덱스

    //pNMLV->item항목의Drag이미지생성및항목의좌표를ptDrag에저장해줌(ptDrag엔리스트컨트롤기준좌표)

    //리턴되는m_pImgListDrag는사용이끝나면delete로메모리해제필수

    m_pImgListDrag = m_List_Left.CreateDragImage(pNMLV->iItem, &ptDrag);

    m_pImgListDrag->SetBkColor(RGB(0,0,0));    //아이콘배경투명하게변경

    ptAction = pNMLV->ptAction;    //리스트컨트롤에서드래그를시작한좌표획득(리스트컨트롤기준좌표)

    

    SetCapture();    //윈도우영역을벗어나도마우스메세지수신

    //항목의시작좌표와클릭좌표의차이만큼Drag이미지가보이도록한다.

    //첫번째인자0은0번째이미지를의미

    m_pImgListDrag->BeginDrag(0, ptAction-ptDrag);

    m_List_Left.ClientToScreen(&ptAction);//스크린좌표로변환

    //첫번째인자를NULL은바탕화면을의미하므로

    //두번째인자는스크린기준의좌표를주어반투명Drag이미지를출력을수행

    m_pImgListDrag->DragEnter(NULL, ptAction);

 

    *pResult = 0;

}

 

    [Drag 중인경우 처리 : WM_MOUSEMOVE]

    Drag 이미지에 대한 처리

void CListCtrlDragDropDlg::OnMouseMove(UINT nFlags, CPoint point)

{

    // TODO: Add your message handler code here and/or call default

    if (m_pImgListDrag != NULL)

    {

        ClientToScreen(&point);    //스크린기준좌표로변환

        //point가위치한곳의윈도우찾기(현재대화상자나자식윈도우인경우만NULL아닌값리턴)

        CWnd* pWnd = CWnd::WindowFromPoint(point);

        if (pWnd != NULL)    //

        {

            if (this==pWnd || IsChild(pWnd))

            {

                //드래그유지

                m_pImgListDrag->DragEnter(NULL, point);//지워진이미지를다기나오게하기위함

                m_pImgListDrag->DragMove(point);    //point좌표에Drag이미지출력

            }

            else

            {

                m_pImgListDrag->DragLeave(NULL);    //Drag이미지삭제

            }

        }

    }

    CDialog::OnMouseMove(nFlags, point);

}

 

    [Drag 종료 처리 : WM_LBUTTONUP]

 

void CListCtrlDragDropDlg::OnLButtonUp(UINT nFlags, CPoint point)

{

    // TODO: Add your message handler code here and/or call default

    CString strTmp = _T("");

    if (m_pImgListDrag != NULL)

    {

        ClientToScreen(&point);

        m_pImgListDrag->DragLeave(NULL);    //Drag이미지삭제

        m_pImgListDrag->EndDrag();

        ReleaseCapture();    //마우스메세지수신종료

 

        //오른쪽리스트컨트롤에항목추가

        CWnd* pWnd = CWnd::WindowFromPoint(point);

        if (pWnd == &m_List_Right && m_nIndexLeftSel >= 0)    //Drop이오른쪽리스트컨트롤이라면

        {

            LVITEM lvItem;

            TCHAR szBuffer[256];

            ::ZeroMemory(&lvItem, sizeof(lvItem));

            ::ZeroMemory(szBuffer, sizeof(szBuffer));

 

            lvItem.mask        = LVIF_TEXT | LVIF_IMAGE;

            lvItem.iItem    = m_nIndexLeftSel;

            lvItem.pszText    = szBuffer;

            lvItem.cchTextMax = 256;

            m_List_Left.GetItem(&lvItem);    //왼쪽리스트컨트롤에서아이템정보획득

 

            m_List_Right.InsertItem(0, lvItem.pszText, lvItem.iImage);

        }

        else    //Drop이왼쪽리스트컨트롤이라면

        {

            m_List_Left.ScreenToClient(&point);    //왼쪽리스트컨트롤기준좌표로변환

            int nIndex = m_List_Left.HitTest(point);//point좌표가가리키는항목인덱스획득

            if (nIndex >= 0)

            {

                strTmp.Format(_T("Drop on %dth item"), nIndex);

                AfxMessageBox(strTmp);

            }

        }

        //Drag 이미지자원해제및쵝화

        delete m_pImgListDrag;

        m_pImgListDrag = NULL;

        m_nIndexLeftSel = -1;

    }

 

    CDialog::OnLButtonUp(nFlags, point);

}

 

    [샘플 전체 project]

    ListCtrlDragDrop.zip

 

Pager Control (페이저 컨트롤) : CpagerCtrl

    툴바 같은 곳에서 아이콘을 일부가리고 넘기면서 다른 아이콘을 볼 수 있는 컨트롤

    아래 예는 SDI project에서 툴바 컨트롤 클래스에 페이저 컨트롤을 사용하는 방법을 설명합니다.

    아래 예는 Client 화면에 출력하므로 View 클래스에서 작업합니다.

    

    [변수 정의]

    CPagerCtrl    m_wndPager;        //페이저 컨트롤

    CToolBar    m_wndToolBar;    //툴바 컨트롤

 

    [View::OnCreate() 에서 페이저 컨트롤 생성 및 툴바 연결]

    //페이저 컨트롤 생성 및 스타일 지정

m_wndPager.Create(WS_VISIBLE | WS_CHILD | PGS_HORZ, CRect(0, 0, 100, 32), this, 1234);

    //툴바 생성

    m_wndToolBar.CreateEx(&m_wndPager);    // 페이저 컨트롤을 부모로 지정

    m_wndToolBar.LoadToolBar(IDR_MAINFRAME);

 

    m_wndPager.SetChild(m_wndToolBar.m_hWnd);    //자식으로 툴바 핸들 지정

    m_wndPager.SetButtonSize(10);    //스크롤 버튼(화살표) 크기 지정

    m_wndPager.SetBorder(1);        //테두리 굵기 설정

 

    [화면에 표시할 수 있는 최대 크기 계산 : PGN_CALCSIZE 통지 메시지 처리]

    통지 메시지는 코딩으로 직접 등록해야 합니다.

    1. View 클래스 헤더 정의

        afx_msg void OnCalcSize(NMHDR* pNotifyStruct, LRESULT* result);

    2. BEGIN_MESSAGE_MAP에 ON_NOTIFY 추가

        ON_NOTIFY(PGN_CALCSIZE, 1234, &CXXXView::OnCalcSize)

    3. OnCalcSize() 구현

        void CXXXView::OnCalcSize(NMHDR* pNotifyStruct, LRESULT* result)

        {    //자식 윈도우의 폭을 계산하는 함수

            LPNMPGCALCSIZE pNMPGCALCSIZE = (LPNMPGCALCSIZE)pNotifyStruct;

            if (pNMPGCALCSIZE->dwFlag == PGF_CALCWIDTH)    //폭 계산을 위해 호출된 경우라면..

            {

                //자식 윈도우(툴바)의 폭 획득하여

                SIZE size;

                m_wndToolBar.SendMessage(TB_GETMAXSIZE, 0, (LPARAM)&size);

                pNMPGCALCSIZE->iWidth = size.cx;    //폭을 최대 스크롤 사이즈로 정의

            }

        }

 

Animation Control (애니메이션 컨트롤) : CAnimateCtrl

    반복되는 애니메이션 출력을 위한 컨트롤

    

    [변수 정의]

    CAnimateCtrl m_Ani;

 

    [초기화 : OnInitDialog()]

    m_Ani.Open(IDR_AVI1);    //리소스에 등록된 .avi 파일

 

    [재생 및 정지]

    void CXXXDlg::Start()

    {

        m_Ani.Play(0, -1, -1);    //0 : 처음부터 재생, -1 : 끝 프레임까지 재생, -1 : 반복 횟수 무한

    }

    void CXXXDlg::Stop()

    {

        m_Ani.Stop();    //재생 정지

    }

 

Calendar (달력)형식의 컨트롤 : Month Calendar 컨트롤, Date Time Picker 컨트롤 : COleDateTime, CTime

Month Calendar 컨트롤 : 달력 형식의 컨트롤. CTime 또는 COleDateTime 과 연결 됨.

    Date Time Picker 컨트롤 : 날짜 형식의 컨트롤로 Month Calendar 컨트롤 내장. CTime 또는 COleDateTime 과 연결 됨.

 

    [사용방법에 대한 pseudo code]

    COleDateTime m_timeLeft;    //Month Calerdar 컨트롤의 연결 변수

    COleDateTime m_timeRight;    //Date Time Picker 컨트롤의 연결 변수

 

    m_timeLeft(COleDateTime::GetCurrentTime());    //현재 시간으로 설정

    m_timeRight(COleDateTime::GetCurrentTime());    //현재 시간으로 설정

 

    UpdateData();    //컨트롤의 값을 각 변수에 반영

    m_timeRight = (m_timeLeft + COleDateTimeSpan(100, 0, 0, 0));    //100일 후의 날짜로 설정

    UpdateData(FALSE);

 

    [COleDateTimeSpan 클래스]

    COleDateTime 클래스와 조합되어 날짜 연산시 사용되는 클래스로 일(day) 단위 이하를 다룸.

 

IP Address 컨트롤 (IP 주소 컨트롤)

    IPv4 주소 형식의 컨트롤로 32bit 값으로 정의됨.

 

    [변수 정의]

    DWORD m_dwAddress; 로 연결

 

    [사용 방법]

    //IP 설정

    m_dwAddress = inet_addr("10.1.1.100");

    UpdateData(FALSE);

 

    //설정된 IP 출력

    UpdateData();

    CString strTmp = _T("");

    DWORD dwAddress = ntohl(m_dwAddress);    //Network order를 host order로 변경

    strTmp = inet_ntoa(*(IN_ADDR*)&dwAddress);//32bit IP주소를 문자열로 변경

    AfxMessageBox(strTmp);

 

Network Address Control (네트워크 주소 컨트롤) : CNetAddressCtrl

    IPv4, IPv6, URL의 형식 검사를 지원해주는 컨트롤로 Vista 이상에서 사용 가능.

 

Tab Control (탭 컨트롤) : CTabCtrl

    CListCtrl 처럼 항목 추가/삭제, HitTest() 제공 등 사용상 유사함.

 

    [변수 정의]

    CTabCtrl m_Tab;    으로 연결

 

    [초기화 : OnInitDialog()]

    CBitmap Bmp;

    Bmp.LoadBitmap(IDB_TabImageList);    //탭에 사용할 이미지 로딩

 

    static CImageList ImgList;

    ImgList.Create(16, 16, ILC_COLOR24 | ILC_MASK, 7, 0);

    ImgList.Add(&Bmp, RGB(192, 192, 192));    //이미지 리스트에 Bmp 등록

    m_Tab.SetImageList(&ImgList);    //탭 컨트롤에 이미지 리스트 등록

 

    //탭 추가

    CString strTmp = _T("");

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

    {

        strTmp.Format(_T("%dth Tab"), i);

        m_Tab.InsertItem(I, strTmp, i);    //탭 추가

    }

 

    [탭마다 사용할 Dialog생성]

    탭마다 사용할 Dialog를 만든 후 사용자가 탭 변경시 해당 Dialog를 보여주는 식으로 동작함.

 

    1.리소스 탭에서 Dialog 추가 후 속성 변경 : Border 속성 : None, Style 속성 : Child

    2.Add Class로 Dialog 클래스 생성 : Base class : CDialog 사용

    3.각 Dialog마다 사용할 컨트롤 등록

 

    [탭마다 사용할 Dialog 사용]

    사용할 Dialog에 대한 Header include 및 멤버 변수 정의하여 사용.

    

    [Dialog 사용을 위한 정의]

    #include "FormOne.h"

#include "FormTwo.h"

 

    CFormOne    m_formOne;    //예로 Dialog 한 개 사용

    CFormTwo    m_formTwo;    //예로 Dialog 한 개 사용

    CWnd*        m_pwndShow;//현재 사용자가 보고 있는 탭의 Dialog

    

    m_pwndShow = NULL;    //생성자에서 초기화

 

    [초기화 : OnInitDialog()]

    CRect Rect;

    m_Tab.GetClientRect(&Rect);    //탭 컨트롤의 크기 획득

 

    //첫번째 탭 Dialog 생성 : SWP_SHOWWINDOW 지정

    m_formOne.Create(IDD_Form_One, &m_Tab);

    m_formOne.SetWindowPos(NULL, 5, 25, Rect.Width()-10, Rect.Height()-30, SWP_SHOWWINDOW | SWP_NOZORDER);

    m_pwndShow = &m_formOne;    //첫번째 Dialog를 시작으로 지정

 

    //두번째 탭 Dialog 생성

    m_formTwo.Create(IDD_Form_Two, &m_Tab);

    m_formTwo.SetWindowPos(NULL, 5, 25, Rect.Width()-10, Rect.Height()-30, SWP_NOZORDER);

 

    [탭 변경 메세지 처리 : TCN_SELCHANGE 통지 메시지]

    void CXXXDlg::OnTcnSelchangeTab(NMHDR* pNMHDR, LRESULT* pResult)

    {

        if (m_pwndShow != NULL)    //현재 Dialog 숨김

        {

            m_pwndShow->ShowWindow(SW_HIDE);

            m_pwndShow = NULL;

        }

 

        int nIndex = m_Tab.GetCurSel();    //현재 선택된 Tab 인덱스

        switch (nIndex)

        {

        case 0:

            m_formOne.ShowWindow(SW_SHOW);

            m_pwndShow = &m_formOne;

            break;

        case 1:

            m_formTwo.ShowWindow(SW_SHOW);

            m_pwndShow = &m_formTwo;

            break;

        }

        *pResult = 0;

    }

 

Modal Dialog (모달 대화 상자)

    Modal Dialog가 종료되기전까지 부모 윈도우를 사용 못하게 하는 Dialog.

    DoModal() 메소드를 통해 사용.

 

    [생성 방법]

    CDialog 를 상속받는 Dialog 클래스 생성

 

    [사용 예제]

    CModalDlg dlg;

    INT_PTR nResponse = dlg.DoModal();    //Dialog가 종료될때까지 block되며 종료시 발생한 메시지 리턴

    if (nResponse == IDOK)            //IDOK 버튼으로 종료된 경우

    {

    }

    else if (nResponse == IDCANCEL)    //IDCANCEL 버튼으로 종료된 경우

    {

    }

 

Modeless Dialog (모달리스 대화 상자)

    다른 윈도우에 영향을 끼치지 않으며 독자적으로 동작하는 Dialog

    Create() 메소드를 통해 사용

 

    [생성 방법]

    CDialog를 상속받는 Dialog 클래스 생성

 

    [사용 예제]

    CModelessDlg dlg;

    if (dlg.GetSafeHwnd() == NULL)    //modeless dialog가 생성되어있는지 확인

    {

        dlg.Create(IDD_Dialog_Modeless);

    }

    dlg.ShowWindow(SH_SHOW);

 

    [PostNcDestroy()]

    new로 생성한 Modeless dialog를 자동으로 delete 하고 싶다면

    PostNcDestroy()를 재정의 하여 delete this; 할 수 있다.

 

Common Dialog Box (공용 대화 상자)

    OS에서 제공하는 dialog로 CDialog를 상속한 CCommonDialog를 부모 클래스로 갖음.

 

    [공용 대화 상자 종류]

    CFileDialog        : 파일 대화 상자

    CFontDialog        : 폰트 대화 상자

    CColorDialog        : 색 대화 상자

    CPageSetupDialog    : 페이지 설정 대화 상자

    CPrintDialog        : 프린트 대화 상자

    CFindReplaceDialog    : 찾기/바꾸기 대화 상자

    COleDialog        : OLE 관련 대화 상자의 부모 클래스

    ::SHBrowseForFolder() : 폴더 찾아보기 대화 상자

 

    [CFileDialog : 파일 대화 상자]

    CFileDialog dlg(TRUE,        //TRUE : 열기 모드, FALSE : 저장 모드

        _T("EXE"),        //저장모드시 파일 확장자 지정. 열기모드시엔 무의미

        NULL,            //경로 입력 필드의 기본 값

        OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,    //사용자가 선택한 파일이 존재하지 않으면 dialog가 종료하지 않도록 함

        //OFN_ALLOWMULTISELECT : 여러 파일 선택 가능 하도록 지정

        //OFN_OVERWRITEPROMPT : 저장모드시 기존 파일에 저장할 경우 경고 메세지 출력

        _T("EXE Files(*.exe)|*.exe|All Files(*.*)|*.*||"),    //파일 목록에 출력에 대한 필터링 지정

        this);    //부모 윈도우 주소

    if (dlg.DoModal() == IDOK)

    {

        dlg.GetPathName();    //선택한 파일 경로

        dlg.GetFileName();    //선택한 파일 이름

        dlg.GetFileExt();    //선택한 파일 확장자

    }

 

    [CFontDialog : 폰트 대화 상자]

    CClientDC dc(this);

    CString strTmp = _T("");

    LOGFONT lfont;

    ::ZeroMemory(&lfont, sizeof(LOGFONT));

    //전체 해상도에서 높이가 9인치인 픽셀수 계산

    //72는 MM_TEXT 매핑 모드에서 1인치당 표시 가능한 픽셀 수

    lfont.lfHeight = -MulDiv(9, dc.GetDeviceCaps(LOGPIXELSY), 72);

    wsprintf(lfont.lfFaceName, _T("%s"), _T("굴림"));

 

    CFontDialog Dlg(&lfont);

    if (Dlg.DoModal() == IDOK)

    {

        Dlg.GetFaceName();    //선택한 글꼴 이름

        Dlg.GetSize();        //선택한 글꼴 크기

    }

 

    [CColorDialog : 색 대화 상자]

    CStrinig strTmp = _T("");

    //RGB(0,0,0)으로 기본 색상 설정.

    //CC_FUULOPEN : 사용자 정의 색 만들기 버튼 제공

    //CC_SOLIDCOLOR : 시스템 기본 색만 제공

    CColorDialog Dlg(RGB(0,0,0), CC_FULLOPEN);

    if (Dlg.DoModal() == IDOK)

    {

        COLORREF color = Dlg.GetColor();    //선택한 색상 획득

        strTmp.Format(_T("RGB(%u, %u, %u)"), GetRValue(color), GetGValue(color), GetBValue(color));

        AfxMessageBox(strTmp);

    }

 

    [::SHBrowseForFolder() : 폴더 찾아보기 대화 상자]

    // 폴더 경로 선택할 때 사용하며 Shell API 사용

    //Feature Pack에선 향상된 dialog가 많음

    BROWSEINFO bi;    ::ZeroMemory(&bi, sizeof(BROWSEINFO));

 

    bi.hwndOwner    = m_hWnd;    //부모 윈도우 지정

    bi.lpszTitle    = _T("파일이 저장될 폴더를 선택하세요");    //설명 등록

    //BIF_NEWDIALOGSTYLE : 새로운 공용 컨트롤 버전 5.0이 제공하는 새로운 스타일 사용

//BIF_EDITBOX : 폴더 이름 편집 가능. 별도의 에디트 컨트롤 제공

//BIF_RETURNONLYFSDIRS : 실제 폴더만 출력(제어판 등은 출력하지 않음)

    bi.ulFlags    = BIF_NEWDIALOGSTYLE | BIF_EDITBOX | BIF_RETURNONLYFSDIRS;

 

 

 

    LPITEMIDLIST pItemIdList = ::SHBrowseForFolder(&bi);    //선택한 폴더의 PIDL 반환

    TCHAR szBuffer[MAX_PATH];    ::ZeroMemory(szBuffer, MAX_PATH);

    if (::SHGetPathFromIDList(pItemIdList, szBuffer)    //PIDL의 상세 경로 해석

        AfxMessageBox(szBuffer);

 

    /* BROWSEINFO 구조체

    hwndOwner    : 부모 윈도우 핸들 지정

    pidRoot    : 출력할 root 폴더의 PIDL(Pointer Item Identifier List). NULL이면 바탕화면 기준

    pszDisplayName : 사용자가 선택한 폴더 이름을 저장할 버퍼 주소. NULL이면 사용 안함

    lpszTitle    : 폴더 트리 위에 출력할 문자열

    ulFlags        : 스타일 지정

    lpfn        : dialog의 통지 메시지를 처리하는 콜백 함수 주소 지정

    lParam        : 콜백 함수에 인자로 전달할 파라미터 값

    iImage        : 선택한 폴더의 시스템 이미지 목록 인덱스

    */

 

HTML dialog (HTML 대화 상자)

    사용1. Dialog project 생성시 HTML 대화상자 사용을 체크하여 생성

        CDialog와 CDHtmlEventSink를 상속한 CDHtmlDialog를 상속하여 생성된다.

        리소스에서 직접 HTML 페이지를 수정하여 작성하며 일반 컨트롤도 추가할 수 있다. (HTML이 기본 컨트롤 아래 그려짐)

        BEGIN_DHTML_EVENT_MAP()에서 HTML의 ID값과 클래스의 멤버 함수를 연결시킬 수 있다.

 

    [사용 예 : Navigate() 함수]

    Navigate(_T("www.google.com"));    //웹페이지 출력

 

    [사용2. HTML dialog 생성하여 삽입]

    삽입할 HTML dialog 생성 :

Border 속성 : None, Style 속성 : Child

        CDHtmlDialog 상속받는 dialog 클래스 생성. Ex) CADwareDlg

        OnInitDialog()에 Navigate(_T("www.google.com")); 추가

    HTML dialog 사용

        CAdwareDlg    m_wndAD;    //멤버 변수 등록

        OnInitDialog()에서 HTML dialog 추가

            m_wndAD.Create(IID_Form_Adware, this);

            m_wndAD.SetWindowPos(NULL, 10, 10, 300, 300, SWP_SHOWWINDOW | SWP_NOZORDER)

 

Message Box (메시지 상자) : AfxMessageBox()

 

Property Sheet dialog (프로퍼티 시트 대화 상자)

    CPropertySheet

    예전에 자주 사용되던 방식으로 생성은 쉬우나 조작이나 UI 꾸미기가 불편함

 

깜빡임 방지

[RedrawWindow() 함수]

    WM_PAINT 메시지를 강제로 발생시키며 어느정도 깜빡이 방지에 도움되나 더블 버퍼링을 사용해야 함.

    인자에 따라 다시 그릴 영역, 화면을 하얗게 지운후 다시 그릴지 여부, 단지 무효화 시킬지 여부 등을 지정

    BOOL RedrawWindow(

        LPCRECT lpRectUpdate = NULL,

        CRgb* prgnUpdate = NULL,

        UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE

    );

    RDW_INVALIDATE    : 주어진 영역 무효화

    RDW_UPDATENOW    : client와 non-client(frame) 영역을 다시 그림

    RDW_ERASE        : RDW_INVALIDATE와 함께 사용하며 WM_ERASEBKGND 메시지를 방생시켜 윈도우 배경을 다시 그림

 

    [화면 그리기 관련 메시지]

    WM_ERASEBKGND

: 화면을 하얗게 지운다. 이후에 WM_PAINT(client영역그리기)나 WM_NCPAINT(non-client영역그리기)가 수행 됨.

OnEraseBkgnd()에 return TRUE;만 한다면 하얗게 지우는 과정이 생략되어 깜빡임이 줄어들지만 처음 실행시

뒷 화면이 창에 그려진다.

    WM_NCPAINT

        : non-client(frame) 영역의 그리는 메시지

 

Double Buffering (더블 버퍼링)

    별도 메모리에 그리기 작업을 수행하여 깜빡임을 없애주는 방법

    아래의 더블 버터링 예는 CDC를 상속한 CBufferDC를 만들고

    OnPaint() 에서 CBufferDC를 통해 그리기를 수행하며

    OnEraseBkgnd()에선 return TRUE; 만 두어 지우기 과정을 하지 않도록 한다.

 

    [BufferDC.h]

 

#if !defined(AFX_BUFFERDC_H__F631A3F3_9053_406F_A147_63DB4CFDA08B__INCLUDED_)

#define AFX_BUFFERDC_H__F631A3F3_9053_406F_A147_63DB4CFDA08B__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

class CBufferDC : public CDC

{

 

private:

    CBufferDC() { }

    CBufferDC(const CBufferDC &src) { }

    CBufferDC& operator=(const CBufferDC &src) { }

 

protected:

    BOOL Attach(HDC hDC);

    HDC Detach();

 

private:

    CWnd*            m_pParent;                            //대상윈도우에대한포인터

    CDC*            m_pTarget;                            //대상윈도우DC에대한포인터

    PAINTSTRUCT        m_PaintStruct;

    CRect            m_RcClient, m_RcWindow;                //대상윈도우의크기정보

 

    CDC                m_MemoryDC;                            //버퍼DC

    CBitmap            m_MemoryBmp, *m_pOldMemoryBmp;        //버퍼링을위한비트맵

 

public:

    CBufferDC(CWnd *pParent);

    ~CBufferDC();

 

public:

    inline CRect ClientRect() const { return m_RcClient; }

    inline CRect WindowRect() const { return m_RcWindow; }

    inline CRect UpdateRect() const { return m_PaintStruct.rcPaint; }

 

    operator HDC() const { return m_MemoryDC.m_hDC; } // DC handle for API functions

};

 

#endif // !defined(AFX_BUFFERDC_H__F631A3F3_9053_406F_A147_63DB4CFDA08B__INCLUDED_)

 

    [BufferDC.cpp]

// BufferDC.cpp: implementation of the CBufferDC class.

//

//////////////////////////////////////////////////////////////////////

 

#include "stdafx.h"

#include "BufferDC.h"

 

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

 

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

CBufferDC::CBufferDC(CWnd *pParent)

: m_pParent(pParent)

{

    ASSERT(pParent);

 

    //대상윈도우에대한정보를수집한다.

    m_pTarget = m_pParent->BeginPaint(&m_PaintStruct);

    m_pParent->GetClientRect(&m_RcClient);

    m_pParent->GetWindowRect(&m_RcWindow);

 

    //대상윈도우에대한DC를생성한다.

    m_MemoryDC.CreateCompatibleDC(m_pTarget);

    //대상DC에대한메모리비트맵을생성하여Select 한다.

    m_MemoryBmp.CreateBitmap(m_RcClient.Width(), m_RcClient.Height(),

        m_MemoryDC.GetDeviceCaps(PLANES),

        m_MemoryDC.GetDeviceCaps(BITSPIXEL), 0);

    m_pOldMemoryBmp = m_MemoryDC.SelectObject(&m_MemoryBmp);

 

    //메모리버퍼에Attach한다.

    Attach(m_MemoryDC);

}

 

//////////////////////////////////////////////////////////////////////

CBufferDC::~CBufferDC()

{

    //메모리DC의내용을대상윈도우에출력한다.

    //내부적으로비트맵에출력한것이므로해당비트맵을1:1로복사한다.

    m_pTarget->BitBlt(

        m_PaintStruct.rcPaint.left,

        m_PaintStruct.rcPaint.top,

        m_PaintStruct.rcPaint.right - m_PaintStruct.rcPaint.left,

        m_PaintStruct.rcPaint.bottom - m_PaintStruct.rcPaint.top,

        &m_MemoryDC,

        m_PaintStruct.rcPaint.left,

        m_PaintStruct.rcPaint.top, SRCCOPY);

 

    m_MemoryDC.SelectObject(m_pOldMemoryBmp);

    m_pParent->EndPaint(&m_PaintStruct);

 

    Detach();

}

 

//////////////////////////////////////////////////////////////////////

BOOL CBufferDC::Attach(HDC hDC)

{

return CDC::Attach(hDC);

}

 

//////////////////////////////////////////////////////////////////////

HDC CBufferDC::Detach()

{

return CDC::Detach();

}

 

    [OnEraseBkgnd() 함수]

BOOL CXXXView::OnEraseBkgnd(CDC* pDC)

{

    return TRUE;

//    return CView::OnEraseBkgnd(pDC);

}

 

    [OnPaint() 함수]

 

void CRedrawDemoView::OnPaint()

{

//    CPaintDC dc(this); // device context for painting

    CBufferDC dc(this); //더블버퍼링 그리기 수행

 

    CRect Rect;

    GetClientRect(&Rect);

    dc.FillSolidRect(&Rect, RGB(192, 0, 0));

 

    Rect -= CRect(7, 7, 7, 7);

    dc.SelectStockObject(NULL_PEN);

    dc.RoundRect(&Rect, CPoint(21, 21));

 

    dc.SetBkMode(TRANSPARENT);

    dc.TextOut(30, 30, _T("Test string!"));

 

}

 

Triple Buffering (트리플 버퍼링)

    원본 버퍼링 DC와 이것을 복사한 버퍼링 DC를 만든다.

    복사한 버퍼링 DC에서 변경되고 있는 그리기를 반영하여 출력하며

    그리기가 수행되기 전으로 되돌려야 할 땐 원본 버퍼링 DC를 출력하고

    그리기가 반영된다면 복사한 버퍼링 DC를 출력하는 방법

 

Multiple View (다중 뷰) : 동적 분할 윈도우

    runtime시 client 영역의 분할을 할 수 있는 윈도우로 동일한 내용을 표시

    1. CMainFrame에 CSplitterWnd m_wndSplitterWnd; 멤버 변수를 정의

    2. CMainFrame의 OnCreateClient()를 재정의하여 아래 코드 작성

        return m_wndSplitterWnd.Create(this, 2, 2, CSize(1, 1), pContext);

 

Multiple View (다중 뷰) : 정적 분할 윈도우

    생성시 client 영역을 분할하며 영역 별로 다른 윈도우를 붙일 수 있음.    

 

    [사용 예]

    1.split된 화면에 붙일 View 클래스 생성

        CLeftListView        : CListView 상속한 클래스

        CTopHtmlView        : CHtmlView 상속한 클래스

        CBottomEditView    : CEditView 상속한 클래스

 

    2. CMainFrame에 CSplitterWnd 멤버 변수 추가

        CSplitterWnd m_wndSplitHor;    //수평 분할 splitter 멤버 변수 추가

        CSplitterWnd m_wndSplitVer;    //수직 분할 splitter 멤버 변수 추가

 

    3. CMainFrame::OnCreateClient()에 초기화 작업 및 return TRUE; 로 변경

    //좌,우로 정적분할

    if(!m_wndSplitHor.CreateStatic(this,1, 2))

        return FALSE;

 

    //왼쪽에 뷰 클래스 붙임

    if(!m_wndSplitHor.CreateView(0, 0,

        RUNTIME_CLASS(CLeftListView), CSize(200, 200), pContext))

        return FALSE;

 

    //오른쪽은 위,아래로 분할

    if(!m_wndSplitVer.CreateStatic(&m_wndSplitHor, 2, 1,

        WS_CHILD | WS_VISIBLE,

        m_wndSplitHor.IdFromRowCol(0, 1)))

        return FALSE;

 

    //오른쪽 위에 뷰 클래스 붙임

    if(!m_wndSplitVer.CreateView(0, 0,

        RUNTIME_CLASS(CTopHtmlView), CSize(100, 300), pContext))

        return FALSE;

 

    //오른쪽 아래에 뷰 클래스 붙임

    if(!m_wndSplitVer.CreateView(1, 0,

        RUNTIME_CLASS(CBottomEditView), CSize(200, 100), pContext))

        return FALSE;

 

    //왼쪽 뷰에 포커스를 줌

    SetActiveView((CView*)m_wndSplitHor.GetPane(0,0)); //GetPane()으로 해당 영역의 View 클래스 획득

 

    return TRUE;    //반드시 TRUE 리턴해야 함.

//    return CFrameWnd::OnCreateClient(lpcs, pContext);

 

SDI 에서 View 교체 구현

    메뉴 명령에 따라 View 교체하기

    [교체할 View 클래스 생성]

    CMyHtmlView, CMyEditView, CMyListView

 

    [CMainFrame 에 멤버 변수 등록 및 뷰에 할당할 ID값 정의]

#define VIEWID_DEFAULT        AFX_IDW_PANE_FIRST

#define VIEWID_HTML            AFX_IDW_PANE_FIRST + 10

#define VIEWID_EDIT            AFX_IDW_PANE_FIRST + 20

#define VIEWID_LIST            AFX_IDW_PANE_FIRST + 30

 

    CMyHtmlView*        m_pwndHtmlView;

    CMyEditView*        m_pwndEditView;

    CMyListView*        m_pwndListView;

 

    [CMainFrame::OnCreateClient()에서 각 뷰 초기화]

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)

{

    m_pwndHtmlView    = new CMyHtmlView;

    m_pwndEditView    = new CMyEditView;

    m_pwndListView    = new CMyListView;

    m_pwndHtmlView->Create(NULL, NULL, WS_CHILD, CFrameWnd::rectDefault, this, VIEWID_HTML, pContext);

    m_pwndEditView->Create(NULL, NULL, WS_CHILD, CFrameWnd::rectDefault, this, VIEWID_EDIT, pContext);

    m_pwndListView->Create(NULL, NULL, WS_CHILD, CFrameWnd::rectDefault, this, VIEWID_LIST, pContext);

 

    return CFrameWnd::OnCreateClient(lpcs, pContext);

}

 

    [CMainFrame에서 View 변경 함수 구현]

void CMainFrame::SwitchView(int nID)

{

    CView* pOldView = GetActiveView();

    CView* pNewView = NULL;

 

    switch (nID)

    {

    case VIEWID_HTML:

        pNewView = (CView*)m_pwndHtmlView;

        break;

 

    case VIEWID_EDIT:

        pNewView = (CView*)m_pwndEditView;

        break;

 

    case VIEWID_LIST:

        pNewView = (CView*)m_pwndListView;

        break;

    }

 

    if(pNewView)

    {

        if(pOldView == pNewView)            return;

 

        pOldView->ShowWindow(SW_HIDE);

        pOldView->SetDlgCtrlID(nID);

 

        pNewView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);

        pNewView->ShowWindow(SW_SHOW);

        SetActiveView(pNewView);

        RecalcLayout();

    }

}

 

    [CMainFrame 에서 View 변경 호출 함수 작성]

void CMainFrame::OnMenuHtmlview()

{

    SwitchView(VIEWID_HTML);

}

 

void CMainFrame::OnMenuEditview()

{

    SwitchView(VIEWID_EDIT);

}

 

void CMainFrame::OnMenuListview()

{

    SwitchView(VIEWID_LIST);

}

 

 

Scroll View (스크롤 뷰)

    CScrollView를 상속받아 scrolling을 지원해주는 뷰

 

    [사용 방법]

void CXXXView::OnInitialUpdate()

{

    CScrollView::OnInitialUpdate();

 

    CSize sizeTotal;

    sizeTotal.cx = 1600;

    sizeTotal.cy = 1200;

 

    SetScrollSizes(MM_TEXT, sizeTotal); //스크롤 최대 크기 지정

}

 

void CImageScrollDemoView::OnPaint()

{

    CPaintDC dc(this); // device context for painting

 

    int nVertScroll = GetScrollPos(SB_VERT);    //현재 스크롤 위치 획득

    int nHorzScroll = GetScrollPos(SB_HORZ);

 

    CImage Image;

    Image.LoadFromResource(AfxGetInstanceHandle(), IDB_Image);

    Image.BitBlt(dc.m_hDC, -nHorzScroll, -nVertScroll); //스크롤 위치에 따라 이미지 그리기 변경

}

 

BOOL CImageScrollDemoView::OnEraseBkgnd(CDC* pDC)

{

    return TRUE;

//    return CScrollView::OnEraseBkgnd(pDC);

}

 

 

MFC의 App, MainFrame, Document, View 간 상호 참조 방법

    [최상위로부터 접근]

    SDI

        CWinApp 접근        : AfxGetApp()

        CMainFrame 접근    : AfxGetMainWnd()

        CView 접근        : AfxGetMainWnd()->GetActiveView()

        CDocument 접근    : AfxGetMainWnd()->GetActiveDocument()

    MDI

        CWinApp 접근        : AfxGetApp()

        CMDIMainWnd 접근    : AfxGetMainWnd()

        CMDIChildWnd 접근    : AfxGetMainWnd()->GetActiveFrame()

        CView 접근        : AfxGetMainWnd()->GetActiveFrame()->GetActiveView()

        CDocument 접근    : AfxGetMainWnd()->GetActiveFrame()->GetActiveDocument()

 

        

    [직접 접근]

    SDI

        

    MDI

        

 

 

CDocument 클래스의 주요 메서드

    AddView()        : CDocument 클래스 객체의 정보 표시시 관련된 뷰 윈도우 등록

    GetFirstViewPosition()    : AddView()로 등록된 첫번째 뷰 윈도우 획득

    GetNextView()        : GetFirstViewPosition()이 리턴한 뷰 윈도우 목록에 있는 다음 뷰 윈도우 획득

    GetPathName()    : 로딩한 문서 파일의 전체 경로를 CString으로 반환

    GetTitle()        : 확장자를 제외한 문서의 파일명을 CString으로 반환

    IsModified()        : 문서가 수정되었는지 검사하고 수정시 저장여부 메시지 dialog 출력

    SetModifiedFlag()    : 문서 수정 여부 강제 지정

    SetTitle()        : 문서 파일명 변경

    UpdateAllViews()    : 연결된 모든 뷰 윈도우의 OnUpdate()를 호출.

 

사용자 정의 메시지 사용

    1. 사용자 메시지 정의

        #define UM_TESTMESSAGE    WM_USER+100

    2. 메시지 처리 함수 등록 (함수 형태 변경 불가)

        LRESULT afx_msg OnTestMessage(WPARAM wParam, LPARAM lParam);

        LRESULT afx_msg CXXXView::OnTestMessage(WPARAM wParam, LPARAM lParam)

        {

            AfxMessageBox(_T("user message"));

            return 0;

        }

    3. BEGIN_MESSAGE_MAP()에 메시지 추가

        ON_MESSAGE(UM_TESTMESSAGE, &CXXXView::OnTestMessage)

    4. 사용자 메시지 발생

        GetActiveView()->PostMessage(UM_TESTMESSAGE, 0, 0);

 

Timer (타이머)

    타이머는 오랫동안 사용시 느려지는 현상이 있으므로 정확한 시간 측정이 필요할 경우엔 다른 방법을 사용해야 한다.

    (QueryPerformanceCounter()는 마이크로 세컨드(us)단위의 측정이 가능하다)

    1. SetTimer()로 Timer 생성

        //첫번째 인자    : 타이머 ID

        //두번째 인자    : 동작 주기(ms)

        //세번째 인자 : 호출할 함수. NULL인 경우 WM_TIMER 메시지 발생하므로 OnTimer() 함수에서 처리

        if (SetTimer(10, 1000, NULL) == 0)

AfxMessageBox(_T("타이머 생성 실패"));

    2. Timer 콜백 함수 원형

    void CALLBACK EXPORT TimerProc(

        HWND        hWnd,        //윈도우 핸들

        UINT        nMsg,        //WM_TIMER

        UINT        mIDEvent,    //Timer ID

        DWORD    dwTime    //System time : GetTickCount()

    );

 

    3. Timer 종료 : KillTimer()

        KillTimer(10);    //10은 Timer ID

 

윈도우 세션 종료

    [윈도우 종료 혹은 logoff시 응용프로그램에서 이를 막는 방법]

    WM_QUERYENDSESSION 메시지 핸들러 함수(OnQueryEndSession())에서 return FALSE; 를 할 경우OS는 종료를 못하게 된다.

 

    WM_QUERYENDSESSION 메시지    : OS 종료 혹은 logoff시 어플리케이션에 전달되는 메시지

    WM_ENDSESSION 메시지        : OS 종료가 확정된 경우 마지막으로 어플리케이션에 전달되는 메시지

    ExitWindows() 매크로    : 내부에서 ExitWindowsEx()를 호출하여 OS를 종료시킴

    ExitWindowsEx() 함수    : 첫번쨰 인자 : 윈도우 종료 방법 설정, 두번째 인자 : 종료 이유 설정

 

    [윈도우를 종료하는 보편적인 샘플]

How to Shut Down the System : http://msdn.microsoft.com/en-us/library/aa376871(v=VS.85).aspx

 

사용자 전환

    WM_WTSSESSION_CHANGE 메시지    : 사용자 전환시 발생하는 메시지로 특정 API로 등록된 윈도우만 받을 수 있음

 

    [사용 샘플]

    1. 라이브러리 및 헤더 추가

#include <Wtsapi32.h>

#pragma comment(lib, "Wtsapi32.lib")

    2. WM_WTSSESSION_CHANGE 메시지를 받을 수 있도록 등록

    if(!::WTSRegisterSessionNotification(m_hWnd, NOTIFY_FOR_ALL_SESSIONS))

    {

        AfxMessageBox(_T("ERROR: Failed to register session notification!"));

        return FALSE;

    }

    3. WM_WTSSESSION_CHANGE 메시지 처리

void CXXXDlg::OnSessionChange(UINT nSessionState, UINT nId)

{

    CString strTmp = _T("");

    DWORD dwSize = 256;

 

    TCHAR* pszBuffer = NULL;

//    DWORD dwSessionID = ::WTSGetActiveConsoleSessionId(); //콘솔 시스템에서 활성화된 세션ID 획득

 

    //상세 정보 획득

    if(::WTSQuerySessionInformation(

                    WTS_CURRENT_SERVER_HANDLE,

                    nId, WTSUserName, &pszBuffer, &dwSize))

    {

        strTmp.Format(_T("Session ID : %d(%s)"), nId, pszBuffer);

        ::WTSFreeMemory(pszBuffer); //필수

    }

    else

{

strTmp.Format(_T("Session ID : %d(Unknown)"), nId);

    }

 

    switch(nSessionState)

    {

    case WTS_SESSION_LOGON:

        m_List.AddString(_T("WTS_SESSION_LOGON"));

        break;

    case WTS_SESSION_LOGOFF:

        m_List.AddString(_T("WTS_SESSION_LOGOFF"));

        break;

    case WTS_SESSION_LOCK:

        m_List.AddString(_T("WTS_SESSION_LOCK"));

        break;

    case WTS_SESSION_UNLOCK:

        m_List.AddString(_T("WTS_SESSION_UNLOCK"));

        break;

    case WTS_CONSOLE_CONNECT:

        m_List.AddString(_T("WTS_CONSOLE_CONNECT"));

        break;

    case WTS_CONSOLE_DISCONNECT:

        m_List.AddString(_T("WTS_CONSOLE_DISCONNECT"));

        break;

    }

 

    m_List.AddString(strTmp);

    CDialog::OnSessionChange(nSessionState, nId);

}

    4. 강제 로그 오프

        ::WTSLogoffSession(WTS_CURRENT_SERVER_HANDLE, m_dwSessionID, TRUE);

    5. WM_WTSSESSION_CHANGE 메시지 등록 해제 (필수)

::WTSUnRegisterSessionNotification(m_hWnd);

 

Sub classing (서브 클래싱)

    이미 생성되어 있는 특정 윈도우의 윈도우 프로시저 함수를 다른 함수로 대체하여 기능을 확장하는 방법

 

    [Win32 에서의 서브 클래싱]

    ::SetWindowLong()으로 윈도우 프로시저를 다른 함수로 변경.

    변경할 윈도우 프로시저를 전역 함수로 작성.

    새 윈도우 프로시저 함수는 반드시 ::CallWindowProc()으로 호출해야 함.

    

    [MFC에서의 서브 클래싱]

    간단하게 파생 클래스 작성으로 이루어짐

    

    [서브 클래싱 작성 예]

    0. Dialog에 리스트 컨트롤(report style)를 넣고 컬럼에 네모 박스를 그려서 클릭시 색이 변경되도록 작성하는 예제

    1. CXXXDlg에 리스트 컨트롤 추가 후 연결 변수 등록

        CListCtrl m_List;    //등록된 리스트 컨트롤 연결 변수

    2. CXXXDlg::OnInitDialog()에서 기본 컬럼 초기화

        m_List.InsertColumn(0, _T(" "), LVCFMT_LEFT, 20);

        m_List.InsertColumn(1, _T("Name"), LVCFMT_LEFT, 220);

        m_List.InsertColumn(2, _T("Test"), LVCFMT_LEFT, 220);

    3. 서브 클래스 생성 및 작성

        CWnd를 상속받는 CSubClassTestWnd 클래스 생성

        BOOL    m_bFlag;    //클릭시 네모 박스 색 변경을 위한 멤버변수 추가

        m_bFlag = TRUE;    //생성자에서 초기화

        void CSubClassTestWnd::OnPaint()

{

            CWnd::OnPaint();    //기본적인 CWnd의 그리기 수행

            CClientDC dc(this);    //추가적인 그리기 수행

            CRect Rect(3, 3, 16, 16);

            if(m_bFlag)    dc.FillSolidRect(&Rect, RGB(192, 0, 0)); //클릭시마다 색이 다른 네모 박스 그리기

            else        dc.FillSolidRect(&Rect, RGB(255, 255, 255));

}

 

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

{

            CWnd::OnLButtonDown(nFlags, point);

        

            CRect Rect(3, 3, 16, 16);

            if(PtInRect(&Rect, point))    //해당 영역에서 버튼 클릭시

            {

                m_bFlag = !m_bFlag;    //네모 상자의 색 변경 플래그 갱신

                RedrawWindow();    //OnPaint 호출

            }

}

 

void CSubClassTestWnd::OnDestroy()

{

            UnsubclassWindow();    //서브클래싱 종료

            CWnd::OnDestroy();

}

 

    4. CXXXDlg 에서 CSubClassTestWnd 를 멤버변수(m_wndTest)로 추가

        CSubClassTestWnd    m_wndTest;    //멤버 변수 추가

    5. . CXXXDlg::OnInitDialog()에서 서브 클래싱 등록

        CHeaderCtrl* pHeaderCtrl = m_List.GetHeaderCtrl();    //첫번째 헤더 컨트롤을 구함

        m_wndTest.SubclassWindow(pHeaderCtrl->m_hWnd);        //첫번쨰 헤더 컨트롤에 대한 서브 클래스로 등록

 

확장 컨트롤

    생성할 컨트롤 윈도우의 기능을 확장하고 싶은 경우 사용.

    MFC의 컨트롤 클래스를 상속하여 함수를 재정의 하거나 기능을 확장하여 서브 클래싱을 구현함.

 

    [오너 드로우(Owner-draw) 버튼 예제]

    오너 드로우(Owner-draw)

: 컨트롤의 외관을 독자적으로 변경할 수 있는 기능

컨트롤 윈도우에 Owner draw 속성을 true로 줄 경우 DrawItem() 메소드의 재정의를 통해 그리기가 수행됨.

        MFC에선 오너 드로우 구현을 서브 클래싱을 전제로 함.

 

    1. dialog에 버튼 추가 후 Owner Draw 속성을 True로 준 후 CButton m_Btn_Image; 라는 연결 변수 생성

    2. CButton을 상속받는 클래스 생성. (여기선 CImageButton으로 정함)

    3. 기존에 추가한 m_Btn_Image를 CButton에서 CImageButton으로 변경

    4. CImageButton 클래스 수정

        BOOL    m_bHover;        //마우스가 올라왔을때를 위한 멤버 변수

        BOOL    m_bTracking;

        m_bHover        = FALSE;    //생성자에서 초기화

        m_bTracking        = FALSE;

 

        void CImageButton::OnMouseMove(UINT nFlags, CPoint point)

        {    //마우스 이벤트 추적 등록

            if(!m_bTracking)

            {

                TRACKMOUSEEVENT tme;

                ::ZeroMemory(&tme, sizeof(tme));

 

                tme.cbSize        = sizeof(tme);

                tme.hwndTrack    = m_hWnd;

                tme.dwFlags        = TME_LEAVE | TME_HOVER; //WM_MOUSEHOVER, WM_MOUSELEAVE 메시지 추적

                tme.dwHoverTime    = 1;

 

                m_bTracking = ::_TrackMouseEvent(&tme);

            }

            CButton::OnMouseMove(nFlags, point);

        }

 

        void CImageButton::OnMouseHover(UINT nFlags, CPoint point)

        {    //마우스가 위에 올라왔을 때 flag변경 및 OnPaint() 호출

            m_bHover = TRUE;

            RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);

 

            CButton::OnMouseHover(nFlags, point);

        }

 

        void CImageButton::OnMouseLeave()

        {    //마우스가 떠났을 때 flag 변경 및 OnPaint() 호출

            m_bHover    = FALSE;

            m_bTracking    = FALSE;

            RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);

 

            CButton::OnMouseLeave();

        }

 

        void CImageButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

        {

            CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

 

            CDC MemDC;

            MemDC.CreateCompatibleDC(pDC);

 

            CBitmap Bmp;

            Bmp.LoadBitmap(IDB_Button_Image);

            CBitmap* pOldBitmap = MemDC.SelectObject(&Bmp);

 

            if(lpDrawItemStruct->itemState & ODS_SELECTED) //버튼을 선택했는지 판별

            {

                pDC->BitBlt(0, 0, 40, 40, &MemDC, 40, 0, SRCCOPY);

            }

            else

            {

                if(m_bHover)    pDC->BitBlt(0, 0, 40, 40, &MemDC, 80, 0, SRCCOPY);

                else        pDC->BitBlt(0, 0, 40, 40, &MemDC, 0, 0, SRCCOPY);

            }

 

            MemDC.SelectObject(pOldBitmap);

        }

 

    [확장 프로그레스(progress) 컨트롤]

    프로그레스의 UI를 변경하는 예제

    CProgressCtrl의 파생클래스에서 OnPaint()를 재정의 하여 UI를 변경한다.

    프로그레스 컨트롤은 오너 드로우(Owner-draw)기능이 없으며 DrawItem() 메소드도 갖고 있지 않다.

 

    1. dialog에 프로그레스 추가 후 CProgressCtrl m_Progress; 라는 연결 변수 생성

    2. CProgressCtrl을 상속받는 클래스 생성. (여기선 CTextProgressCtrl로 정함)

    3. 기존에 추가한 m_Progress를 CProgressCtrl에서 CTextProgressCtrl로 변경

    4. CTextProgressCtrl클래스 에서 OnPaint() 재정의

        #pragma once

        // CTextProgressCtrl

 

        class CTextProgressCtrl : public CProgressCtrl

        {

            DECLARE_DYNAMIC(CTextProgressCtrl)

 

        public:

            CTextProgressCtrl();

            virtual ~CTextProgressCtrl();

 

            int        m_nData;

 

        protected:

            DECLARE_MESSAGE_MAP()

        public:

            afx_msg void OnPaint();

            void SetValue(int nPos);

        };

        // TextProgressCtrl.cpp : implementation file

        //

 

        #include "stdafx.h"

        #include "TextProgressDemo.h"

        #include "TextProgressCtrl.h"

 

        // CTextProgressCtrl

 

        IMPLEMENT_DYNAMIC(CTextProgressCtrl, CProgressCtrl)

 

        CTextProgressCtrl::CTextProgressCtrl()

        {

            m_nData = 0;

        }

 

        CTextProgressCtrl::~CTextProgressCtrl()

        {

        }

 

        BEGIN_MESSAGE_MAP(CTextProgressCtrl, CProgressCtrl)

            ON_WM_PAINT()

        END_MESSAGE_MAP()

 

        // CTextProgressCtrl message handlers

        void CTextProgressCtrl::OnPaint()

        {

            CPaintDC dc(this);

 

            CString strTmp = _T("");

            strTmp.Format(_T("%d%%"), m_nData);

 

            //프로그래스컨트롤을둘로나누기위해서윈도우크기를계산한다.

            CRect LeftRect, RightRect, ClientRect;

            GetClientRect(ClientRect);

            LeftRect = ClientRect;

            RightRect = ClientRect;

 

            //1%에해당하는윈도우크기를계산한다.

            //그리고, 둘로나누어진왼쪽과오른쪽각각에대해서다른색으로칠한다.

            LeftRect.right = (ClientRect.right * m_nData) / 100;

            RightRect.left = (ClientRect.right * m_nData) / 100;

            dc.FillSolidRect(LeftRect, RGB(0, 0, 128));

            dc.FillSolidRect(RightRect, RGB(255, 255, 255));

 

            //왼쪽과오른쪽을두영역으로구분한다.

            CRgn LeftRgn, RightRgn;

            LeftRgn.CreateRectRgnIndirect(LeftRect);

            RightRgn.CreateRectRgnIndirect(RightRect);

            

            //왼쪽영역에비율표시텍스트를중앙정렬하여출력한다.

            dc.SetBkMode(TRANSPARENT);

            dc.SetTextColor(RGB(255, 255, 255));

            dc.SelectClipRgn(&LeftRgn);

            dc.DrawText(strTmp, ClientRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

 

            //오른쪽영역에비율표시텍스트를중앙정렬하여출력한다.

            dc.SetTextColor(RGB(0, 0, 128));

            dc.SelectClipRgn(&RightRgn);

            dc.DrawText(strTmp, ClientRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

        }

        void CTextProgressCtrl::SetValue(int nPos)

        {

            m_nData = nPos;

            RedrawWindow();

        }

 

 

GDI+ (Graphic Device Interface Plus)

    http://winapi.co.kr/project/library/gdiplus/gdiplus.htm

    2D 벡터 그래픽 사용, 이미지 캐싱 사용, 안티 엘리어싱 적용 됨. (XP 부터 등장)

    XP에선 DirectX와 GDI가 분리된 구조지만 Vista부터는 모두 DirectX Runtime 위에 올라간다.

    XP는 GDI+는 1.0 버전이며 Vista는 1.1 버전임.

 

[GDI+ 초기화 및 기본 사용]

//Ex. StdAfx.h

#include <gdiplus.h>

#pragma comment(lib, "gdiplus")

using namespace Gdiplus;

 

//Ex. CXXXApp::InitInstance() 안에서..

    ULONG_PTR    gdiplusToken;

    GdiplusStartupInput gdiplusStartupInput;

    if (::GdiplusStartup(&gdiplusToken, &dgiplusStartupInput, NULL) != Ok)    //GDI+ 초기화

        AfxMessageBox(_T("error"));

    }

    if (!AfxOleInit())    //OLE 라이브러리 초기화 : 상관없음

    {

        AfxMessageBox(IDP_OLE_INIT_FAILED);

    }

 

    //Ex. CXXXApp::ExitInstance() 안에서..

    ::GdiplusShutdown(gdiplusToken);    //GDI+ 해제

 

    [CXXXView::OnPaint() 에서 그리기 준비]

    CPaintDC dc(this);

    Graphic graphic(dc);    //GDI+ 클래스

 

    [펜, 직선 사용 1 : 기본 사용]

    Pen BluePen(Color(255, 0, 0, 255), 20.0f);    //펜 설정 : 첫번째 값이 alpha 값, 20.0f는 굵기

    graphics.DrawLine(&BluePen, Point(10, 50), Point(210, 50));

 

    BluePen.SetColor(Color(128, 0, 0, 0));    //펜 재활용 : 색 변경

    graphics.DrawLine(&BluePen, Point(20, 60), Point(220, 60));

 

    [펜, 직선 사용 2 : 선 연결, 선 스타일, 선 끝부분 스타일 지정]

    Pen BluePen(Color(255, 0, 0, 255), 20.0f);    //펜 설정

    Point point1(30, 10);

    Point point2(30, 110);

    Point point3(230, 20);

    Point point4(230, 120);

    Point points[4] = {point1, point2, point3, point4};

 

    BluePen.SetLineJoin(LineJoinRound);    //라인을 둥글게 연결

    BluePen.SetDashStyle(DashStyleDot);    //선 스타일 지정

    BluePen.SetStartCap(LineCapRoundAnchor);    //둥근 시작점

    BludPen.SetEndCap(LineCapArrowAnchor);    //화살표 끝점

    graphic.DrawLines(&BludPen, points, 4);

 

    [곡선, 안티 에일리어싱]

    graphics.SetSmoothingMode(SmoothingModeHighQuality);    //안티 에일리어싱 적용

    Pen RedPen(Color(255, 255, 0, 0), 2.0f);

    Pen GreenPen(Color(255, 0, 255, 0), 2.0f);

    Pen BluePen(Color(255, 0, 0, 255), 2.0f);

 

    Point points[6] = {Point(10, 150), {Point(110, 10), Point(170, 250), Point(220, 120), Point(270, 150), Point(350, 150)};

    graphics.DrawCurve(&RedPen, points, 6, 0.0f);        //points에서 좌표 6개를 사용하며 0.0f의 커브 사용(직선으로 나옴)

    graphics.DrawCurve(&GreenPen, points, 6, 0.5f);    //마지막 인자 값(0.5f)은 곡선의 정도를 의미

graphics.DrawCurve(&BluePen, points, 6, 1.0f);    

 

    [도형 그리기]

    Pen BlackPen(Color(255, 0, 0, 0), 20.0f);

    graphics.DrawRectangle(&BlackPen, 30, 30, 100, 100);    //30, 30 좌표에 100, 100 크기의 사각형 그림

    graphics.DrawEllipse(&BlackPen, 30, 30, 100, 100);        //원 그리기 : 30, 30 좌표에 100, 100 크기의 원 그림

    graphics.DrawArc(&BlackPen, 30, 30, 150, 150, 0.0f, 90.0f);    //원호 그리기

    graphics.DrawPie(&BlackPen, 30, 30, 150, 150, 180.0f, 90.0f);    //부채꼴 그리기

 

    Pen BlackPen(Color(255, 0, 0, 0), 20.0f);

    Point points[6] = {Point(30, 30), Point(180, 30), Point(180, 130), Point(130, 130), Point(130, 80), Point(30, 80)};

    graphics.DrawPolygon(&RedPen, points, 6);    //다각형 그리기

 

    [솔리드 (Solid) 브러시(Brush)]

    SolidBrush solidbrush(Color(255, 0, 0, 192));    //브러시 설정

    graphics.FilRectangle(&solidbrush, 20, 20, 100, 100);

 

    //빗살 무늬(Hatch) 브러시

    int nStyle = HatchStyleHorizontal;

    int nCounter = 0;

    for (int y=0; y<6; ++y)

    {

        for (int x=0; x<10; ++x)

        {

            //빗살 무늬(Hatch) 브러시

            HatchBrush hatchbrush((HatchStyle)(nStyle + nCounter), Color::Black, Color::Transparent);

            graphics.FillRectangle(&hatshbrush, x*50+20, y*40+20, 40, 30);

            nCounter++;

            if (nCounter >= HatchStyleMax)    break;

        }

    }

 

    [그라데이션(Gradation) 브러시]

    //그라데이션(Gradation) 브러시 1 : 두 좌표의 선이 이루는 각데로 그라데이션 적용

    //(0, 0)좌표부터 (100,100)좌표까지 지정한 색으로 그라데이션 적용.

    LinearGradientBrush lgBrush(Point(0, 0), Point(100, 100), Color(128, 221, 236, 255), Color(255, 86, 125, 204));

    graphics.FillRectangle(&lgBrush, 0, 0, 600, 200);

 

    //그라데이션(Gradation) 브러시 2 : 정해진 그라데이션 사용

    LinearGradientBrush lgBrush(Rect(10, 10, 200, 200), Color(128, 221, 236, 255), Color(255, 86, 125, 204), LinearGradientModeVertical);

    graphics.FillRectangle(&lgBrush, 10, 10, 200, 200);

 

    //그라데이션(Gradation) 브러시 3 : 그라데이션 각도 직접 설정

    LinearGradientBrush lgBrush(Rect(10, 10, 200, 200), Color(128, 221, 236, 255), Color(255, 86, 125, 204), 45.0f, FALSE);

    graphics.FillRectangle(&lgBrush, 10, 10, 200, 200);

 

    [텍스처(Texture) 브러시]

    //bitmap을 입히는 브러시

    Image image(_T("texture.jpg"));

    TextureBrush txBrush(&image, WrapModeTile);    //텍스처 이미지 로드(WrapModeTile:바둑판형식)

    

    CRect rectClient;

    GetClientRect(&rectClient);

    graphics.FillRectangle(&txBrush, 0, 0, rectClient.Width()/2, rectClient.Height());

    txBrush.SetWrapMode(WrapModeTileFlipXY);        //텍스터 이미지를 좌우 반전 시킴

    graphics.FillRectangle(&txBrush, rectClient.Width()/2, 0, rectClient.Width()/2, rectClient.Height());

    

    [외부 이미지 파일 처리]

    Image 클래스    : 외부 이미지 파일 처리의 기본 클래스. GDI의 CImage 클래스와 동일한 기능.

    Bitmap 클래스    : 이미지 프로세싱 등 추가 기능 필요시 사용.

비트맵 핸들, 아이콘 핸들에 대한 이미지 생성/관리. (Image 클래스 상속)

    MetaFile 클래스: WMF나 EMF 파일 처리 (Image 클래스 상속)

        [Image 클래스]

        Image image(_T("test.jpg"));        //로그

        graphics.DrawImage(&image, 0, 0);    //원본 그데로 (0,0)좌표에 출력

        graphics.DrawImage(&image, 100, 50, image.GetWidth()/4, image.GetHeight()/4);    //(100,50)좌표에 1/4 축소하여 출력

        

        //기울어진 이미지 출력 : 왼쪽 위, 오른쪽위, 왼쪽 아래 좌표로 기울어진 이미지 출력

        Point points[] = {Point(200,0), Point(image.GetWidth(), 0), Point(0, image.GetHeight())};

        graphics.DrawImage(&image, points, 3);

 

        [Bitmap 클래스]

        Bitmap bmp(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_Sample));    //리소스에서 로딩하는 예제

        graphics.DrawImage(&bmp, 10, 10);

 

        [CachedBitmap 클래스]

        //비트맵 캐싱 : 출력할 비트맵을 DDB로 변환하여 보관하여 매번 DIB에서 DDB 변환을 하지 않도록 하는 기능

        //이미지를 여러 번 출력할 경우 이점을 갖음.

        Bitmap bmp(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_Sample));

        CachedBitmap cachedbmp(&bmp, &graphics);

 

        //graphics.DrawCachedBitmap()이 graphics.DrawImage(&bmp, 10,10); 보다 3배정도의 속도 향상

        graphics.DrawCachedBitmap(&cachedbmp, 10, 10);

        

    [글꼴(Font), 문자열]

    Font font(_T("Arial"), 100, FontStyleBold, UnitPixel);    //글꼴(Font) 설정

    PointF ptText(10.0f, 10.0f);

    HatchBrush brush(HatchStyleSmallCheckerBoard, Color(255, 128, 0, 0), Color::Transparent);

    graphics.DrawString(_T("Test String"), -1, &font, ptText, &brush);    //문자열 출력 : GDI의 TextOut()에 대응됨

 

    //StringFormat : 특정 사각형 기준으로 문자열 출력 : GDI의 DrawText()에 대응됨

    Font font(_T("Arial"), 48, FontStyleBold, UnitPixel);

    SolidBrush sbrush(Color::Black);

    Pen pen(Color::Blue);

    StringFormat format;        //사각형 출력시 문자열의 style 설정

    format.SetAlignment(StringAlignmentCenter);        //가로의 가운데 정렬

    format.SetLineAlignment(StringAlignmentCenter);    //세로의 가운데 정렬

    format.SetFormatFlags(StringFormatFlagsDirectionVertical);    //문자열을 세로로 출력

    format.SetTrimming(StringTrimmingEllipsisCharacter);    //사각형 초과시 … 으로 축약시킴

    format.SetHotkeyPrefix(HotkeyPrefixShow);        //문자열 출력시 &가 있는 문자에 밑줄을 줌(메뉴 바로가기키 처럼..)

    graphics.DrawRectangle(&pen, RectF(10, 10, 200, 200));

    graphics.DrawString(_T("Test &String"), -1, &font, RectF(10, 10, 200, 200), &format, &sbrush));

 

    [경로 (Path)]

    Pen pen(Color(255, 0, 0, 0), 3);

    SolidBrush sbrush(Color(255, 192, 192, 192));

 

    GraphicsPath path;        //경로(Path)

    path.AddRectangle(Rect(10, 0, 100, 100));    //path에 사각형 추가

    path.AddEllipse(Rect(70, 70, 120, 120));        //path에 원 추가

    FontFamily fontFamily(_T("Arial"));

    path.AddString(_T("Test String"), -1, &fontFamily, FontStyleBold, 48, Point(20, 20), NULL);    //path에 글자 추가

    path. SetFillMode(FillModeWinding);    //채우기 모드. FillModeAlternate : 겹치는 면은 반전시킴

    graphics.FillPath(&sbrush, &path);    //면을 채움

    graphics.DrawPath(&pen, &path);    //선을 그림

 

    [영역(Region)]

    Region Rgb(&path);    //path는 위의 경로(path)의 코드에서 작성한 path변수임

    graphics.SetClip(&Rgn);    //path에서 면이 있는 부분만 그리기 수행

    Font font(_T("Arial"), 100, FontStyleBold, UnitPixel);

    HatchBrush htbrush(HatchStyleDiagonalBrick, Color:Black, Color::Chocolate);

    graphics.DrawString(_T("Test String"), -1, &font, PointF(10, 10), &htbrush);

 

    //영역에 대한 단순한 예제

    Pen pen(Color(255, 0, 0, 0), 1);

    SolidBrush sbrush(color(255, 192, 192, 192));

 

    Region Rgn1(Rect(10, 10, 140, 140));    //영역1

    Region Rgn2(Rect(80, 50, 140, 140));    //영역1

 

    Rgn2.Xor(&Rgn1);    //겹치는 부분은 제외시킴. Intersact() : 교집합 부분, Exclude() : 빼기 부분, Union() : 합집합

    graphics.Fillregion(&sbrush, &Rgn2);

 

    [좌표계 변환]

        [Matrix 사용]

        Pen pen(Color::block, 3);

        Pen pen2(color(255, 192, 0, 0), 3);

        Pen penLine(Color(255, 192, 0, 0), 2);

        penLine.SetDashStyle(DashStyleDot);

          

        graphics.DrawRectangle(&pen, Rect(30, 30, 150, 100));    //좌표계 변환 전의 사각형

          

        Matrix transformMatrix;

        transformMatrix.Translate(100.0f, 100.0f);    //(0,0)을 (100, 100)으로 좌표 변환

        transformMatrix.Rotate(45.0f);            //45도 회전

        

graphic.SetTransform(&transformMatrix);    //변환 적용

graphics.DrawLine(&penLine, Point(-200, 0), Point(200, 0));    //좌표계 변환 후의 x축

graphics.DrawLine(&penLine, Point(0, -200), Point(0, 200));     //좌표계 변환 후의 y 축

graphics.DrawRectangle(&pen2, Rect(30, 30, 150, 100));    //좌표계 변환 후의 사각형

 

        [Graphics만으로 구현]

        Pen pen(Color::block, 3);

        Pen pen2(color(255, 192, 0, 0), 3);

        Pen penLine(Color(255, 192, 0, 0), 2);

        penLine.SetDashStyle(DashStyleDot);

        

        graphics.DrawRectangle(&pen, Rect(30, 30, 150, 100));    //좌표계 변환 전의 사각형

        

        graphics.TranslateTransform(100.0f, 100.0f);    //(0,0)을 (100, 100)으로 좌표 변환

        graphics.RotateTransform(45.0f);        //45도 회전

        

graphics.DrawLine(&penLine, Point(-200, 0), Point(200, 0));    //좌표계 변환 후의 x축

graphics.DrawLine(&penLine, Point(0, -200), Point(0, 200));     //좌표계 변환 후의 y 축

graphics.DrawRectangle(&pen2, Rect(30, 30, 150, 100));    //좌표계 변환 후의 사각형

 

 

 

 

'C++' 카테고리의 다른 글

파일 핸들링 API  (0) 2011.02.03
MFC tip  (0) 2011.01.25
OLEDB  (0) 2011.01.24
COM  (0) 2011.01.24
파일 비동기 IO 조작 (Async IO)  (0) 2011.01.18
SEH (Structured Exception Handling) 예외처리  (0) 2011.01.12
윈도우 GUI에서 콘솔(console) 띄우기  (0) 2011.01.11
Windows 접근 제어  (0) 2011.01.11