2009년 04월 23일
[C#] MDI 에서 화살표키에 의한 자식폼(Child Form) 포커스 이동 막기
이녀석 하나로 상당히 골머리를썩고(3일 정도) 해결해서 포스팅!!
1차시도 : KeyDown -> 실패 (화살표키 입력조차 인식못함)
2차시도 : PreviewKeyDown -> 실패 (화살표키 입력은 인식하나 포커스가 이동함)
3차시도 : WndProc -> 실패 (SDI에서 화살표키 입력은 인식하나 MDI에서는 화살표키 입력인식조차 못함)
4차시도 : DefWndProc -> 실패 WndProc와 같은 현상
5차시도 : IMessageFilter 적용 -> 성공!
이에 따라 IMessageFilter 를 이용한 화살표키에 따른 자식폼 포커스이동 막기에대해서 예제만 포스팅을 하겠습니다..
솔직히 저도찌질이하수라 상세한 지식까지는 무리임 .... :'(
1. IMessageFilter 사용하는 법
1_1.우선 IMessageFilter 가 위치한 Namespace 는 System.Windows.Forms 입니다.
IMessageFilter는 상속받아서 이용해야하므로 IMessageFilter를 상속받는 클래스를 만듭니다.
/* IMessageFilter 를 상속받는 Class의 기본형태 */
public class MyMessageFilter : System.Windows.Forms.IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
/* 메세지에 따른 행동 코드 */
}
}
1_2.자 그럼 필터 클래스가 만들어졌다면 인스턴스화 해서 적용을 시켜야겠지요
MyMessageFilter myMsgFilter = new MyMessageFilter()
Application.AddMessageFilter(myMsgFilter);
2. MessageFilter를 통한 자식폼 포커스 이동 막기
2_1. MDI_Parent 라는 Form을 상속받는 클래스가 있다고 가정하겠습니다.
2_2. 위에 1_1 에서 알려드린것처럼 IMessageFilter를 상속받는 클래스를 만듭니다.
(부모폼의 클래스 내부에 클래스를 선언하는게 여러모로 사용하기가 편리할수도 있구요 외부에선언하고 생성자에서
부모폼을 넘겨받아서 맴버변수에 두고 부모폼에 접근해도 됩니다. 여기서는 부모폼의 클래스 외부에 선언하겠습니다.)
public class MyMessageFilter : System.Windows.Forms.IMessageFilter
{
MDI_Parent m_parent;
MyMessageFilter ( MDI_Parent p )
{
m_parent = p;
}
public bool PreFilterMessage(ref Message m)
{
}
}
2_3. 1_2의 필터클래스 인스턴스화 및 적용은 부모폼의 생성자에서 수행하도록 합니다.
public class MDI_Parent : System.Windows.Forms.Form
{
/* 부모폼 클래스의 생성자 */
public MDI_Parent()
{
/*VS2005이후부터는 디자이너 코드가 외부파일로 빠지기때문에 아래의 코드가 있습니다.*/
InitializeComponent();
MyMessageFilter myMsgFilter = new MyMessageFilter(this);
Application.AddMessageFilter(myMsgFilter);
}
}
이로서 일단 MessageFilter를 장착했습니다.
2_4. 이제 MessageFilter 클래스의 PreFilterMessage 메서드의 내용을 채워줍니다.
/* 활성화된 Focus를 가진 컨트롤이 있는지 확인후 */
if( m_parent.Activecontrol != null)
{
/* 해당 컨트롤이 Form 타입인지를 확인합니다. */
if(m_parent.Activecontrol.GetType == typeof(Form))
{
/* 넘어온 메세지의 아이디가 WM_KEYDOWN 값인지를 확인합니다. */
/* 이 값은 WinUser.h 파일에 기술되어있습니다. 이파일은 VS2005를 기본설치경로로 설치했을시를 기준으로 */
/* C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Include 에 있습니다.*/
if(m.Msg == 0x0100)
{
/* VK_ 값을 확인합니다. 이녀석역시 WinUser.h 에 기술되어있습니다. */
/* WParam은 IntPtr 값이므로 ToInt32 메서드를 호출해서 정수값으로 변환해서 비교합니다. */
/* 이때 WinUser.h 에는 VK_UP,DOWN,LEFT,RIGHT 값이 16진수로 선언되어있으므로 해당값의 10진수값을 찾아내서 걸러주시면됩니다. */
switch(m.WParam.ToInt32())
{
case 37: //to hex : 0x26 VK_LEFT
/* 왼쪽버튼일때 */
/* 리턴값을 true로 넘기면 윈도우메세지가 다른곳으로 전파되지 않습니다. */
/* 즉 return 값이 false 일경우 포커스가 넘어가게 됩니다. */
return true;
case 38: //to hex : 0x27 VK_UP
/* 위쪽버튼일때 */
return true;
case 39://to hex : 0x28 VK_RIGHT
/* 오른쪽버튼일때 */
return true;
case 40://to hex : 0x29 VK_DOWN
/* 아래쪽버튼일때 */
return true;
}
}
}
}
return false;

1차시도 : KeyDown -> 실패 (화살표키 입력조차 인식못함)
2차시도 : PreviewKeyDown -> 실패 (화살표키 입력은 인식하나 포커스가 이동함)
3차시도 : WndProc -> 실패 (SDI에서 화살표키 입력은 인식하나 MDI에서는 화살표키 입력인식조차 못함)
4차시도 : DefWndProc -> 실패 WndProc와 같은 현상
5차시도 : IMessageFilter 적용 -> 성공!
이에 따라 IMessageFilter 를 이용한 화살표키에 따른 자식폼 포커스이동 막기에대해서 예제만 포스팅을 하겠습니다..
솔직히 저도
1. IMessageFilter 사용하는 법
1_1.우선 IMessageFilter 가 위치한 Namespace 는 System.Windows.Forms 입니다.
IMessageFilter는 상속받아서 이용해야하므로 IMessageFilter를 상속받는 클래스를 만듭니다.
/* IMessageFilter 를 상속받는 Class의 기본형태 */
public class MyMessageFilter : System.Windows.Forms.IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
/* 메세지에 따른 행동 코드 */
}
}
1_2.자 그럼 필터 클래스가 만들어졌다면 인스턴스화 해서 적용을 시켜야겠지요
MyMessageFilter myMsgFilter = new MyMessageFilter()
Application.AddMessageFilter(myMsgFilter);
2. MessageFilter를 통한 자식폼 포커스 이동 막기
2_1. MDI_Parent 라는 Form을 상속받는 클래스가 있다고 가정하겠습니다.
2_2. 위에 1_1 에서 알려드린것처럼 IMessageFilter를 상속받는 클래스를 만듭니다.
(부모폼의 클래스 내부에 클래스를 선언하는게 여러모로 사용하기가 편리할수도 있구요 외부에선언하고 생성자에서
부모폼을 넘겨받아서 맴버변수에 두고 부모폼에 접근해도 됩니다. 여기서는 부모폼의 클래스 외부에 선언하겠습니다.)
public class MyMessageFilter : System.Windows.Forms.IMessageFilter
{
MDI_Parent m_parent;
MyMessageFilter ( MDI_Parent p )
{
m_parent = p;
}
public bool PreFilterMessage(ref Message m)
{
}
}
2_3. 1_2의 필터클래스 인스턴스화 및 적용은 부모폼의 생성자에서 수행하도록 합니다.
public class MDI_Parent : System.Windows.Forms.Form
{
/* 부모폼 클래스의 생성자 */
public MDI_Parent()
{
/*VS2005이후부터는 디자이너 코드가 외부파일로 빠지기때문에 아래의 코드가 있습니다.*/
InitializeComponent();
MyMessageFilter myMsgFilter = new MyMessageFilter(this);
Application.AddMessageFilter(myMsgFilter);
}
}
이로서 일단 MessageFilter를 장착했습니다.
2_4. 이제 MessageFilter 클래스의 PreFilterMessage 메서드의 내용을 채워줍니다.
/* 활성화된 Focus를 가진 컨트롤이 있는지 확인후 */
if( m_parent.Activecontrol != null)
{
/* 해당 컨트롤이 Form 타입인지를 확인합니다. */
if(m_parent.Activecontrol.GetType == typeof(Form))
{
/* 넘어온 메세지의 아이디가 WM_KEYDOWN 값인지를 확인합니다. */
/* 이 값은 WinUser.h 파일에 기술되어있습니다. 이파일은 VS2005를 기본설치경로로 설치했을시를 기준으로 */
/* C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Include 에 있습니다.*/
if(m.Msg == 0x0100)
{
/* VK_ 값을 확인합니다. 이녀석역시 WinUser.h 에 기술되어있습니다. */
/* WParam은 IntPtr 값이므로 ToInt32 메서드를 호출해서 정수값으로 변환해서 비교합니다. */
/* 이때 WinUser.h 에는 VK_UP,DOWN,LEFT,RIGHT 값이 16진수로 선언되어있으므로 해당값의 10진수값을 찾아내서 걸러주시면됩니다. */
switch(m.WParam.ToInt32())
{
case 37: //to hex : 0x26 VK_LEFT
/* 왼쪽버튼일때 */
/* 리턴값을 true로 넘기면 윈도우메세지가 다른곳으로 전파되지 않습니다. */
/* 즉 return 값이 false 일경우 포커스가 넘어가게 됩니다. */
return true;
case 38: //to hex : 0x27 VK_UP
/* 위쪽버튼일때 */
return true;
case 39://to hex : 0x28 VK_RIGHT
/* 오른쪽버튼일때 */
return true;
case 40://to hex : 0x29 VK_DOWN
/* 아래쪽버튼일때 */
return true;
}
}
}
}
return false;

어때요? 참 쉽죠?
# by | 2009/04/23 16:23 | 프로그래밍이야기 | 트랙백 | 덧글(0)






☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]