이경문님이 델파이로 만들어 놓은 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;
}
//---------------------------------------------------------------------------
|
"대체식" 또는 "교체식" 이 좀더 좋지 않을까?
개인적으로 "교체식"을 추천합니다.
"교체식 ImageButton" 음...
좋은 컴포넌트 감사합니다. 잘쓰겠습니다.