[팁] 일반 윈도우에서 다이얼로그박스의 편리한 키보드 인터페이스 구현하기 |
작성자 | 강성엽 (IP:220.78.3.178) |
작성일 | 2004년 11월08일 20시 10분(조회수:5067) |
내용 | 다이얼로그(특히 모달형 다이얼로그)박스를 만들어보신 분이라면 그 편리한 키보드 인터페이스에 대해 부러움을 가져보셨을 겁니다. TAB 키를 누르면 컨트롤들 사이에서 포커스를 전환할 수 있고, 캐럿을 가지지 않는 컨트롤이라면 방향키로도 포커스 전환이 되고, ShortCut을 이용해 한 번에 포커스를 옮길 수 도 있으며, Default버튼은 포커스를 위치시킬 필요 없이 Enter 키만 눌러도 클릭이 되고, ESC 키를 누르면 WM_COMMAND 메시지와함께 IDCANCEL 코드가 넘어와서, 대화상자를 닫는 등의 작업을 시킬 수 있으니 정말 배가 아플 정도로 부럽지요. 그런데, 우리가 직접 CreateWindow로 만든 윈도우랑 컨트롤들은 어떻습니까? 암만 WS_TABSTOP이나 BS_DEFPUSHBUTTON 스타일을 줘도 TAB키, 방향키, Enter 키, ESC 키 꿈쩍도 하지 않지요. 물론 이들 기능을 일일이 WndProc 안에다 구현해 넣으면 되겠지만, 보통 힘든 일이 아닌데다가, 차일드 컨트롤의 수가 많아지면 많아질수록 여간 코드가 길어지고 성가신 일이 아닐 수 없지요. 직접 만든 윈도에서도 이와같은 편리한 키보드 인터페이스를 별도의 코딩 없이 구현하기위해 이리저리 찾아 헤맨 끝에 드디어 좋은 방법을 발견했습니다. 바로 while(GetMessage()) { } 루프 내에다 IsDialogMessage() 함수를 사용해서 키보드 메시지를 다이얼로그 인터페이스용 메시지로 바꾸어주는 것이지요. 이 함수의 사용법은 TranslateAccelerator()와 마찬가지로 TRUE가 리턴됐을 경우에는 나머지 메시지 처리(Translate, Disptch)를 하지 않고 다시 GetMessage로 돌아가야 합니다. while(GetMessage(&msg, NULL, 0, 0)) { 그런데 메시지 처리 루프에 IsDialogMessage()를 넣는 것 만으로는 부족한 것이 있습니다. 위와 같이 하면 TAB키, 방향키, ESC 키, Enter 키, ShortCut은 잘 작동하지만, Default Pushbutton 스타일이 유지가 되지 않아서 디폴트 버튼일지라도 포커스를 뺐기면 더이상 디폴트 버튼으로서의 기능을 상실하게 됩니다. 따라서 Enter 키가 의미 없게 되어 버리지요. 완벽한 다이얼로그박스를 흉내내려면 WndProc의 디폴트 메시지 처리 함수를 DefWindowProc()에서 DefDlgProc()으로 바꾸어줍니다. 인수는 DefWindowProc와 완전히 동일합니다. 단, 이 함수를 WndProc 내에 넣을 때 몇 가지 주의해야 할 것이 있습니다. 이 함수는 윈도의 여분 메모리를 이용해서 작동하므로 클래스 선언할 때 반드시 cbWndExtra 멤버에 DLGWINDOWEXTRA 값을 넣어주어야 합니다. (확인해보니 이 값은 30이더군요. 그냥 DLGWINDOWEXTRA 상수 쓰셔도 되구요) 또, 이 함수는 WM_CLOSE 메시지를 처리해주지 않으므로 사용자가 직접 WM_CLOSE 메시지에 대한 코드를 작성해주어야 합니다. 보통 DestroyWindow(hWnd);를 호출하면 되지요. 만약 기존에 하던대로 cbWndExtra를 0으로 방치해두면 잘못된 연산 수행 오류가 발생합니다. 다음으로, 만약 디폴트 버튼을 두고 싶으면 상식적으로는 해당 버튼에 BS_DEFPUSHBUTTON 스타일을 주면 되겠거니 생각하겠지만, 이 스타일을 주지 말고, 대신 메인 윈도우로 DM_SETDEFID 메시지를 디폴트 버튼을 삼을 버튼의 ID와 함께 넘겨주면 DefDlgProc()이 알아서 디폴트 버튼으로 만들어주며, 이 버튼이 포커스를 뺐기더라도 디폴트버튼 스타일을 유지시켜줍니다. 여기까지 마치면 완벽하게 DialogBox와 동일한 키보드 인터페이스를 갖는 자신만의 Custom DialogBox가 만들어지는 것입니다. Custom DialogBox의 또 하나의 장점(경우에 따라서는 단점이 될 수도 있지만, 확실히 대부분의 이들에게는 장점으로 작용하리라 봅니다)은 좌표 단위가 일반 윈도우의 좌표인 Pixel 그대로 유지되므로 DialogBox에서 골치아프게 계산/변환하던 DLU에 대해서 신경쓰지 않아도 되는 것입니다. 아래에 간단한 예제 소스를 첨부합니다. 기존에 프로그램하던 방식과 거의 같습니다만 위에서 언급한 약간의 차이가 있지요. 눈여겨 봐둘만한 소스가 될겁니다. --------------------------------------------------------------------- #include <windows.h> |
winapi.co.kr의 자유강좌란에서 퍼왔다.
와우 정말 굿굿굿 팁~~~~
'API' 카테고리의 다른 글
전역 스레드 핸들을 다룰시 유의사항 (0) | 2010.03.16 |
---|---|
TerminateThread사용시 생존여부 판단 주의(GetExitCodeThread 사용시 리턴값 주의) (0) | 2010.03.16 |
리스트뷰(혹은 트리뷰 등등)의 배경에 그림 넣기입니다 (2) | 2009.11.05 |
시스템 정보 알아내기....네이버 지식인 참조 (3) | 2009.10.04 |
리스트뷰 아이템 스왑, 이동, 정렬 관련 API 소스 (2) | 2009.09.03 |
윈도우 속성 제거 및 추가 (and or not 연산) (0) | 2009.08.17 |
[펌] 프로세스의 메모리안에 접근하고 읽고 쓰기. (0) | 2009.07.11 |