CRichEditCtrl 을 MFC 내에서 사용할 때 몇 가지 고려사항에 대해 살펴 보자. (개인적으로 나중에 다시 MSDN 찾지 않기 위해 작성, ㅋ)
1. control을 손수 넣어 사용할 때 application 차원에서 호출해야 하는 함수 : AfxInitRichEdit();
2. focus 를 가질 때 전체 선택이 되는 문제.
3. LineIndex 와 LineLength
4. vertical scroll bar 가 보이지 않는 문제.
1. control을 손수 넣어 사용할 때 application 차원에서 호출해야 하는 함수 : AfxInitRichEdit();
View를 CRichEditView를 상속받아 사용할 때는 default code 를 실행시켜도 아무 문제 없이 rich edit control의 기능을 사용할 수 있음에도 불구하고 dialog-based app.이나 코드로 CRichEditCtrl 을 집어 넣으려고 할 때, debug mode에서 실행시킬 때 memory leak 이 생기면서 프로그램이 곧바로 중단된다. 이 문제는, rich edit control의 기능을 사용하기 위해서는 AfxInitRichEdit() 를 호출해주면 해결할 수 있다. 즉, rich edit 의 여러 기능을 사용하기 위한 초기화라고 볼 수 있다.
2. focus 를 가질 때 전체 선택이 되는 문제.
수정. focus 를 가질 때 전체 내용이 선택되는 것은 Rich edit control의 option 중 ECO_SAVESEL 이 설정되어 있기 때문이다. 따라서 이 설정을 없애 주면 이렇게 작동하지 않는다. 즉, rich edit control이 focus 를 가질 때 전체 내용이 선택되지 않게 하기 위해서는 다음과 같이 한다.
_recSourceText.SetOptions(ECOOP_XOR,ECO_SAVESEL);
위에서 [_recSourceText] 는 CRichEditCtrl 형 변수이다.
왜 이런 문제가 발생하는지는 잘 모르겠다. 하여튼, control 내에 내용이 있을 때 focus 를 받으면 전체 선택이 되어 버리는 경우가 있다. 이럴 경우, 내 경우, 전체 선택이 되기 전에 이벤트를 잡아 채는 방법은 잘 찾지를 못해서, 우선 전체 선택이 된 후 다시 선택을 없애는 방법을 택했다. Spy++ 로 알아 보니 전체 선택이 되기 직전에 EN_SELCHANGE message 가 발생했다. 그래서 이 message handler 에서 특정 위치만을 다시 선택하도록 했다. EN_SELCHANGE message 는 control 내의 선택 영역이 변경될 때 발생하는데, rich edit control이 이 메세지를 부모 window에게 전달할 수 있게 하기 위해서는 rich edit control의 event mask 를 설정해 주어야 한다. 다음과 같다.
일반적인 경우라면 위 정도만으로도 충분할 것이다. MSDN에는 약간 복잡하게 되어 있는데, 간단히 말하자면, 위처럼 설정해 준 event 만 부모 window 로 날라 간다는 말. 그 후 EN_SELCHANGE message handler 에서 다음과 같이 작업해 준다.
즉, 현재 EN_SELCHANGE를 보낸 control의 id (pSelChange->nmhdr.idFrom) 를 확인해서 내가 처리하고 싶은 control 에서 발생한 경우에만 처리를 한다. rich edit control의 경우, 전체 선택이 되었는지를 알아 내는 함수가 없기 때문에, 나의 경우 위처럼 했다. 즉, 시작된 영역이 0 부터 '특정값'보다 클 때 전체선택이 되었다고 간주했다. 이 때, '특정값'이란 rich edit control의 가장 마지막 줄 시작 위치까지이다. 이 영역보다 더 많은 영역이 선택되었다면 선택된 영역을 없애 버린다. 이 부분이 위 코드에서 SetSel 을 하는 부분이고, 여기에 같은 값을 넣어 주면(위의 경우 _current_sel_line_number_start 값으로 이 값은 member variable이다) 선택 영역이 없어 지고 이 위치 바로 뒤에 caret 이 놓여 진다(고 MSDN 에 씌여 있는데 caret 은 으째 안보여...)
3. LineIndex 와 LineLength.
LineIndex 는 parameter N 으로 호출이 되었을 때 N+1 번째 line 의 시작 글자의 위치를 반환한다. 이 때 '위치'란 rich edit control 내용 중 그 글자가 가장 처음부터 몇 번째 글자인가에 해당하는 index 이다. LineLength 는 parameter N 으로 주어지는 N+1 번째 글자가 속해 있는 줄(line)의 길이를 반환해 준다. LineLength 의 경우 N+1 번째 줄의 길이, 로 착각하기 쉬운데, 그것이 아니라 N+1번째 글자가 속한 줄의 길이이다. 약간 혼란스럽다. MSDN의 설명에는 정확히 이렇게 나와 있다.
Specifies the character index of a character in the line whose length is to be retrieved. - MSDN
4. vertical scroll bar 가 보이지 않는 문제.
이것 역시 원인을 알 수 없지만, vertical scroll bar 가 보여야 할 때 보이지 않는 경우도 있다. 즉, WS_VSCROLL 이나 ES_VSCROLL, ES_AUTOVSCROLL 을 설정해 주었고 control 안의 내용이 control 안에서 한 번에 보이는 내용보다 많아서 vertical scroll bar 가 나타나야 하는 상황에도 나타나지 않는 경우도 있다. 지금 디버깅 중 엔터를 지속적으로 입력해서 scroll bar 가 나와야 할 상황에 나오지 않다가, 전체 선택을 해서 전부 지운 후 다시 똑같은 작업을 하면 scroll bar 가 나타나는 것을 경험했다. 두 경우 rich edit control 이 받는 메세지를 spy++ 로 확인해 보면 다음과 같다.
scroll bar가 나타났을 때의 메세지
scroll bar가 나타나지 않았을 때의 메세지
두 경우에 있어, 회색으로 선택된 부분부터 메세지가 차이가 나기 시작한다. 왜 이런 현상이 발생했는지를 잘 모르겠고, 여하튼, 이런 문제를 해결하기 위해서는 ShowScrollBar로 강제로 scroll bar 를 보여주거나, Disable No Scroll 속성을 true; 로 주어 항상 scroll bar 가 보이도록 한다.