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
[123] Edit 컨트롤(TEdit, TDbEdit)의 ReadOnly 보완하기
김태선 [cppbuilder] 13012 읽음    2007-03-29 23:06
//---------------------------------------------------------------------------

#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에서 실험되었습니다.

그럼.
김태선 [cppbuilder]   2008-08-14 04:31 X
그런데 꼼수로 작은 패널위에 TEdit  컨트롤을 올리고
패널을 Enabled 을 false로 놓음으로써 코드 한줄 동원하지 않고
거의 비슷한 결과를 얻을 수 있습니다.

+ -

관련 글 리스트
123 Edit 컨트롤(TEdit, TDbEdit)의 ReadOnly 보완하기 김태선 13012 2007/03/29
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.