//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
/*
Edit 컨트롤(TEdit, TDbEdit)의 ReadOnly 보완하기
출처 : 델파이 버전, 델마당의 이경환님(단디)
http://www.delmadang.com/cwb-bin/CrazyWWWBoard.exe?db=dmdlec3&mode=read&num=4653&page=1&backdepth=1
포팅 : C++빌더 버전 , 볼랜드포럼의 김태성
2007.4.29
아래 주석은 이경환님의 주석 그대로 입니다.
//---------------------------------------------------------------------------
Edit 컨트롤(TEdit, TDbEdit)의 Enabled:= False 보완하기
일반적으로 TEdit나 TDBEdit 같은 컨트롤들을 쓰면서, 사용자가 입력하는 것을 막으려면 Enabled 속성을 False 로 주거나 혹은, ReadOnly 속성을 True 로 주게 됩니다.
물론, 그렇게 사용해도 상관은 없지만, Enabled 속성을 False로 해 놓으면 회색빛으로 보기가 별로 안 좋고, 내용자체를 복사 따위의 용도로 선택이 불가능 합니다.
또한, ReadOnly를 True로 해 놓으면 커서가 계속 깜박이게 되므로, 사용자들이 무심코 먼가 입력을 하려한다는 문제가 있습니다.
그런데, html코드에서 {input type=text} 의 태그에 대하여 readonly 속성을 readonly로 해 놓으면, 인터넷 익스플로러에서 커서는 안 보이지만, 사용자 선택이 가능합니다.
html의 readonly 속성의 작동 방식을 델파이에서도 사용할 수 있는 예제입니다.
*/
class TEdit : public Stdctrls::TEdit
{
typedef Stdctrls::TEdit inherited;
private:
protected:
// 컴퍼넌트가 로딩될 때 초기화
// CreateParams에서 적용하지 않고 Create에서 적용하면 반영이 되질 않습니다.
virtual __fastcall void CreateParams(TCreateParams& Params)
{
// ReadOnly 일때는 Tab 키로 포커스를 받지 못하게 합니다.
inherited::CreateParams(Params);
TabStop = ! ReadOnly;
// 칼라지정.
if (ReadOnly)
Color = clYellow;
else
Color = clWindow;
}
DYNAMIC void __fastcall DoEnter()
{
inherited::DoEnter();
if (ReadOnly)
CreateCaret(Handle, 0, 0, 0);
}
DYNAMIC void __fastcall DoExit()
{
inherited::DoExit();
CreateCaret(Handle, (void *)1, 1, 1);
}
DYNAMIC void __fastcall Change()
{
inherited::Change();
if (ReadOnly)
CreateCaret(Handle, 0, 0, 0);
}
// 이 부분은 마우스로 내용을 드래그할 때 캐럿이 생기는 것을 막습니다.
DYNAMIC void __fastcall MouseUp(TMouseButton Button, TShiftState Shift, int X, int Y)
{
inherited::MouseUp(Button, Shift, X, Y);
if (ReadOnly)
CreateCaret(Handle, 0, 0, 0);
}
// ReadOnly 속성이 변경되었을 때...
// ReadOnly 속성이 바뀔 때 마다 vcl에서 em_setreadonly라는 메세지를 핑핑~ 날려줍니다.
// em_ 으로 시작하는 메세지들을 잘 보면, 윈도우 자체 메세지와 별도로 vcl에서 많은 메세지들을 보내줍니다.
// 언제 어떤 메세지들을 보내는지 잘 보면, 경우에 따라 많은 도움이 될 것입니다.
virtual void __fastcall EM_SetReadonly(TMessage& Msg)
{
// ReadOnly 일때는 Tab 키로 포커스를 받지 못하게 합니다.
TabStop = !ReadOnly;
// 이 아래 코드는 용도에 맞게 고쳐 쓰세요~
if (ReadOnly)
// ReadOnly = true 이면 노란색 배경.
Color = clYellow;
else
// ReadOnly = false 이면 기본 색.
Color = clWindow;
}
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(EM_SETREADONLY, TMessage, EM_SetReadonly);
END_MESSAGE_MAP(Stdctrls::TEdit);
public:
};
#define TEdit ::TEdit
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
여기서 부터는 저의 주석입니다.
델마당에 흥미로운 강좌가 있어 C++빌더 버전으로 바꾸어 보았습니다.
이를 위해 기존의 TEdit 컴포넌트를 대치할 새로운 TEdit 컴포넌트를 기존 TEdit 컴포넌트를 상속받아
만들었습니다.
사실 델파이 코드를 C++빌더 코드로 바꾼 것이지요.
델파이는 C++빌더와 유사한 점이 많지만 C++ 나름대로 특성이 강하므로 이에 맞게 바꾸어 주어야 합니다.
코드는 위의 설명으로 충분할 것이고요,
다만 클래스 선언을
class TEdit : public Stdctrls::TEdit
라고 했죠.
델파이 대로라면
class TExEdit : public Stdctrls::TEdit
식으로 해야 하는데 이렇게 하면 TExEdit 컴포넌트가 되니, 컴포넌트를 설치해서 사용해야 합니다.
저는 그냥 간단히 테스트 할 목적이므로 위처럼 했습니다.
이렇게 하고 아랫줄의
#define TEdit ::TEdit
를 하면 기존 TEdit 컴포넌트로 화면 디자인을 해도
여기에서 정의한 새로운 컴포넌트로 인식되게 됩니다.
이는 저의 이전 강좌에서 컴포넌트 대치하는 방법 4가지 중에 하나이니, 자세히 알고픈 분은
그 강좌를 보시기 바랍니다.
델파이처럼
class TExEdit 로 정의하고
typedef TExEdit TEdit;
식으로 하면 *.dfm 에 있는 TEdit 는 새로운 TEdit 를 인식하여 링크하지 않고
Stdctrls::TEdit 와 링크하므로
위처럼 TEdit 를 재정의 하는 식으로 한 것입니다.
물론 완전히 새로운 컴포넌트를 만든다는 개념으로 한다면
그냥 새로운 컴포넌트 명칭을 주는게 편리하겠죠.
새로운 컴포넌트로 등록하실 분은 위 소스에서
class TExEdit : public Stdctrls::TEdit
식으로 새로운 컴포넌트 명을 주고
컴포넌트 등록 함수를 하나 만들어 주면 될 것입니다.
위 코드 테스트는 새로운 프로젝트를 선택한 뒤 소스를 긁어서 실행해 보면 됩니다.
이때 화면에 TEdit 컴포넌트를 2개 떨어뜨리고
한쪽에는 ReadOnly 를 True로 해주시고 난뒤 실행해보면
기존 TEdit 컴포넌트와의 차이점을 한눈에 아실 것입니다.
위 코드는 C++빌더 6에서 실험되었습니다.
그럼.
패널을 Enabled 을 false로 놓음으로써 코드 한줄 동원하지 않고
거의 비슷한 결과를 얻을 수 있습니다.