본문 바로가기
[ Program ]/CC++MFCAPI

깜빡임이 없어지지않네요

by 관이119 2012. 9. 14.
출처 iperfume님의 블로그 | 루시아
원문 http://blog.naver.com/iperfume/100032793209

 

[MFC] CList로 비트맵 띄우는데 드래그 할 때 깜빡임이 없어지지않네요

이미지를 몇개 출력해서 리스트에 저장한다음 뿌려주는 프로그램을 짜고 있습니다.
거의 다 완성 되었는데

OnLButtonDown()
OnMouseMove()에서 OnLButtonUp()으로

그림을 선택해서 드래그 하는 프로그램인데요.

드래그 될때 마니 깜박거리네요.

Invalidate, InvalidateRect, OnEraseBkfnd()도 써보고
아예 배경을 다시 그리기도 해봤지만

왜 안되는건지 궁금합니다.

아래는 이미지를 그리는 부분과
마우스 커서 움직이는 부분입니다.

깜박거리는 것 말고는 잘 동작하고 있습니다.



BOOL CTestGDIView::DrawImage(int x,int y,int z,int w,UINT nFileName, CDC* pDC)
{
CDC memDC;
CBitmap myBit, *pOldBit;
BITMAP bm;

myBit.LoadBitmap(nFileName);
myBit.GetObject(sizeof(BITMAP), &bm);
memDC.CreateCompatibleDC(pDC);
pOldBit = memDC.SelectObject(&myBit);

CRect rc;
GetClientRect(rc);

pDC->BitBlt(x, y, z, w, &memDC, 0, 0, SRCCOPY);
memDC.SelectObject(pOldBit); //반환

return 0;
}

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

void CTestGDIView::OnMouseMove(UINT nFlags, CPoint point) //마우스 커서를 움직일 때
{
// TODO: Add your message handler code here and/or call default

/////////////////// 상태바에 커서 위치 출력 /////////////////

CString str;
str.Format("X:%d, Y:%d",point.x,point.y);

((CMainFrame *)AfxGetMainWnd())->GetStatusBar()->SetWindowText(str);

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

if(m_bMouseDown)
{ //마우스를 누른 상태(그림이 클릭되었을 때에만 해당)
CTestGDIDoc* pDoc = GetDocument();

POSITION pos1, pos2;

for(pos1 = pDoc->m_pList.GetHeadPosition(); (pos2 = pos1) != NULL;)
{
CObjectInfo info = pDoc->m_pList.GetNext(pos1);
if(m_nCurrentType == info.m_nKind)
{ //같은 종류의 그림을 리스트에서 찾아서
info.m_nx += point.x - m_nOriginalPointX;//마우스 좌표에따라 이동
info.m_ny += point.y - m_nOriginalPointY;

m_nOriginalPointX = point.x; //이전 좌표 계속 업데이트
m_nOriginalPointY = point.y;

pDoc->m_pList.SetAt(pos2, info); //리스트에 값들 저장

Invalidate(TRUE);
//InvalidateRect(m_rect, TRUE);
return;
}
}
}


CView::OnMouseMove(nFlags, point);
}
추가된 질문 (2006-08-11 13:51 추가)

GetClipRect는 MSDN에서 찾아도 없는데 혹시 GetClipRgn아닌가요?

 

답변

화면 깜박거림을 처리하는 몇 가지 방법

마우스를 움직임에 따라서 그림을 다시 그릴 때

Invalidate함수를 호출하는 것을 부적절할 수 있습니다.

왜냐하면 Invalidate는 전체 화면을 다시 그리기 때문입니다.

최소한으로 화면을 갱신하기 위해서는 이전에 그림이 있던 곳을 지우고

그림이 새로 움직인 위치에 그림을 표시해주면 됩니다.

이러한 처리를 하기에 적절한 곳은 OnMouseMove함수입니다.

왜냐하면 OnDraw함수에서는 그림을 움직임으로써 어느 부분을 새로 그려야 하는지

알 수가 없기 때문입니다.

물론 OnDraw함수에서 GetClipRect라는 함수를 사용하여 다시그리게 될 영역을

한정해 줄 수는 있습니다. 이렇게 하기 위해서는

InvalidateRect함수를 사용해서 무효화영역을 설정해 주어야 합니다.

위 내용을 다음과 같이 3가지로 정리할 수 있습니다.

1) OnDraw함수에서 모든 영역을 그리는 방법 : 간단하나 필요없는 부분도 다시 그리게

되므로 비효율적일 수 있다.

2) MouseMove함수에서 InvalidateRect함수로 무효화영역을 설정한 후에

OnDraw함수에서 GetClipRect로 무효화 영역을 얻어서 이 부분에 대해서만

다시 그리기를 해주는 방법

3) MouseMove에서 Invalidate나 InvalidateRect함수를 전혀 사용하지 않고

직접 화면에 그려주는 방법. 물론 그림의 위치에 관한 정보가 갱신되어야 하고

프로그램이 최소화되었다가 복구될 때 전체 화면이 그려지게 되면 이것은

OnDraw함수에서 처리하게 됨.

위 내용 중에 1번을 사용하여 프로그램을 하나 짜 보았습니다.

간단하기 때문에 선택하였는데, 그림의 깜박거림은 거의 관찰되지 않았습니다.

2번이나 3번을 구현하게 되면 일반 상용프로그램과 같은 수준의 구현이

될 수 있을 것입니다.

이동중에 그림이 깜박 거리는 것은 위 3가지 방법들과는 별개로 double buffering과

OnEraseBkgnd함수에서 return FALSE를 사용하지 않았기 때문으로 보입니다.

위과 같이 화면 깜박임을 최소로 한 경우에도 위와 같은 소프트웨어적인 방법을

사용하여 화면 전체를 검은색과 흰색으로 교대로 표시하게 될 경우에 화면의 깜박거림을

볼 수 있는데, 이는 하드웨어(모니터, 그래픽카드, 메인보드, CPU, 칩셋 등)에 의한 영향일

것입니다.

메일 주소를 쪽지로 보내주시면 프로그램을 보내드리겠습니다.

- 추가답변

GetClipBox가 맞습니다. GetClipRgn함수도 있는데 이것은 GetClipBox보다

사용하기가 조금 어려울 것 같습니다.

http://www.codeproject.com/gdi/flickerfree.asp

위 사이트에 CDC클래스를 이용하여 Back Buffer를 CBitmap으로 구현한

좋은 클래스가 소개되어 있습니다. 참고하시기 바랍니다.

OnEraseBkgnd함수를 사용하고 안에서 return FALSE; 라고 작성했다면,

배경을 그리는 것은 OnDraw함수에서 해주어야 합니다.

그렇게 되어 있는지도 확인해보시기 바랍니다.

댓글