삽질의 현장/- 윈도우 API

#009_WIndow_API_다이얼로그 (1)

shovelman 2015. 9. 15. 14:20


안녕하세요 삽잡이 입니다.

이번 시간에는 지난시간에 이어서 리소스에 대해 조금 더 살펴보고자 합니다.


여러분은 이와 같은 메시지 창을 보신적이 있으신가요?

물론 없으시겠지요... 저런 혐오스러운 메시지창을 하하...


아무튼... 어떤 확인을 위해 띄우는 윈도우를 바로 MessgeBox라고 합니다.

이 메시지 박스를 띄우기 위해서는



MSDN에서 우리에게 알려주는 것과 같이,

부모 윈도우 핸들과, 출력될 내용, 캡션의 이름, 스타일이 순서대로 매개변수에 입력되어져야 됩니다.

여기서 의문이 듭니다... 왜 부모 윈도우 핸들을 넣어줘야할까요?

왜냐하면, 메시지박스는 윈도우이기 때문입니다.


정리하자면, 윈도우 상에 어떠한 작업 중 

'확인을 위해 띄우는' 목적에 의해 생성되는 윈도우가 메시지 박스이기 때문에 

결과적으로 이 메시지 박스 전에는 윈도우가 실행되고 있다는 것입니다.


아무튼... 우리는 메시지 박스에 대해서 알아보려고 한 것은 아니였지만,

메시지 창을 띄운 이유는 이와 비슷하지만 다른... 재미있는 녀석을 살펴보기 위해서

관심거리로 한번 던져봤습니다...



우리가 알아볼 재미있는 녀석! 바로, 다이얼로그에 대해서 알아보려고 합니다.

다이얼로그는 지난 시간 메뉴를 만들때와 같이 리소스에서 만들 수 있습니다.


자... 다이얼로그란? 

사용자에게 정보를 보여주거나 응답을 받는 사용자 인터페이스에서 사용되는 특별한 창이라고

위키백과에서는 친절히 설명을 해주고 있습니다.


이 다이얼로그는 

모달 다이얼로그와 모달리스 다이얼로그라는 두가지의 종류로 나눌 수 있습니다.

이제 본격적으로 시작을 해볼까요... (그래요 제목을 보세요 제목이 다이얼로그입니다....)


modal dialog 에는 대표적으로 옵션창이 있습니다.

설정한대로 확인 및 취소 기능을 통해 

변경 내용을 저장하거나 원상태로 복구시킬 수 있는 옵션창 말입니다.

이 모달로그의 특징으로는, 

해당 창이 활성화 되어있는 상태에서는 결코 다른 윈도우에 포커스를 줄 수 없다는 것입니다.

다들 이런 윈도우 창을 한번쯤은 경험 해보셨겠지요...


다음으로는 modeless dialog 에 대해 살펴보도록 하겠습니다.

이런 창들 보신 적이 있으실 것입니다. 찾기, 바꾸기 등등의 다이얼로그 말입니다.

일반적으로 이런 창들에는 확인 및 취소 기능의 버튼이 없습니다.

다이얼로그를 띄우면 x 혹은 close 버튼으로 다이얼로그를 제거하게 생긴 놈들이지요...

이 놈들은 얼마든지 다른 윈도우 창으로 포커스를 이동할 수 있게 해줍니다.

다른 윈도우 창에서 내용을 참조할 수 있도도록 허용해준다는 것입니다.


자... 이와 같이 다이얼로그는 두가지의 종류로 나뉠 수 있을 것 같습니다.

잘 보니 다이얼로그는 미리 만들어서 제공하고,

사용자와 원할한 대화를 할 수 있도록 구현된 즉, 인터페이싱 할 수 있는 윈도우라는 것을

혹시 깨달으신 분이 있으시련지요... 있다면 짱


그렇다면, 이번시간에는 modal dialog에 대해서 조금 더 자세하게 살펴보도록 하겠습니다.

모달 다이어로그는 'CreateDialog'와 'DestroyWindow' 함수를 통해 만들고 제거할 수 있게 됩니다.


어떻게 생긴 놈들일까요...



요렇게 생겨먹었습니다.... 잘생겼군요...

해당 함수는 

프로그램 인스턴스의 핸들, 리소스의 ID, 부모 윈도우의 핸들, 다이어로그 프로시저의 주소를

순차적으로 매개변수에 넣습니다.


EnDialog 함수도 살펴보도록 하겠습니다.



빈약하게 생겼군요... 푸하하 장난입니다. 죄송합니다.

이왕 살펴본김에 다음에 살펴볼 모달리스 다이얼로그를 만들기 위한 친구들도

잠시 쳐다만 보고 가도록 하지요...

모달리스 다이얼로그는 일반 팝업 윈도우와 다른 것이 없습니다....


자... 정신이 없습니다. 아무튼, 산으로 가지 말고... 오늘은 모달!!!

다이어로그를 사용하기 위해서는 DialogBox 함수의 매개변수에서 확인했듯이 

다이어로그 프로시저가 필요합니다.

여기서 알 수 있는 것은, 잠시 뒤에 다시 설명하겠지만,

다이어로그 창이 활성화 되어 있는 상태에서는 다이어로그 프로시저만을 사용한다는 것입니다.


이쁘게 한번 만들어보겠습니다.

이전에 언급한 적이 있었는데 프로시저는 WndProc만이 있는 것이 아니라 했었습니다.

아무튼... 


 

 

이와 같이 다이어로그의 메시지를 처리할 수 있는 

DlgProc 함수를 만들었다면 return 또한 신경을 써줘야합니다.

다이어로그 프로시저를 만들때에 위의 그림을 살펴보신다면

false로 되어있는 것을 확인하실 수 있습니다.


WndProc에서 모든 메시지를 받고 반환할 때 나머지 처리해야할 메시지가 있다면

DefWindowProc으로 처리를 했던 것을 기억하시나요?

다이어로그 프로시저는 false를 넘김으로 남은 처리를 모두 default 하겠다고 약속한 것입니다.

즉, 디폴트적인 처리 작업을 하겠다는 것이라구요...


해당 다이어로그 프로시저에는 WM_COMMAND 메시지가 정말로 가장 중요한 메시지입니다.

WndProc 프로시저에서는 

WM_CREATE, WM_DESTROY, WM_PAINT, WM_LBUTTONDOWN 등과 같은 메시지들이 중요했었지만, 

다이얼로그에서는 WM_COMMAND가 중요한 메시지 중 하나라고 꼽을 수 있다는 것입니다.


기존 메뉴 리소스를 만들었을 때에도 COMMAND 메시지가 발생했었는데...

이는 이전시간 WM_COMMAND가 발생하는 경우에 대해서 언급한 적이 있었는데 

잠시후에 다시 설명해보도록 하겠습니다.


우선, COMMAND 메시지에 대해서 생각하기 전에 

우리는 GUI에서 다루는 컨트롤에 대해서 알아볼 필요성이 있습니다.


우선, 컨트롤이란 API에서 사용자와 대화를 아주 잘 할 수 있도록

미리 만들어 제공하는 간단하고도 단순한 GUI 위젯이라고 부를 수 있습니다.

즉, 윈도우인데 사용자와 인터페이스 할 수 있도록 간단하게 만들어 놓은 윈도우라는 것입니다.

단, 해당 컨트롤은 단일 목적을 가지고 있습니다. 

텍스트 컨트롤 박스, 체크 버튼 박스 등등 모두 한가지의 기능만을 가지고 있다는 것입니다.


아무튼, 이 컨트롤이라는 놈은 사용자로부터 Input과 Output을 위해 존재합니다.

즉, 컨트롤은 사용자와의 UI를 위해 탄생되었다는 것입니다.

해당 컨트롤에 어떠한 이벤트가 발생하는지에 대해서 알아야 하는데

이를 COMMAND 메시지를 통해 알게 되는 것입니다.


이해가 안가시는 분들을 위해...

 


이처럼 각 단일 목적을 가진 컨트롤 놈들의 버튼이 눌려지고 값이 입력될 때

이 발생한 이벤트에 대해서 COMMAND 메시지를 통해 알려진다는 것입니다.


그리고 맨 처음 언급했었는데, 

해당 다이어로그는 기존 윈도우에서 나온 윈도우입니다.

그렇다면 COMMAND 메시지가 발생되는 2번째 경우가 성립하게 됩니다.

바로 '부모에게 컨트롤 자식이 자신의 상태를 보고하는 경우' 말입니다.


다시한번 정리하도록 해보지요... COMMAND는 두 가지의 경우 발생하게 됩니다.

1. 메뉴 / 단축키가 눌렸을 때 발생한다.

2. 컨트롤이 컨트롤이 포함되어 있는 부모에게 상태를 알릴 때 발생한다.


우리가 지금 다이얼로그, 정확하게 모달 다이얼로그에 대해서 아아보고 있는데

모달 다이얼로그의 특성에 대해서 잘 생각해보셔야합니다.


다이얼로그 창을 띄울 수는 있습니다. 껌이죠...

하지만, 다이얼로그를 생성하고 보여주는 것 까지는 쉽지만,

모달 다이얼로그는 다른 곳으로 포커스를 이동 시킬 수 없다는 특징이 있었습니다.

모달 다이얼로그가 생성 된 후로 모든 메시지를 다이얼로그 프로시저가 받게 된다는 것입니다.

이말인 즉, 다이얼로그를 생성할 때에는 내가 생성하지만,

제거할 때는 모달 다이얼로그만 알게되는 문제가 생겼습니다.


모달 다이얼로그는 언제 제거되야 할까요?

확인 및 취소 버튼이 눌렸을 때 제거되어야 되지 않을까요?

따라서, 모달 다이얼로그에는 제거하기 위한 기능에 대해서 고려해볼 필요성이 있습니다.


확인 및 취소 버튼 컨트롤은 다이얼로그에 포함되어있습니다.

즉, 해당 버튼들의 부모는 다이어로그가 된다는 것입니다.

이말은, 확인 취소에 대한 COMMAND가 다이어로그에게 날라간다는 것입니다.


메시지가 날라올 때 딸려 오는 정보들 즉, wParam과 lParam에 날라오는 정보들을 살펴보도록 하겠습니다.

lParam은 자식 윈도우의 핸들이 포함되어 오고,

wParam의 하위 2바이트에는 ID, 

상위 2바이트에는 보고/통지 코드/ 알림 코드라고 불리우는 Notification Message가 포함되어 날라옵니다.



따라서, 알림코드가 확인 및 취소에 대한 코드일 경우, 종료에 대한 처리를 하는 방법을 찾을 수 있었습니다.

지금까지 다이어로그를 생성하고 제거하는 기본적인 방법에 대해서 생각해봤습니다.


자... 다시 한번 생각해볼까요...

모달 다이어로그는 집중 받기를 좋아합니다. 다른 곳에 집중을 할 수 없지요...

즉, 모달 다이어로그가 시작되면 메인 프로시저가 멈춰져 있기 때문에

모든 메시지 처리는 다이어로그 프로시저가 받게됩니다.

결정하기 전까지 어떤 메시지도 처리되지 못하는 욕심쟁이입니다.


위에서 다이어그램 프로시저함수에 대해 기본적인 코드를 구현했을때

WM_INITDIALOG 메시지를 보셨나요...

윈도우에서 최초 발생하는 WM_CRETE가 있다면, 다이어로그에는 해당 메시지가 있습니다.

즉, 초기화를 위해 발생되는 메시지라는 것입니다.


윈도우를 가지고 놀기 위해서는 핸들이 필요합니다.

그런데 다이어로그에서 생성된 컨트롤들은 핸들을 어떻게 알 방도가 있을까요...

우리는 다이어로그를 만들 때 해당 컨트롤들의 ID를 알 수 있습니다.

따라서 핸들을 구할 수 있는 방법을 알게 된것입니다.


ID를 알고 있을때 handle을 구하는 함수가 있습니다.

바로, GetDlgItem 이라는 함수 입니다.


 

부모 윈도우의 핸들과 자식 ID를 매개변수로 넘겨주면, Handle을 주는 녀석입니다.

이와 반대로 GetParent 함수가 있는데,

해당 함수는 자식 윈도우의 Handle을 넘겨주면 부모 윈도우의 핸들을 주는 녀석입니다.

하나의 부모로 부터 여러 자식 프로세스는 생성될 수 있지만,

해당 자식의 부모 프로세스는 하나밖에 없으니 이와 같은 매개변수를 받게 되는 것 같습니다.


지금까지, 

다이어그램에 대한 설명과 종류 및 약간의 기능에 대해 살펴봤습니다.

이상 삽잡이였습니다!