아래 내용은 이미 많이들 알고있는 방법이고
Q&A에 검색하면 나오는 것이지만 한번 정리해 봅니다.
제목 : Enter를 Tab 처럼 사용하기
[방법1]
1. 위 기능을 적용하고 싶은 Control의 OnKeyPress 이벤트에서
2. Key를 확인한후에 SendMessage로 Form에 WM_NEXTDLGCTL을 날리면 됩니다
//C++Builder
void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key)
{
if(Key==VK_RETURN)
Perform(WM_NEXTDLGCTL,0,0);
}
//Dephi
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN) then
Perform(WM_NEXTDLGCTL,0,0);
end;
* 문제점
그런데 이방법의 문제점은 적용하고 싶은 Control이 많은 경우에 문제가 됩니다.
원하는 모든 Control에 해당 위 code를 copy하거나
아니면 모든 Control이 이벤트 핸들러를 하나의 Method로 걸어두거나 하는 방법이 있지만
귀찮고 불편할것입니다.
[방법2]
그래서 Form전체에 한번에 적용하는 방법으로 해봅니다.
1. Form의 KeyPerview = true 로 해두시구요
2. Form의 OnKeyPress 이벤트에 방법1에서와 같은식으로 코딩해 둡니다.
//c++Builder
void __fastcall TForm1::FormKeyPress(TObject *Sender, char &Key)
{
if(Key==VK_RETURN)
{
Perform(WM_NEXTDLGCTL,0,0);
Key=0;
}
}
//Dephi
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN) then
Perform(WM_NEXTDLGCTL,0,0);
end;
* 근데 위 방법은 TMemo같이 Enter키에 다음 라인으로 넘어가야 하는 Control에는 적용되면 문제가 되겠죠
* 그래서 아래와같이 현재 Focus가 되어있는 Control이 무엇인지 확인해 보구 적용합니다.
//c++Builder
void __fastcall TForm1::FormKeyPress(TObject *Sender, char &Key)
{
if(Key==VK_RETURN)
{
String sClsName=ActiveControl->ClassName();
if(sClsName=="TEdit" || sClsName=="TComboBox")
{
Perform(WM_NEXTDLGCTL,0,0);
Key=0;
}
}
}
//Dephi
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if (Key = Char(VK_RETURN)) then
if ActiveControl is TEdit then
Perform(WM_NEXTDLGCTL,0,0);
end;
* 문제점:
방법2에도 문제점이 있는데 Form이 여러개 있는경우가 그렇겠죠
문론 해당코드를 모두 copy - paste하시면 됩니다만..
[방법3]
방법2의 문제점은 Application의 OnMessage이벤트를 이용해 해결할수 있습니다.
1. Application의 OnMessage 에 이벤트 핸들러를 걸어두시구
2. 해당 핸들러 함수에서 Screen의 ActiveForm과 ActiveContol을 확인하여 처리하면 됩니다.
//c++Builder
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Application->OnMessage = AppMessage;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::AppMessage(tagMSG &Msg, bool &Handled)
{
if(Msg.message == WM_KEYDOWN)
{
if(Msg.wParam == VK_RETURN)
{
String sClsName=Screen->ActiveControl->ClassName();
if(sClsName=="TEdit" || sClsName=="TComboBox")
{
Screen->ActiveForm->Perform(WM_NEXTDLGCTL,0,0);
Msg.wParam=0;
}
}
}
}
//Dephi
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
end;
procedure TForm1.AppMessage(var Msg:tagMSG;var Handled: boolean);
var
sClsName: String;
begin
if Msg.message = WM_KEYDOWN then
begin
if Msg.wParam = VK_RETURN then
begin
sClsName:=Screen.ActiveControl.ClassName();
if (sClsName='TEdit') or (sClsName='TComboBox') then
begin
Screen.ActiveForm.Perform(WM_NEXTDLGCTL,0,0);
Msg.wParam:=0;
end;
end;
end;
end;
3.위와같이 하면 전체 application에 적용되는데 해당기능을 원하지 않는 Form이 있다면
Screen->ActiveForm이 무엇인지 확인해본후 적용하면 되겠죠
//=========================================================================================
[응용]
위 방법3은 다양하게 응용이 가능합니다.
개인적으로 MainForm이 아닌 Form들은 Esc 키에 Close하고 싶은데...
방법2로 모든 Form의 OnKeypress이벤트에 적용해도 되지만
방법3의 Application->OnMessage 를 이용하면 간단하게 되죠
//c++Builder
void __fastcall TForm1::AppMessage(tagMSG &Msg, bool &Handled)
{
if(Msg.message == WM_KEYDOWN)
{
if(Msg.wParam == VK_ESCAPE)
{
if( Screen->ActiveForm != Application->MainForm) // 메인폼이 아닌경우
{
Screen->ActiveForm->Close();
}
}
}
}
//Dephi
procedure TForm1.AppMessage(var Msg:tagMSG;var Handled: boolean);
begin
if (Msg.message = WM_KEYDOWN) and (Msg.wParam = VK_ESCAPE) then
if Screen.ActiveForm <> Application.MainForm then // 메인폼이 아닌경우
Screen.ActiveForm.Close();
end;
* 그밖에도 여러가지로 응용할수 있습니다.
* 앗참 한가지더..
Tab 키가 다음 Control로 Focus가 이동되구 Shift + Tab이 이전 Control로 Focus가 이동되듯이
Shift + Enter 키에 이전 Control로 Focus가 이동하려면
Perform(WM_NEXTDLGCTL,VK_SHIFT,0); // 이렇게 메세지를 날리면 됩니다.
* 앗참 또 한가지
Form의 Perform(WM_NEXTDLGCTL,0,0); 는
Form의 SelectNext(ActiveControl,true,0) 함수로 해도 됩니다.
오히려 SelectNext가 좋겠네요.
SelectNext(ActiveControl,false,0); 하면 Shift + Tab 과 같습니다.
그럼..
이런 많이 쓰이는 기법은 자료 정리가 되어 있는게 무척 중요합니다.
정작 쓰려고 찾을때 시간이 꽤 걸리기도 하거든요.