. 탭문자

텍스트 편집기는 순수한 텍스트만을 다루며 서식이 없다. 그래서 그냥 조사된 범위의 문자열을 TextOut으로 출력하기만 하면 그만이다. 그러나 예외가 있는데 그 예외가 바로 탭문자다. 탭은 문자열을 일정한 간격으로 배치하기 위한 일종의 제어코드며 다음과 같은 모양의 문서를 만들기 위해 사용한다.

여러 사람의 성적을 과목별로 일목 요연하게 정리했는데 똑똑한 김상형군 안타깝게도 사회에서 한 문제 틀린 모양이다. 이런 도표 모양의 문서를 만들기 위해서는 문자열간의 간격을 정확하게 띄워야 하는데 공백으로 대충 비슷하게 만들 수 있을 것 같지만 근본적으로 가변폭 폰트로는 정확할 수가 없다. 또한 설사 그럴듯하게 만들었다 하더라도 수정할 때마다 간격을 조정해 줘야 하기 때문에 여간 불편한 것이 아니다.

결국 이런 문서를 만들기 위해서는 탭문자가 반드시 필요하다. 또 탭은 소스 코드의 들여쓰기를 위해 많이 사용되며 소스의 가독성을 높이는데 결정적인 기여를 한다. 이 책을 읽는 사람은 코딩을 하는 사람들이니 탭문자의 중요성은 더 강조할 필요가 없을 것이며 그래서 좀 귀찮더라도 텍스트 편집기는 반드시 탭문자를 지원해야 한다.

탭은 문자코드로 표현되지만 그 폭이 정해져 있지 않다는 점이 가장 큰 문제다. 탭은 일정한 위치에 반복적으로 배치되며 다음 탭위치까지의 폭을 가진다. 탭문자의 폭은 나타난 위치에 따라 달라지며 미리 알 수 없기 때문에 실시간으로 계산해야 한다. 생각해보면 대단히 어려울 것 같지만 다행히 생각보다 어렵지 않으며 알고 나면 시시할 정도다. 간단한 수학식 하나면 깔끔하게 해결된다.

간단한 기능 추가이므로 별도의 프로젝트를 새로 만들지 말고 ApiEdit3프로젝트에 계속 작성해보도록 하자. 탭 지원에 필요한 두 개의 전역변수를 선언한다.

 

int TabWidth;

int TabSize;

 

TabWidth는 탭의 폭을 문자 단위로 지정하는 변수이고 TabSize는 탭의 픽셀 단위 폭을 가지는 변수이다. 왜 탭의 폭을 기억하는데 변수가 두 개나 필요한가 하면 탭의 크기는 다른 문자의 n배 폭으로 정의되며 실제 폭은 현재 선택된 글꼴의 평균폭에 n을 곱해서 구한다. n에 해당하는 값이 바로 TabWidth이며 실제로 적용할 픽셀 폭이 TabSize이다. 이 두 변수는 OnCreate에서 초기화된다.

 

BOOL OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)

{

     ....

    TabWidth=4;

    TabSize=FontWidth*TabWidth;

     UpdateScrollInfo();

 

     return TRUE;

}

 

TabWidth 4로 초기화했는데 보통 4 8을 많이 사용한다. TabSize는 문자의 평균폭에 이 값을 곱하면 구할 수 있다. 문자의 평균폭이 8이라면 탭은 32픽셀 단위로 배치될 것이다. 탭의 폭은 사용자의 취향에 따라 선택할 수 있도록 해야 하는데 편집기들은 옵션 대화상자를 통해 탭 폭을 지정할 수 있도록 한다. 이때 사용자가 지정하는 탭의 폭은 TabSize가 아니고 TabWidth이다. 사용자가 옵션 대화상자를 통해 TabWidth를 조정하면 프로그램은 이 값을 근거로 TabSize를 계산해 사용한다. , TabWidth는 사용자로부터 탭폭을 입력받기 위한 외부용 변수이고 TabSize는 문자열 정렬에 사용할 내부용 변수이다.

탭의 문자코드는 \t이며 단순한 문자이기 때문에 입력을 받기 위해 별도의 코드를 작성할 필요는 없다. OnChar에 이미 탭을 입력받는 코드가 작성되어 있으며 <Tab>키를 누르면 버퍼에 \t가 기록된다. 이렇게 입력받은 탭을 정렬루틴과 출력루틴에서 정확하게 간격을 띄워주기만 하면 된다.