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

컴포넌트/라이브러리
Delphi/C++Builder Programming Components&Libraries
[531] 컴포넌트 대치방식으로 만들어진 ImageButton 컴포넌트
김태선 [cppbuilder] 11979 읽음    2008-08-06 01:17
이경문님이 델파이로 만들어 놓은  TImageButton라는 좋은 컴포넌트가 있습니다.
이걸 빌더 버전으로 컨버전 한 것입니다.

하지만 그냥 컴포넌트로 그대로 하지 않고 아래처럼 기존 TImage의 Tag값이 1000이상 값을 가질
때만 ImageButton으로 동작하게 만들었는데, 컴포넌트 대치방식 입니다.
컴포넌트 대치방식이란 용어는 기존에 없는 개념이라서 제가 처음 이 방식을 빌더에 적용해서 팁란에 올렸는데
이를 표현하기 위한 용어일 뿐입니다.

디자인은 기존 컴포넌트로 그대로 하고, 기능은 새로운 컴포넌트가 적용되는 방식이죠.
이 방식은 새로운 컴포넌트 설치 절차가 필요없기 때문에, 디자인은 편리하게 기존 방식으로 하면서도
새로운 컴포넌트의 기능을 쓰고 배포시 편리하게 소스형태로 그대로 배포할 수 있는 장점이 있습니다.
또한 소스가 다 공개라서 즉시 고쳐서 보기도 쉽습니다. 컴포넌트 재 설치 작업 같은 것은 필요 없죠.
단점은 컴포넌트로 만들어 인스톨해서 디자인할때의 직관성과 프로퍼티 운영의 편리성은 조금 떨어진다는 것입니다.
즉 추가적으로 새로 만들어지는 프로퍼티를 디자인시 지정할 수 없고, 코딩으로 지정해야 합니다.

필요하다면 컴포넌트 명칭을 바꾸고 Register 등록함수만 추가하면 간단히
기존 컴포넌트와 같은 식이 됩니다. 이 방식은 아마도 컴포넌트 개발할때 편리할 것 같네요.

빌더6는 CodeGuard가 엉망이라서 메모리가 새는지 체크하기 곤란해서,
빌더2007에서 체크해보았는데 메모리는 전혀 안새고 잘 동작합니다.
다만 이미지 버턴을 빠른 속도로 연속으로 클릭하는 경우 더블클릭 이벤트가 발생하는 등의
메시지 처리가 완벽하지 못해 MouseDown에 해당하는 그림으로 안 바뀌는 경우가 있습니다.

이 부분 버그는 잡지 않고 그냥 릴리즈 하니 필요하신 분이 고치시기 바랍니다.
물론 일반적인 버턴으로서의 응용은 실무에 써도 전혀 지장 없을 정도입니다.

하지만 이 부분이 거슬린다면 고치는 방법도 있습니다.
더블클릭으로 이미지 버턴이 이상해지지 않게 하려면
더블클릭 메시지 핸들러 아래처럼
    Perform(WM_LBUTTONDOWN, Msg.Keys, *(int *)&Msg.Pos);
버턴 클릭 메시지를 자신에게 다시 날려주는 방법을 쓰면 됩니다.
아래 이미지 버턴에는 이 코드를 적용하지 않았으나 필요하신 분이 적용하시면 될 것입니다.

기존에 TImage를 많이 사용하는 프로그램에 그대로 적용해서 해보니, 깔금하게 잘 동작하더군요.

그럼..


#ifndef __IMAGEBUTTON_H
#define __IMAGEBUTTON_H

//---------------------------------------------------------------------------
// 이미지 버턴. Tag가 1000 이상값일때만 이미지 버턴으로 동작함.
//    이미지버턴으로 동작할때는
//        MouseUp Over Down Disable시는 해당하는 그림을 지정해야 하고,
//        본래 지정해야 하는 Picture는 반드시 비게 놔둔다.

#define IMAGEBUTTON_BASE_TAG        1000

class TImage : public Extctrls::TImage
{
    typedef Extctrls::TImage  inherited;
    enum TDrawType { dtDisable, dtDown, dtOver, dtUp };

private:
    TDrawType FDrawType;
    bool FEnabled;
    Graphics::TPicture* FPictureUp;
    Graphics::TPicture* FPictureOver;
    Graphics::TPicture* FPictureDown;
    Graphics::TPicture* FPictureDisable;

    void __fastcall SetPictureUp(Graphics::TPicture* Value)
    {
        if (Tag < IMAGEBUTTON_BASE_TAG) return;
        // Up 이미지를 처음에 Picture에 대입시켜서 처음화면에 보여 질 수 있도록 한다.
        FPictureUp->Assign(Value);
        if (FEnabled)
            Picture = Value;
    }
    void __fastcall SetPictureOver(Graphics::TPicture* Value)
    {
        if (Tag < IMAGEBUTTON_BASE_TAG) return;
        FPictureOver->Assign(Value);
    }
    void __fastcall SetPictureDown(Graphics::TPicture* Value)
    {
        if (Tag < IMAGEBUTTON_BASE_TAG) return;
        FPictureDown->Assign(Value);
    }
    void __fastcall SetPictureDisable(Graphics::TPicture* Value)
    {
        if (Tag < IMAGEBUTTON_BASE_TAG) return;
        FPictureDisable->Assign(Value);
        if (!FEnabled)
            Picture = Value;
    }

private:
  TNotifyEvent FOnMouseEnter;
  TNotifyEvent FOnMouseLeave;

protected:
    virtual void __fastcall Dispatch(void *Message)
    {
        if (Tag < IMAGEBUTTON_BASE_TAG)
        {
            inherited::Dispatch(Message);
            return;
        }
        switch( ((PMessage)Message)->Msg )
        {
            case CM_MOUSEENTER :
                inherited::Dispatch(Message);
                if (!FEnabled)
                    break;
                if (FDrawType == dtOver)
                    break;
                FDrawType = dtOver;
                if (FPictureOver)
                    Picture = FPictureOver;

                if (FOnMouseEnter)
                    FOnMouseEnter(this);
                break;
            case CM_MOUSELEAVE :
                inherited::Dispatch(Message);
                OnMouseLeave();
                break;
            case WM_LBUTTONDOWN :
                inherited::Dispatch(Message);
                if (!FEnabled)
                    break;
                if (FDrawType == dtDown)
                    break;
                FDrawType = dtDown;
                if (FPictureDown)
                    Picture = FPictureDown;
                break;
            case WM_LBUTTONUP :
                inherited::Dispatch(Message);
                if (!FEnabled)
                    break;
                if (FDrawType == dtDisable)
                    break;
                FDrawType = dtDisable;
                if (FPictureUp)
                    Picture = FPictureUp;
                break;
            default:
                inherited::Dispatch(Message);
                break;
        }
    }
    void __fastcall OnMouseLeave()
    {
        if (!FEnabled)
            return;
        if (FDrawType == dtUp)
            return;
        FDrawType = dtUp;
        if (FPictureUp)
            Picture = FPictureUp;

        if (FOnMouseLeave)
            FOnMouseLeave(this);
    }
    virtual void __fastcall SetEnabled(bool Value)
    {
        inherited::SetEnabled(Value);
        FEnabled = Value;
        if (Tag < IMAGEBUTTON_BASE_TAG)
            return;
        if (FEnabled && FPictureUp)
        {
            FDrawType = dtUp;
            Picture = FPictureUp;
        }
        if (!FEnabled && FPictureDisable)
        {
            FDrawType = dtDisable;
            Picture = FPictureDisable;
        }
    }

public:
    __fastcall virtual TImage(TComponent* Owner) : inherited(Owner)
    {
        FDrawType = dtUp;
        Enabled = true;
        FPictureUp = new TPicture;
        FPictureOver = new TPicture;
        FPictureDown = new TPicture;
        FPictureDisable = new TPicture;
        FOnMouseEnter = NULL;
        FOnMouseLeave = NULL;
    }
    __fastcall virtual ~TImage()
    {
        delete FPictureUp;
        delete FPictureOver;
        delete FPictureDown;
        delete FPictureDisable;
    }
    // CM_MOUSE_LEAVE 이벤트가 발생하지 않을 수도 있다.
    // 이런 경우 프로그램에서 직접 MouseLeave를 호출하도록 한다.
    void __fastcall MouseLeave(void)
    {
        OnMouseLeave();
    }

__published:
    __property bool Enabled = { read=FEnabled, write=SetEnabled, default=1 };
    __property Graphics::TPicture* PictureUp = { read=FPictureUp, write=SetPictureUp };
    __property Graphics::TPicture* PictureOver = { read=FPictureOver, write=SetPictureOver };
    __property Graphics::TPicture* PictureDown = { read=FPictureDown, write=SetPictureDown };
    __property Graphics::TPicture* PictureDisable = { read=FPictureDisable, write=SetPictureDisable };
};
#define TImage            ::TImage

#endif



#ifndef TImageButtonH
#define TImageButtonH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <Graphics.hpp>

#include "ImageButton.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
    TImage *Image1;
    TImage *Image2;
    TImage *Image3;
    TImage *Image4;
    TImage *Image5;
    void __fastcall FormCreate(TObject *Sender);
private:    // User declarations
public:        // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif



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

#include <vcl.h>
#pragma hdrstop

#include "TImageButton.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    Image1->PictureUp = Image2->Picture;
    Image1->PictureOver = Image3->Picture;
    Image1->PictureDown = Image4->Picture;
    Image1->PictureDisable = Image5->Picture;
}
//---------------------------------------------------------------------------
장성호 [nasilso]   2008-08-07 17:40 X
"대치방식" 보다는?

"대체식"  또는 "교체식" 이 좀더  좋지 않을까?
개인적으로 "교체식"을 추천합니다.

"교체식 ImageButton" 음...

좋은 컴포넌트 감사합니다. 잘쓰겠습니다.
김태선 [cppbuilder]   2008-08-07 19:29 X
교체식이 더 나은 용어 같네요.

앞으로는 교체식이 하겠습니다. ^^;

+ -

관련 글 리스트
531 컴포넌트 대치방식으로 만들어진 ImageButton 컴포넌트 김태선 11979 2008/08/06
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.