얼마전에 Q&A에 TMemo의 CaretPos가 이상하게 나온다고 해서 ..해보다가...
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_qna&no=52783
VCL의 TMemo는 64KByte까지 만 제대로 Edit할수있습니다.
왜냐하면 win32의 EDIT를 슈퍼클래싱해놓은 컴포넌트이기 때문입니다.
그래서 내용이 64KByte넘게 들어가서 SelStart가 65535를 넘어간경우 CaretPos가 제대로된값이 나오지 않습니다.
그래서 가능하면 64KByte넘어갈때는 TMemo를 쓰지 않도록 하는것이 좋습니다.
하지만 외부 컴포넌트를 쓰지 않으면 마땅한 대안이 없어 TMemo를 써야하고
CaretPos를 써야한다면?
아래 함수를 이용하면 적당한 CaretPos를 구할수 있을 것입니다.
기냥 SelStart까지 각 Line의 Length를 구해서 ... 계산해서.. CaretPos를 구하는거죠..
TPoint __fastcall GetMemoCaretPos(TMemo *Memo)
{
TPoint oPt=Memo->CaretPos;
if(oPt.x>=0)return oPt;
TPoint pt=Point(0,0);
int iSelStart=Memo->SelStart;
int iLen=0;
iSelStart=iSelStart+Memo->SelLength;
bool bFind=false;
for(int i=0;iLines->Count;i++)
{
iLen+=Memo->Lines->Strings[i].Length();
if(iLen>=iSelStart)
{
pt.y=i;
pt.x=iSelStart-iLen+Memo->Lines->Strings[i].Length();
bFind=true;
break;
}
iLen+=2;
}
if(!bFind)
{
pt.x=0;
pt.y=Memo->Lines->Count;
}
return pt;
}
그런데 위 함수에 문제가 있습니다.
TMemo 의 WordWrap=false인경우 또는 WordWrap=true이더라고 가로 ScrollBar가 있는 경우에는 문제없지만
WordWrap=true되어 자동줄바꿈이 되면 문제가 있습니다.
그런데 오늘 TMemo에서 현재 위치의 LineNumber를 알아오는 방법과
그 Line의 Index를 알아오는 message를 알았습니다.
뭐 간단합니다.
int LineNumber = SendMessage(Memo1->Handle,EM_LINEFROMCHAR,Memo1->SelStart,0);
또는
int LineNumber = Memo1->Perform(EM_LINEFROMCHAR,Memo1->SelStart,0);
그 다음 그 라인에서 현재 위치의 Index는?
int index=Memo1->Perform(EM_LINEINDEX, LineNumber , 0);
결론적으로 위 두가지를 이용해서 CaretPos를 구할수 있겠죠..
TPoint __fastcall GetMemoCaretPos(TMemo *Memo)
{
if(Memo==NULL)return Point(0,0);
TPoint pt;
pt.y = Memo->Perform(EM_LINEFROMCHAR, Memo->SelStart, 0);
pt.x = Memo->SelStart - Memo->Perform(EM_LINEINDEX, pt.y, 0);
return pt;
}
위 함수는 Memo가 WordWrap=true 인경우.. 그리고 SelStart가 65535를 넘어가는 경우에도 제대로 나옵니다.
그럼..
WordWrap = true 이면서 HScrollBar 가 있는 경우는 어떤 경우인가요? (상상이 안가서;;)