.버그 수정

마지막으로 프로그램이 가진 약간의 버그를 수정해 보자. ApiDraw 도형을 이동, 크기 변경할 도형이 화면 안에 있는지, 잘못된 상태가 아닌지를 점검하여 도형이 갑자기 사라지지 않도록 한다. 이런 에러 처리에 의해 다른 에러가 발생할 있는데 직선의 경우 점을 드래그하여 수평, 수직선으로 바꾸어 버리면 , 높이가 0 되어 무효한 도형으로 잘못 점검된다. 그래서 직선을 그어 수평, 수직선을 만들 있지만 이미 존재하는 선을 수평, 수직선으로는 바꾸지 못한다.

또한 타원의 경우 선택의 정확도를 높이기 위해 리전 테스트를 했기 때문에 타원이 음수 영역으로 이동하여 타원 영역의 바깥쪽 일부만 보일 타원을 다시 선택할 방법이 없다. PtInRect 선택 점검을 때는 안보이는 일부라도 화면안에 걸치기만 하면 다시 꺼낼 있었지만 리전 테스트를 함으로써 타원 내부가 아닌 점은 타원으로 인정되지 않는 버그가 생긴 것이다.

버그가 발생한 이유는 도형의 이동과 크기 변경시의 유효성 점검 루틴이 정교하지 못하기 때문이다. 그래도 이전 버전에서는 버그가 목격되지 않았으나 그리드 기능에 의해 수평, 수직선을 만들기 쉬워졌고 리전 테스트로 인해 도형 선택이 정확해졌기 때문에 이제는 버그가 쉽게 재현될 있다. 객체의 유효성을 점검하는 방법이 객체의 타입에 따라 정교해질 필요가 있다. 객체의 유효성을 점검하는 다음 함수를 추가한다.

 

BOOL IsValidObject(HWND hCanvas,int Type, RECT *ort)

{

   RECT crt,irt;

   HRGN hRgn;

   BOOL bIn;

 

   GetClientRect(hCanvas,&crt);

   InflateRect(&crt,-10,-10);

   switch (Type) {

   case DT_LINE:

      if (ort->left == ort->right && ort->top == ort->bottom)

          return FALSE;

      return (PtInRect(&crt,*((POINT *)ort)) || PtInRect(&crt,*((POINT *)&ort->right)));

   case DT_ELLIPSE:

      if (IsRectEmpty(ort))

          return FALSE;

      hRgn=CreateEllipticRgn(ort->left, ort->top, ort->right,ort->bottom);

      bIn=RectInRegion(hRgn,&crt);

      DeleteObject(hRgn);

      return bIn;

   default:

      IntersectRect(&irt,&crt,ort);

      return (!IsRectEmpty(&irt));

   }

}

 

작업 영역 크기에서 10만큼 여유분을 영역을 생성했다. 직선인 경우는 점이 모두 같을 무효한 도형이며 하나라도 작업 영역 내에 있으면 유효한 도형으로 인정했다. 따라서 수평, 수직선도 유효한 상태가 되며 드래그해서 수평, 수직선을 만들 있다.

타원은 일단 영역이 비어 있지 않아야 하는데 , 높이 어느 것도 0 아니어야 눈에 보이는 객체이다. 조건을 만족할 경우 타원 리전을 만들고 리전이 작업 영역의 일부에라도 걸쳐 있는지 점검했다. 그외의 사각형 객체들은 작업 영역과 객체 영역의 일부라도 겹쳐 있으면 된다. ort 비어 있다면 교집합 영역이 있을 없으므로 ort 대해 IsRectEmpty 점검할 필요는 없다. 유효성을 점검할 필요가 있는 곳에서 함수를 호출한다. 다음 군데이다.

 

LRESULT OnLButtonUp(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

   ....

   if (DragMode==DM_MOVE || DragMode==DM_SIZE) {

      SwapResult=NormalizeRect(&dObj.rt);

      if (IsValidObject(hWnd,arObj[NowSel]->Type,&dObj.rt)) {

 

LRESULT OnKeyDown(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

   ....

   if (bAction) {

      if (IsValidObject(hWnd,arObj[NowSel]->Type,&drt)) {

          bModified=TRUE;

          arObj[NowSel]->rt=drt;

          InvalidateRect(hWnd,NULL,TRUE);

      }

   }

 

유효성을 점검하는 별도의 함수가 만들어졌으므로 함수에서 별도의 점검을 필요는 없어졌으며 함수의 지역 변수 crt, irt 이제 불필요하다. 마지막으로 릴리즈 후에 발견된 버그 하나를 수정하도록 하자. 마우스로 이동이나 크기 변경을 하는 중에 오른쪽 마우스 버튼을 눌러 팝업 메뉴를 열거나 키보드로 이동해도 코드가 동작하는데 드래그 중에는 팝업 메뉴를 열거나 키보드 조작을 못하도록 해야 한다. 다음 코드를 추가하도록 하자.

 

LRESULT OnKeyDown(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

   BOOL bShift, bControl;

   int dx,dy;

   RECT drt;

   BOOL bAction=TRUE;

 

   if (DragMode != DM_NONE) {

      return 0;

   }

   ....

 

LRESULT OnContextMenu(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

   HMENU hMenu, hPopup;

   int TempSel;

   POINT pt;

 

   if (DragMode != DM_NONE) {

      return 0;

   }

   ....

 

드래그 중일 때는 키보드 입력이나 팝업 메뉴 출력을 거부하도록 했다. 이를 막지 않으면 이동중에 선택이 바뀌어 버리므로 프로그램이 다운될 수도 있다. 이런 버그는 미리 예측하기는 어렵지만 일단 존재 사실만 알면 수정하기는 아주 쉽다. 이외에 아직 찾지 못한 버그가 28 있는데 이건 다음에 발견되는대로 수정하기로 한다.