|
짐작하신 그대로입니다. 아마도 Win32쪽 공부를 제대로 하셨나봅니다. ^^
아시다시피 그래픽컨트롤은 윈도우 핸들을 아끼려는 목적이 강하기 때문에 윈도우 핸들이 아예 없습니다.
따라서 기본적으로는 메시지를 받을 수가 없지요.
하지만 메시지를 이용해서 처리하는 것이 여러모로 유리한 경우가 많기 때문에 핸들이 없는 그래픽 컨트롤에도 메시지의
개념이 도입된 것입니다. 그래픽 컨트롤 자체에는 핸들이 없기 때문에 직접 외부로부터 메시지를 받을 수는 없지만,
Parent로부터 메시지를 받고 자체 내에서 메시지를 운영하기 위해서는 핸들이 필요하지 않습니다.
왜 메시지 모델을 쓰는데 핸들이 필요가 없냐 하면... TGraphicControl의 직접 애비인 TControl의 Perform() 이라는
함수가 있기 때문입니다. 이 함수는 컨트롤 내부에서 마치 자신의 핸들이 있을 때의 핸들에 대한 SendMessage()
함수처럼 동작합니다. 에뮬레이션한다는 말이 적당하겠군요. SendMessage()의 첫 인자인 핸들만 없고 나머지 인자들,
그러니까 메시지 번호와 WPARAM, LPARAM이 차례로 인자로 들어갑니다. 윈도우 핸들 대신 컨트롤 객체가 대신한다는
점만 차이가 나는 셈이죠. 이 함수의 구현을 보면, 실제로 하는 일은 WindowProc()을 직접 호출해버리는 것 뿐입니다.
여기서 WindowProc()은 Win32의 WndProc()과 똑같다고 보시면 됩니다. (내부적으로 단계를 한둘 더 거치지만요)
이 Perform() 함수는 윈도우 핸들이 있는 컨트롤, 즉 TWinControl에 대해서는 실제로 SendMessage() 호출과 완전히
같은 역할이죠. 단지, SendMessage()를 호출하면 메시지큐를 한번 들렀다가 오는데 Perform() 함수는 메시지를 처리할
실제 함수로 직접 보내는 것이 차이가 나는 것입니다. 그래픽컨트롤의 경우에는 핸들이 없어서 SendMessage()를
쓰지 못해도 대신 쓸 수 있는 Perform()이 있기 때문에 VCL 객체 구조에서는 아무런 문제가 없습니다.
머 썰이 길어졌는데, 어쨌든 핸들이 없더라도 SendMessage()와 똑같이 써먹을 수 있는 Perform() 함수가 있기 때문에
외부에서 TControl이라는 객체로 메시지를 보내는 것이 아니라 딱 윈도우 핸들로만 메시지를 보내겠다고 고집하는 경우가
아니라면, 그래픽컨트롤이라도 VCL 내부적으로 메시지를 처리하는 데는 아무런 문제가 없습니다.
질문하신 그래픽컨트롤에서 WM_PAINT 메시지는 짐작하신 대로 Parent의 DC를 쓰구요. 구체적으로 이렇게 동작합니다.
TWinControl에서 그리기 동작을 실제로 수행하는 함수는 PaintHandler()라는 함수인데, 이 함수가 자기 자신을 다 그린
후에 PaintControls()라는 함수를 호출합니다. 이름에서 삘이 오지요? 루프를 돌면서 자식 컨트롤들을 그리는 함수입니다.
여기서 자식 컨트롤을 실제로 그리기 위해 호출하는 것이 Perform(WM_PAINT, DC, 0); 입니다. 여기서 두번째 인자
DC는 당연히 TWinControl 객체 자체의 DC입니다. 자식 컨트롤의 입장에서는 TWinControl이 Parent이고, 다시 말하면
Parent가 스스로 그린 직후에 자식 컨트롤에 Perform() 함수를 이용해서 WM_PAINT를 보내고, 그러면 자식 컨트롤이
스스로 그릴 수 있게 되는 것입니다.
상당히 축약해서 메시지 처리 방식을 설명드렸는데, 실제로는 이것보다 상당히 더 복잡합니다. 그리고 이런 구조를 가만히
뜯어보면, VCL이 비주얼한 프로그래밍과 로우레벨 코딩 양쪽 모두를 위해 정말 최적화된, 대단한 프레임워크라는 걸
느끼고 또 한번 감탄하게 된답니다. ^^
WARSHIP 님이 쓰신 글 :
: 안녕하세요 ^^
:
: 제가 공부를 하다가 약간 궁금한 점이 있어서 질문을 올리게 되었습니다.
: (TGraphicControl 로 검색을 해보았지만 원하는 답변이 없었습니다 ㅜ.ㅜ)
:
: ---------------------------------------------------------------------------------
: 1. TGraphicControl의 경우 Handle이 없지 않습니까?
: 그런데 어떻게 메세지를 받고 이벤트 핸들러를 작성할 수 있는지요?
:
: 예를 들어 TLabel을 상속받은 TMyLabel 이 있다고 할때
: 메세지맵을 이용해서
: BEGIN_MESSAGE_MAP
: VCL_MESSAGE_HANDLER( WM_PAINT , TMessage, OnPaint);
: END_MESSAGE_MAP(TLabel)
:
: void __fastcall TMyLabel::OnPaint(TMessage &MSG)
: {
: HDC dc = (HDC)MSG.wParam;
: ~dc를 이용한 드로잉
: }
:
: 이런식으로 이용하면 잘 되더라구요.
: 그렇다면 TLabel은 핸들이 없는데 어떻게 WM_PAINT 를 받는 것인지요?
: 혹은 private 속성으로 감추어진 것인지요?
: win32api 에서 WM_PAINT 의 wParam 에 대해서 일부 공용 컨트롤의 경우
: 에 wParam으로 DC가 넘어온다고 되어 있는데. 일반적으로 핸들이 있는 컨트롤의 경우
: BeginPaint(),EndPaint()를 사용하는데
: TLabel의 경우 인수로 집어넣어줄 핸들이 없어서 wParam을 이용했더니
: 잘 되더군요.
: 아무래도 부모 윈도우의 DC가 넘어오는거 같은데.
: 그렇다면 부모윈도우의 WM_PAINT 이벤트 핸들러에서
: TGraphicControl의 WM_PAINT핸들러를 호출해주는것인지요?
: 너무너무 궁금합니다 @_@;
:
: TGraphicControl의 구현된 방식에 대해 꼭 조언좀 부탁드립니다. ^^;
:
: 그럼 좋은 하루 보내시구 행복한 일만 잔뜩 일어나시길 바랍니다 ^^
: ---------------------------------------------------------------------------------
|