RAD 2010 VCL 라이브러리 소스를 보면
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
Handled: Boolean;
Unicode: Boolean;
MsgExists: Boolean;
begin
Result := False;
MsgExists := PeekMessage(Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
if MsgExists or PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
begin
Unicode := (Msg.hwnd = 0) or IsWindowUnicode(Msg.hwnd);
if not MsgExists then
begin
if Unicode then
MsgExists := PeekMessageW(Msg, 0, 0, 0, PM_REMOVE)
else
MsgExists := PeekMessageA(Msg, 0, 0, 0, PM_REMOVE);
end;
if MsgExists then
begin
Result := True;
if Msg.Message <> WM_QUIT then
begin
Handled := False;
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
if not IsPreProcessMessage(Msg) and not IsHintMsg(Msg) and
not Handled and not IsMDIMsg(Msg) and
not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
begin
TranslateMessage(Msg);
if Unicode then
DispatchMessageW(Msg)
else
DispatchMessageA(Msg);
end;
end
else
begin
{$IF DEFINED(CLR)}
if Assigned(FOnShutDown) then FOnShutDown(self);
DoneApplication;
{$IFEND}
FTerminate := True;
end;
end;
end;
end;
위와 같이 되어있는데,
IME 와 Edit Control은 서로 별개의 윈도우 이기 때문에, Edit 콘트롤이 Focus Out 되는 것을 IME 윈도우 쪽에서는
알수 없어서, IME Completion 과정에서 발생하는 메세지 셋이 라우팅 될수 있도록 Message Dispatch 루틴을
만들 때 그런 부분을 고려했어야 하는데
VCL 라이브러리 소스를 보면 마우스 이벤트에 대해 선행처리 한답시고 닭짓을 하고 있기 때문에 문제가 발생하는 것임.
if MsgExists then
윗부분의 코드를 걷어내고 다음과 같이 작성했더라면 전혀 질문에 언급된 문제가 발생하지 않았을 것임.
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
Handled: Boolean;
Unicode: Boolean;
MsgExists: Boolean;
begin
Result := False;
if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
begin
Unicode := (Msg.hwnd = 0) or IsWindowUnicode(Msg.hwnd);
if Unicode then
MsgExists := PeekMessageW(Msg, 0, 0, 0, PM_REMOVE)
else
MsgExists := PeekMessageA(Msg, 0, 0, 0, PM_REMOVE);
if MsgExists then
begin
Result := True;
if Msg.Message <> WM_QUIT then
begin
Handled := False;
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
if not IsPreProcessMessage(Msg) and not IsHintMsg(Msg) and
not Handled and not IsMDIMsg(Msg) and
not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
begin
TranslateMessage(Msg);
if Unicode then
DispatchMessageW(Msg)
else
DispatchMessageA(Msg);
end;
end
else
begin
// 이하 생략
VCL 라이브러리 소스코드를 수정해서 사용하는 게 불편 하면
void __fastcall TForm1::Edit1Exit(TObject *Sender)
{
Application->ProcessMessages();
}
위와 같이 작성하면 됨.
: 장성호 님이 쓰신 글 :
: : Edit에 입력중에
: : 코딩으로 강제로 Focus를 옮기며, 곧바로 입력중이던 Edit의 값을 읽어오면
: : 그런현상이 발생합니다.
: :
: :
[문제 원인]
: : Edit1에 입력중인데..
: :
: :
: : Edit2->SetFocus();
: : String str=Edit1->Text;
: : // 이때 str에 내용은 아직 완성이 안된 문자열이 될수 있습니다
: :
: :
: : Edit1입력중에 다른 Control로 Focus를 강제로 옮기면
: : Edit1에 Char완성메세지(WM_CHAR) 와 화면갱신메세지(WM_PAINT)가 발생하게 되는데..
: : 님께서 Edit1의 Text를 읽어온것은 해당 메세지가 Edit1의 WindowProc에서 처리하기 전에 가져온것입니다.
: :
: :
: :
[해결방안]
: : 다음과 같이
: : Edit1의 Text를 읽기전 Edit1에서 처리해야할 메세지를 처리하고 Text를 읽으시면 됩니다.
: : VCL함수중에 Application->ProcessMessages(); 메소드가
: : 현재 어플리케이션 GUI 쓰레드의 메세지큐에 있는 메세지를 가져와서 처리해주는 함수 입니다.
: :
: :
: : void __fastcall TForm8::Timer1Timer(TObject *Sender)
: : {
: : Edit2->SetFocus();
: : Application->ProcessMessages(); //Edit1의 TEXT를 읽지전 Edit1에 발생되는 메세지를 처리
: : String str=Edit1->Text;
: : Edit2->Text=str;
: : }
: :
: :
: :
: : 다른 방법
: : 원리는 같은데요
: : Application->ProcessMessages(); 메소드는
: : Edit1뿐만 아니라 모든 어플에서 발생하는 메세지가 처리됩니다.
: : Edit1에 해상되는 메세지만 처리하고 싶다면 다음과 같이 해보세요
: :
: :
: : void __fastcall MessageProcess(TWinControl *pCtrl)
: : {
: : TMsg Msg;
: : bool MsgExists = PeekMessageW(&Msg, pCtrl->Handle, 0, 0, PM_REMOVE);
: : while(MsgExists)
: : {
: : TranslateMessage(&Msg);
: : DispatchMessageW(&Msg);
: : MsgExists = PeekMessageW(&Msg, pCtrl->Handle, 0, 0, PM_REMOVE);
: : }
: : }
: : //--------------------------------------------------------------------------
: : void __fastcall TForm8::Timer1Timer(TObject *Sender)
: : {
: : Timer1->Enabled=false;
: : Edit2->SetFocus();
: : MessageProcess(Edit1); //Edit1에 발생하는 WM_CHAR메세지 처리
: : String str=Edit1->Text;
: : Edit2->Text=str;
: : }
: :
: :
: : 두번째 방법은 직접 메세지큐에서 메세지를 가져와서 처리하므로
: : Application객체에서 발생하는 OnMessage등의 이벤트들이 발생하지 않습니다.
: : 관련사항을 유의하시고 사용하셔야 합니다.
: :
: :
: : 이상입니다.
: :
: : 그럼..
: :
: : 서치포림 님이 쓰신 글 :
: : : 안녕하세요.
: : :
: : : 현재 C++Builder 2010 버전을 사용하고 있습니다.
: : : 그런데 TEdit 에 텍스트를 넣고 마우스로 다른 컨트롤을 클릭하여 포커스를 이동하면 TEdit에 입력한 문자 중 마지막 글자가 사라집니다.
: : : Edit 박스에는 마지막 글짜까지 표시되어 있는데 코딩으로 읽어보면 마지막 글자는 나타나지 않습니다.
: : :
: : : 예를들면, Edit1 에 "학용품" 라고 입력한 후에 마우스로 다른 컨트롤을 클릭하여 포커스를 이동한 후 코딩으로
: : :
: : : AnsiString sText = Edit1->Text;
: : :
: : : 위와 같이 하면, sText 에는 "학용" 이라고 나옵니다.
: : :
: : : 즉 마지막 글자 입력 중에 포커스를 다른 데로 옮기면 조합중인 글자가 사라지는 문제가 발생합니다.
: : :
: : : 그런데 Edit1에는 원래 입력한 대로 "학용품"이라고 표시되어 있고, 포커스를 다시 Edit1으로 옮겼다가 다른 컨트롤로 옮기면 이번에는 정상으로 나옵니다.
: : :
: : : 그리고 포커스를 옮길 때 <Tab> 키를 쳐서 이동하면 괜찮은데, 마우스로 다른 컨트롤을 클릭하여 이동하면 이런 문제가 발생합니다.
: : :
: : : 이런 경우에 어떻게 해결해야 하나요?
: : :
: : : 코딩으로 Edit 박스를 빠져나갈 때 End 키나 Right 키를 강제로 입력하여 마지막 글자가 사라지는 문제를 해결할 수 있을까요?
: : : 기초가 많이 부족하여 해결하기가 어렵네요.
: : : 가능하면 방법 좀 부탁드립니다.