C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 강좌/문서
C++Builder Programming Tutorial&Docments
[162] 핸들이 없는 컴포넌트가 핸들 갖기와 TLabel과 TStaticText의 차이점.
김태선 [jsdkts] 17177 읽음    2008-08-03 01:52
일단 소스 보시고 ....

//---------------------------------------------------------------------------

#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include "Calendar.hpp"
#include <ComCtrls.hpp>
#include <DockTabSet.hpp>
#include <ExtCtrls.hpp>
#include <Grids.hpp>
#include <Tabs.hpp>

//---------------------------------------------------------------------------
// TStaticText는 Handle이 있지만 Paint() 메소드가 없다.
// 하지만 핸들이 있으므로 직접 메시지를 받아서 화면을 다시 그리는 방법을 쓴다.

class TStaticText : public Stdctrls::TStaticText
{
    typedef Stdctrls::TStaticText    inherited;
public:
    __fastcall TStaticText(TComponent *Owner) : Stdctrls::TStaticText(Owner)
    {
    }
    void virtual __fastcall Paint()
    {
        // 이렇게하는 것은 소용없고 WndProc 메시지 핸들러에서 적당히 다시 그리는 방법을 써야 한다.
    }
};
#define TStaticText        ::TStaticText
//---------------------------------------------------------------------------
// TLabel 은 윈도우 핸들은 없어 직접 윈도우 메시지를 받을 수 없다.
// 화면을 다시 그리는 방법은 자신이 소속된 parent 컨트롤에서
// 화면을 다시 그려야 할 일이 있으면 WM_PAINT 메시지를 받아서
// 이 메시지가 오면 Paint() 메소드를 불러 화면을 다시 그리는 방법을 쓴다.

void    display(TMessage& Message);


class TLabel : public Stdctrls::TLabel
{
    typedef Stdctrls::TLabel    inherited;
private:
    THandle    FHandle;

public:
    __fastcall TLabel(TComponent *Owner) : Stdctrls::TLabel(Owner)
    {
        FHandle = 0;
        HandleNeeded();
    }
    __fastcall virtual ~TLabel()
    {
        if (HandleAllocated())
            DeallocateHWnd((void*)FHandle);
    }
    void virtual __fastcall Paint()
    {
        TRect r = ClientRect;
        //Font->Style = TFontStyles() << fsBold;
        inherited::Paint();
        DrawEdge(Canvas->Handle, &r, EDGE_SUNKEN, BF_RECT );
    }

    //---------------------------------------------------------------------------
    // 핸들을 생성하고 핸들 관련 처리를 위한 부분. 옛날 파워오브델파이 강좌 참조했음.
    //---------------------------------------------------------------------------

    // 핸들이 할당되어 있는가?
    bool __fastcall HandleAllocated()
    {
        return FHandle != 0;
    }
    // 핸들이 필요하면 할당한다.
    void __fastcall    HandleNeeded()
    {
        if (!HandleAllocated())
            FHandle = (THandle)AllocateHWnd(WndProc);
    }
    // 핸들얻기.
    THandle __fastcall GetHandle()
    {
        HandleNeeded();
        return FHandle;
    }
    // 윈도우 메시지 핸들러.
    void virtual __fastcall WndProc(TMessage& Msg)
    {
        if (Msg.Msg == WM_MOUSEMOVE)
        {
            display(Msg);    // check
        }
        Dispatch((void*)&Msg);
    }
__published:
    __property THandle Handle = { read=GetHandle };
};
#define TLabel        ::TLabel
//---------------------------------------------------------------------------
class TForm2 : public TForm
{
__published:    // IDE-managed Components
    TShape *Shape1;
    TStaticText *StaticText1;
    TLabel *Label1;
private:    // User declarations
public:        // User declarations
    __fastcall TForm2(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm2 *Form2;
//---------------------------------------------------------------------------
void    display(TMessage& Message)
{
    char buf[100];
    wsprintf(buf, "Msg:%d %d %d", Message.Msg, Message.LParamLo, Message.LParamHi);
    OutputDebugString(buf);
}
#endif

따로 설명을 안 달아도 웬만한 분은 다 알아 보시는 모양이군요.
주석에 설명 같은 것을 달아 놨으니 그 정도로 충분한가 봅니다.

컴포넌트나 클래스가 핸들을 갖으려는 이유는 윈도우 메시지를 받기 위함이죠.
VCL에서는 핸들을 갖는 방법을 위의 예제처럼 하고 있습니다.
위에 표시한대로 옛날 파워오프델파이라는 매우 얇은 정기 간행물을 구독한 적이 있는데
그기에 이미 나와 있는 방법이고 그 코드를 빌더로 옮겨 약간 수정한 것입니다.

신통하게도 매우 쉽게 윈도우 메시지를 받을 수 있을 뿐 아니라,
그 처리 또한 상당히 손쉽습니다.

위의 TLabel 예제의 Paint 에서 모클래스의 Paint()를 부르지 않는다면
Label이 아니라 어떤 것을 표현하는 다른 형태의 컴포넌트가 될 수 도 있습니다.
그러면서 TLabel이 가졌던 모든 핸들러와 프로퍼티는 유효하고, 없는 것은 새로 핸들을 얻는 윈도우 메시지 핸들러를 통해 만들 수 있습니다. 즉 아주 쉽게 컴포넌트를 만들 수 있는 것이죠.

새로 만든 TLabel은 기존 TLabel에 비해 4바이트가 늘었났습니다.
하지만, 필자의 PC 경우에는 sizeof로 찍어보면 8바이트가 증가된 것으로 나오는데, 이는 컴파일러가 기본 8바이트 메모리 경계 정렬을 해서입니다. #pragma pack(4)로 해서 검사해보면 4바이트가 증가한 것이 맞다는 것을 알수 있습니다.

위에서 보인 기존 컴포넌트를 새 컴포넌트로 대치하는 기술은 예전에 저의 팁을 찾아보시면 쉽게 이해 될 것입니다.


TLabel과 TStaticText의 차이점은 위에 주석에 써 놓은 대로입니다.
실제 적용에서는 둘 간에 차이는 그다지 있어 보이지 않습니다.
TStaticText는 표준적인 static text 윈도 클래스를 래핑하여 VCL화 한 것이고,
TLabel 은 VCL 특성에 맞게 새로 디자인 된 레이블입니다.

척 보면 아실만한 내용들이라 군더더기 설명은 마칩니다.
장성호 [nasilso]   2008-08-04 15:28 X
그런데 이걸 어이다가 쓰죠?

Non-Visual 컴포넌트같은경우에 SendMessage로 메세지를 받고 싶을때는
이걸 쓰면 좋지만..

기존에 TGraphicControl을 상속받은 Control에 굳이 Handle을 갖게 할필요가 있는것인지요?

잘 몰라서...
김태선 [cppbuilder]   2008-08-04 20:09 X
꼭 어디에 써야 한다는 목적의식에서 예를 보인 것은 아니고요
필요할때 긁어다 쓸수 있게 한 것입니다.

살다보면 핸들이 필요할 때도 생기는 법이죠.
이길남.HoPe [miru0418]   2008-08-05 12:51 X
감솨합니당...이전에는 클래스를 맹거놓구 핸들 맹그는 방법을 몰라서리
메인 폼에서 메세지를 받아서 처리하는 방법을 썼습니다.
바로 적용해서 사용해보니...인제 제대로 된 객체 클래스를 맹겄습니당..ㅜㅜ

+ -

관련 글 리스트
162 핸들이 없는 컴포넌트가 핸들 갖기와 TLabel과 TStaticText의 차이점. 김태선 17177 2008/08/03
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.