//트리컨트럴이 그려질 부모 윈도우 즉 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;