본문 바로가기
컴퓨터/MFC_API

CScrollView의 OnDraw의 좌표

by adnoctum 2011. 7. 30.

   CScrollView를 상속받은 뷰를 갖고 코딩을 하는데, 아래와 같이 그림의 표현이 잘못 되고 있다.



위에서 표시한 바와 같이, 원래의 그림이 뿌려진 다음, 위쪽에 살짝 잘못된 그림 영역이 뿌려지고 있다. 현재, 화면의 확대/축소 기능을 구현하다 문제가 발생한 것인데, 조금 더 자세히 설명하면 이렇다. 원래 그려야 할 그림을 필요한 만큼 확대를 한 후, 그 크기만큼 스크롤 영역을 설정해 준다(CScrollView::SetScrollSizes). 그 후, 실제 화면의 크기(눈에 보이는 크기, CWnd::GetClientRect로 얻는 것)와 동일한 크기를 갖는 CBitmap instance 를 만들어서 확대된 이미지에서 화면으로 나타낼 영역을 bitmap에 BitBlt 시켜서 복사하고, 그것을 다시 화면에 표시한다. 그림으로 보자면 다음과 같다.


위처럼 모니터(엄밀히 말하면 application의 window)에 나타날 부분만 따내서 화면에 표시를 하는 것이다. 이 경우, 그런데 지금 나의 경우는 Shift를 누른 상태에서 마우스 휠을 돌리면 확대/축소를 하고, 따라서 현재의 화면 크기보다 그림이 커질 경우 SetScrollSizes에 의해 ScrollBar가 생기고, 확대/축소 전/후에 전체 그림에서 위치했던 마우스 포인터를 유지하기 위해 적절히 ScrollBar를 움직이게 된다. 그런데, 스크롤 바를 제일 아래로 둔 후 스크롤 영역을 감소시킨 후 그림을 그리면 제일 위의 그림처럼 위쪽 부분에 알 수 없는 그림이 그려진다. 뭔가 해서 찾다 보니 이 그림은 현재 화면에 나타날 그림을 갖고 있는 bitmap의 제일 아래쪽 부분이었다. 디버깅을 위해서 화면을 클릭하면 이 bitmap을 0,0 위치에 BitBlt 시켰더니 다음과 같다.



그런데 난 OnDraw에 이런 루틴, 즉 다음과 같이 작성해 놓았었다.


즉, 화면에 표시할 그림을 갖고 있는 bitmap을 0,0 위치에 BitBlt 시켜 놓았던 것. 그런데, 스크롤 바를 움직이게 하기 때문에 계속 WM_PAINT 메세지가 호출이 되었던 것이다. Spy++로 보면 다음과 같다.


위처럼 Shift 키가 눌린 상태에서 WM_MOUSEWHELL이 발생한 이후 WM_PAINT가 호출이 되었다. 따라서 이것 때문에 OnDraw가 호출이 되고, 이 곳에서 0,0 위치로 BitBlt 를 시키게 되는데, 문제는 이 때 그려진 그림이 현재 화면에 나타나야 할 부분이 아니었다는 것이다.

   문제를 해결할 수 있었던 단서는, 그려진 영역이, 화면에 표시될 Bitmap의 아래쪽 부분이었다는 점. 그리고 이런 일은 Scroll Bar가 가장 아래쪽에 내려가 있을 때만 발생했다는 점. 그래서 든 생각은, 아마도 OnDraw에서 그려질 때 사용되는 좌표계는 스크롤 영역의 논리 좌표계를 따를 것이란 생각이 들었다. 즉, 실제 화면이 1,000 x 1,000 크기였고, SetScrollSizes로 2,000 x 2,000 만큼 크기를 잡아 놓았다면 BitBlt를 시킬 때 사용하는 목적 좌표계는 2,000 x 2,000 이라는 것이다. 따라서 위의 경우, 화면에 표시되는 영역이, 0,0 이긴 하지만 실제로 스크롤이 된 상태이기 때문에 현재 스크롤 된 가장 왼쪽/위쪽 점에 BitBlt를 시켜야 했던 것이다. 위 OnDraw 코드에서 주석으로 처리해 놓은 바로 그 부분처럼. 그러면 정상적으로 된다.



어쨌든 문제는 해결이 되었는데, 그래도 살짝 의문은 생긴다. 그렇다면 왜 위쪽의 잘못된 부분과 아래쪽의 정상적인 부분이 '둘 다' 그려졌던 것일까? 이 것은 아직 잘 모르겠다. 어쩌면 위와 같이 이해한 것이 틀린 것일 수도 있다. 아니면, Spy++ 결과에서 보면 WM_ERASEBKGND 메세지가 호출이 되는데, 이 메세지에 의해 지워진 영역이 문제가 되는 것일지도 모르겠다. 뭐, 귀찮아서 확인해 보진 않았다.





아, 놔, 이것 때문에 열 좀 받았다. 변수가 잘못되는 것이면 디버깅하면서 값을 죄다 확인할 수 있기 때문에 그나마 쉬운데, 이놈의 그림은 안의 내용을 간단히 확인하기가 좀 번거로워서 디버깅 할 때면 열 좀 받는다. 종종 png 파일로 만들어서 확인하기도 하고. 여하튼, 이것 때문에, 디버깅 하다가 처음으로, 컴퓨터 안으로 들어가서 값들을 죄다 확인해 보고 싶다는 충동이 일었다. 으, 역시 코딩은 스트레스를 많이 받게 한다니까.