//트리컨트럴이 그려질 부모 윈도우 즉 view클래스 헤더 파일에


//뷰클래스 안에다

CTreeCtrl m_treeCtrl; //변수를 선언하고


public:

    afx_msg void OnTvnItemexpandedTree1(NMHDR *pNMHDR, LRESULT *pResult);//요거는 트리가 접히거나 펴질때 발생합니다.




//view 클래스 cpp파일의 클래스 밖에 맨 윗부분이나 맨 아래 요렇게 콜백함수(시스템이 호출하는함수)를 만듭니다.


WNDPROC g_wndProc;

bool SetBkImage(HDC hdc,const TCHAR *szImage,CRect rect,int iMode);//이미지를 그려주는 전역함수

bool LoadGraphicFile(LPCWSTR szFileName,HBITMAP &hBmp,BITMAP *bmp);//그래픽(bmp,jpg,gif,png)파일 로드전역 함수


LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{  

    switch(iMsg)

    {

    case WM_ERASEBKGND://배경을 다시그릴때 호출됩니다.

        {

        CRect rc;

        GetClientRect(hwnd,&rc);

        //배경그림을 설정하는 함수 호출(전역함수)

        if(SetBkImage((HDC)wParam,_T("love1.gif"),rc,1)) return 1;//요 함수는 클래스 밖에 있는 함수입니다. 따라서 맨 밑에

       //view 클래스 밖에다가 만듭니다.

        }

    case WM_VSCROLL | WM_HSCROLL://스크럴 바를 움직일때 호출됩니다.

        {

        CRect rc;

        GetClientRect(hwnd,&rc);//윈도우중 사용자영역의 사각좌표를 얻는다.

        if(LOWORD(wParam)==SB_THUMBTRACK)//스크럴 바를 끌고 있을때

            ::InvalidateRect(hwnd,rc,1);//배경을 지우고 다시 그린다.

        break;

        }

    }

    return CallWindowProc (g_wndProc, hwnd, iMsg, wParam, lParam) ;

}



//그리고 view 클래스 안쪽에다가  요렇게 트리컨트럴을 대화상자의 트리컨트럴ID와 연결합니다.

void CexamView::DoDataExchange(CDataExchange* pDX)

{

                    CFormView::DoDataExchange(pDX);

DDX_Control(pDX, IDC_TREE1, m_treeCtrl);

}


//다음  view 만든후 처음 호출되는 대화상자의 모든 컨트럴을 로드한 후 호출되는 메시지에

//요렇게 m_treeCtrl의 핸들을 이용하여 컨트럴 자체의 메시지를 가로챕니다.


void CexamView::OnInitialUpdate()

{

    CFormView::OnInitialUpdate();


g_wndProc=(WNDPROC)SetWindowLong(m_treeCtrl.m_hWnd,GWL_WNDPROC,(LONG)WndProc);

//g_wndProc는 전역 WNDPROC이어야 합니다. 요새는 SetWindowLongPtr이거를 사용하라고 마소에서 권고합니다.^^


}


//그리고 트리컨트럴이 부모윈도우(view)에 보내는 메시지중 TVN_ITEMEXPANDING 이거를 받습니다.

//트리노드가 펼치거나 접혀질때 발생합니다.

//요렇게 그때마다 트리컨트럴을 다시 그립니다.


void CexamView::OnTvnItemexpandedTree1(NMHDR *pNMHDR, LRESULT *pResult)

{

    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);

    // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.

    CRect rc;

    m_treeCtrl.GetClientRect(&rc);

    m_treeCtrl.Invalidate();

    *pResult = 0;

}


//마지막으로 배경을 그려주는 전역 함수를 맨 밑에다 클래스 밖에 만들어 줍니다.


bool SetBkImage(HDC hdc,const TCHAR *szImage,CRect rect,int iMode)

{

    HDC memDC;

    HBITMAP hbmp=NULL,hbmpPrev;

    BITMAP bmp;

    bool bReturn=true;//반환 값

   

    //그래픽파일 로드

    if(!LoadGraphicFile(szImage,hbmp,&bmp)) return false;


    //메모리 DC 만듬    

    memDC=CreateCompatibleDC(hdc);

    //로드된 비트맵을 DC에 선택

    hbmpPrev=(HBITMAP)SelectObject(memDC,hbmp);

    //배경채우기 선택

    if(iMode==0)//늘이기

    {

        SetStretchBltMode(hdc,COLORONCOLOR);

        StretchBlt(hdc,0,0,rect.Width(),rect.Height(),memDC,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);

    }

    else if(iMode==1)//바둑판식

    {

              //바둑판식 효과

         for (int y=0; y < rect.Height(); y += bmp.bmHeight)

         { // for each row:

             for (int x=0; x < rect.Width(); x += bmp.bmWidth)

             { // for each column:

               BitBlt(hdc,x, y,bmp.bmWidth ,bmp.bmHeight ,memDC, 0, 0, SRCCOPY); // copy

               

             }

          }

    }

    else if(iMode==2)//가운데

    {

        LOGBRUSH lb;//브러쉬 구조체

        HBRUSH hbrush,hbrushPrev;//브러쉬 핸들

        //브러쉬 스타일과 색상

        lb.lbStyle=BS_SOLID   ;lb.lbColor=GetBkColor(hdc);

        //브러쉬를 만든다.

        hbrush=CreateBrushIndirect(&lb);

        //DC에 브러쉬를 선택

        hbrushPrev=(HBRUSH)SelectObject(hdc,hbrush);

        Rectangle(hdc,0,0,rect.right,rect.bottom);//사각형을 그린다.

        SelectObject(hdc,hbrushPrev);//브러쉬 환원

        DeleteObject(hbrush);//브러쉬 삭제

        //메모리 DC에 있는 그림을 목적 DC로 전송

        //좌표를 계산한다

        //그림의 넓이가 DC의 넓이 보다 크면 X좌표는 0 그렇지 않으면

        //DC의 넓이를 반으로 나눈 값에서 그림의 넓이를 반으로 나눈 값을 뺀다.

        //Y좌표도 마찬가지 방법으로 계산한다.

        rect.Width()/2>=bmp.bmWidth?rect.left=rect.Width()/2-bmp.bmWidth/2:rect.left=0;

        rect.Height()/2>=bmp.bmHeight?rect.top=rect.Height()/2-bmp.bmHeight/2:rect.top=0;

        BitBlt(hdc,rect.left,rect.top,rect.Width(),rect.Height(),memDC,0,0,SRCCOPY);


    }

    else //모드 에라;;

    {   AfxMessageBox(_T("인식할수 없는 Fill Mode 입니다."));bReturn=false;}

   

    SelectObject(memDC,hbmpPrev);DeleteObject(hbmp);

    DeleteDC(memDC);

    return bReturn;

}


bool LoadGraphicFile(LPCWSTR szFileName,HBITMAP &hBmp,BITMAP *bmp)

{

     HRESULT hr;

     HANDLE hFile = CreateFileW(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

    if(INVALID_HANDLE_VALUE == hFile)

    {

        AfxMessageBox(_T("Graphic File Open Error"));

        return false;

    }

    // 파일의 사이즈를 얻는다.

    DWORD dwFileSize = GetFileSize(hFile, NULL);

    if(-1 == dwFileSize)

    {

        AfxMessageBox(_T("Graphic File Read Error"));

        return false;

    }

       

    LPVOID pvData = NULL;

    // 파일의 크기만큼 동적할당(alloc memory based on file size)

    HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE,dwFileSize);

    if(NULL == hGlobal) return false;

    pvData = GlobalLock(hGlobal);

    if(NULL == pvData) return false;

    DWORD dwBytesRead = 0;

    // 파일을 읽고 할당된 전역공간에 저장(read file and store in global memory)

    BOOL bRead = ReadFile(hFile, pvData, dwFileSize, &dwBytesRead, NULL);

    if(FALSE == bRead) return false;

    GlobalUnlock(hGlobal);

    CloseHandle(hFile);

    LPSTREAM pstm = NULL;

    // create IStream* from global memory

    hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pstm);

    if(S_OK != hr || pstm == NULL) return false;

     // Create IPicture from image file


    LPPICTURE pPicture;

    hr = ::OleLoadPicture(pstm,dwFileSize, FALSE, IID_IPicture, (LPVOID *)&pPicture);

    if(S_OK != hr || pPicture == NULL)

    {

        AfxMessageBox(_T("Graphic File Load Error"));

        return false;

    }

    pstm->Release();

    GlobalFree(hGlobal);

    OLE_HANDLE picHandle;

    pPicture->get_Handle(&picHandle);


    hBmp=(HBITMAP)picHandle;

    if(NULL!=bmp)

        GetObject(hBmp,sizeof(BITMAP),bmp);

    return true;


Posted by 명혀니
,