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

C++빌더 Q&A
C++Builder Programming Q&A
[45442] Re:TCustomControl에서 키입력 받기에 질문이 있습니다.?
박지훈.임프 [cbuilder] 1289 읽음    2006-06-26 04:38
일단... 질문하신 문제의 원인은, 만드신 컴포넌트에 키 관련 이벤트가 없기 때문입니다.
OnKeyDown이라는 이벤트를 만들었으니 동작해야 하는 거 아니냐고 생각하시겠지만, 키 관련 이벤트는 컴포넌트 개발자가 만드는 것이 아니라 VCL에 이미 있는 것을 노출시키는 것 뿐입니다. 새로 이벤트를 만든다고 해도 그 이벤트를 호출해주는 부분이 있어야 동작할텐데, 장동훈님이 만드신 OnKeyDown 이벤트는 어디에도 그걸 호출해주는 코드가 없지요?

따라서, 다음 부분을,
__property TKeyEvent OnKeyDown = {read=FOnKeyDown, write=FOnKeyDown};
이렇게 바꾸시면 됩니다.
__property OnKeyDown;

다시 말하지만 OnKeyDown 이벤트는 이미 VCL에 있습니다. 그런데 protected로 되어 있죠. 그래서 이미 존재하는 프로퍼티의 비저빌리티를 __published로 바꾸기만 하면 되므로, 그냥 __published 섹션에 __property OnKeyDown으로 선언하는 것만으로 키 속성이 동작하게 됩니다.

그런데 이것만으로는 (실제로는 동작하는데) 동작하지 않는 것처럼 보일 겁니다. 그것은, 포커스를 받을 방법이 전혀 없기 때문입니다. 특정 컨트롤에 포커스를 주는 방법은 키보드의 Tab키를 이용하는 방법과 마우스로 클릭하는 방법 두가지가 있는데, 두가지 모두 처리를 안하셨지요.

키보드의 Tab키를 받으려면, TabStop 프로퍼티의 값이 true여야 합니다. 이 TabOrder는 만드신 컴포넌트에 없지요? 위의 OnKeyDown 이벤트와 마찬가지로, protected로 되어 있습니다. 그래서 마찬가지 방법으로 노출시킵니다. 그리고 또 하나, TabOrder 속성도 마찬가지로 노출시킵니다. 이 두가지 속성은 항상 같이 필요합니다.
__property TabStop;
__property TabOrder;

마우스 클릭으로 포커스를 받으려면 조금 더 복잡합니다. 역시 protected 멤버인 MouseDown()를 오버라이드해서 거기서 SetFocus를 해주거나, 혹은 WM_MOUSEACTIVATE 메시지를 처리해주면서 SetFocus를 해야 합니다. 조금이나마 더 쉬운 MouseDown() 방법을 소개해드리죠.

헤더파일에 선언을 추가합니다.
protected:
    DYNAMIC void __fastcall MouseDown(TMouseButton Button, Classes::TShiftState Shift, int X, int Y);

그리고 cpp 파일에 바디를 만듭니다.
void __fastcall Tfilewin::MouseDown(TMouseButton Button, Classes::TShiftState Shift, int X, int Y)
{
    TCustomControl::MouseDown(Button, Shift, X, Y);
    SetFocus();
}

이제 원하시는, 키보드 입력을 받을 수 있는 모든 처리가 다 된 것입니다.

그런데.. 그 외에도, 만드신 코드를 보면 손볼 곳이 한두군데가 아닙니다. 예를 들어, Paint() 함수는 원래 컴포넌트가 그려질 필요가 있을 때마다 자동으로 호출되어 그려지길 바라셨을텐데, 아마 안되어서 //kview->Paint(); 이런 식으로 외부에서 호출해주도록 만드신 거 같습니다. 원래 Paint() 함수는 자동으로 호출되어 언제든 필요할 때마다 그려주는 함수인데, 장동훈님이  만든 컴포넌트에서는 자동으로 호출되지 않은 것은 오버라이드를 하지 않고 같은 이름의 새 함수를 만들었기 때문입니다. 오버라이드되도록 하려면 헤더의 선언부에서 앞에 virtual을 붙여줘야 합니다. 그리고 protected 섹션에 두는 것이 좋습니다.

또 한가지, Caption 속성을 직접 만드셨는데요. 이 Caption 속성도 기본적으로 있지만 노출되지 않은 것이므로, 역시 __property Caption이라고만 선언해주면 속성이 생깁니다.

그리고 ControlState는 일반적인 목적으로 컴포넌트 개발자가 세팅해서는 안됩니다. 이 속성은 이름 그대로 컴포넌트의 순간적인 '상태'를 가지고 있는 것이므로, 값을 읽을 필요는 있을 수 있지만 써넣는 경우는 없습니다. 이 속성에 값을 함부로 써넣으면 컴포넌트가 오동작할 수 있습니다.

그 외에도 수정하는 편이 나은 곳이 몇 군데 더 있는데... 이미 강좌 수준으로 너무 주저리주저리 썼기 때문에 더 길게 쓰지는 않겠습니다.

컴포넌트 하나 만드는데 왜 이렇게 많은 일이 필요하냐고 생각하실 수 있겠습니다만, 그건 장동훈님이 스스로 '밑바닥부터 새로 만들겠다'라고 결심하셨기 때문입니다. TCustomControl은 밑바닥부터 완전히 새로 구현하기 위해 컨트롤의 가장 기초적인 뼈다귀만 만들어져 있는 클래스입니다. 개발자가 직접 선택해서 노출시킬 수 있도록 거의 대부분의 표준 속성 및 이벤트들이 숨겨져 있지요. 좀더 쉽게 하시고 싶으시다면 기존의 다른 컨트롤들을 상속받으면 되죠.

그럼...


장동훈 님이 쓰신 글 :
: 안녕하세요...
: 몇일전부터 TCustomControld을 상속받아서 컴퍼넌트 공부중에 있습니다..
: 근데 다름이 아니라 help와 여기의 질/답을 검색해서 화면에 text를 찍는것 까지는 성공을 하였습니다.
:
: 그러나 키보드입력 처리부분을 하는도중 form에서 keypreview속성을 true로 주고
: 키입력부분을 처리하여서 상속받는 컴퍼넌트 paint 부분에서 다시 그려주게 했습니다.
: 그런데 제가 만든 컴퍼는트를 제외하고는 모두다 키입력을 받는데 제것만 못받더군여,
:
: 그래서 어제부터 계속 델마당과 함께 검색을 하다 도져히 알수가 없어서 이렇게 질문 드립니다.
: 소스를 첨부하겠습니다..
:
: 현제 동적으로 할당해서 사용하고 있습니다..
:
: -# 헤더 파일
: //---------------------------------------------------------------------------
:
: #ifndef kfilewinH
: #define kfilewinH
: //---------------------------------------------------------------------------
: #include <SysUtils.hpp>
: #include <Classes.hpp>
: #include <Controls.hpp>
: //---------------------------------------------------------------------------
: class PACKAGE Tfilewin : public TCustomControl
: {
: private:
:     AnsiString gCaption;
:     void __fastcall SetCaption(AnsiString Caption);
:
: protected:
: public:
:     __fastcall Tfilewin(TComponent* Owner);
:     __fastcall ~Tfilewin();
:     void __fastcall Paint(void);
:     TRect sRect; //선택막대 크기
: __published:
:     __property AnsiString Caption = { read = gCaption, write = SetCaption, nodefault};
:     __property TKeyEvent OnKeyDown = {read=FOnKeyDown, write=FOnKeyDown};
:
: };
: //---------------------------------------------------------------------------
: #endif
:
: ####################################################################################
: -#소스 파일
: //---------------------------------------------------------------------------
:
: #include <vcl.h>
:
: #pragma hdrstop
:
: #include "kfilewin.h"
: #pragma package(smart_init)
: //---------------------------------------------------------------------------
: // ValidCtrCheck is used to assure that the components created do not have
: // any pure virtual functions.
: //
:
: static inline void ValidCtrCheck(Tfilewin *)
: {
:     new Tfilewin(NULL);
: }
: //---------------------------------------------------------------------------
: __fastcall Tfilewin::Tfilewin(TComponent* Owner)
:     : TCustomControl(Owner)
: {
:     SetBounds(0,0,400,400);
:     //sRect = Rect(1,1,ClientWidth/2 ,18);
:
:     ControlStyle = ControlStyle <<
:         csAcceptsControls <<
:         csCaptureMouse <<
:         csDesignInteractive <<
:         csClickEvents <<
:         csFramed <<
:         csOpaque <<
:         csDoubleClicks <<
:         csFixedWidth <<
:         csFixedHeight <<
:         csReplicatable <<
:         csDisplayDragImage <<
:         csReflector <<
:         csActionClient <<
:         csMenuEvents;
:
:     ControlState = ControlState <<
:         csFocusing <<
:         csLButtonDown <<
:         csClicked <<
:         csCustomPaint;
: }
: //---------------------------------------------------------------------------
: __fastcall Tfilewin::~Tfilewin()
: {
: }
: namespace Kfilewin
: {
:     void __fastcall PACKAGE Register()
:     {
:         TComponentClass classes[1] = {__classid(Tfilewin)};
:         RegisterComponents("DHtools", classes, 0);
:     }
: }
: //---------------------------------------------------------------------------
: void __fastcall Tfilewin::Paint(void)
: {
:     TColor TopColor,BottomColor;
:     TRect cRect;
:
:     Canvas->Brush->Color = clBtnHighlight;
:     Canvas->FillRect(ClientRect);
:     cRect = ClientRect;
:
:     Graphics::TBitmap *bit = new Graphics::TBitmap;
:     bit->Width = ClientWidth;
:     bit->Height = ClientHeight;
:     bit->Canvas->Brush->Color = clBtnHighlight;
:     bit->Canvas->FillRect(cRect);
:
:     for(int i=0;i<3;i++)
:         bit->Canvas->TextOutA(1,i * 14,gCaption);
:
:     sRect = Rect(1,1,ClientWidth/2 ,18);
:
:     bit->Canvas->DrawFocusRect(sRect);
:
:     Frame3D(bit->Canvas,cRect,TopColor,BottomColor,1);
:     BitBlt(Canvas->Handle,0,0,ClientWidth,ClientHeight,bit->Canvas->Handle,0,0,SRCCOPY);
:
:     delete bit;
: }
: void __fastcall Tfilewin::SetCaption(AnsiString Caption)
: {
:     if(gCaption != Caption)
:     {
:         gCaption = Caption;
:         Invalidate();
:     }
: }
:
: #############################################################################
: -# 폼에서 키보드 입력 처리 부분
: void __fastcall TForm1::kview1KeyDown(TObject *Sender, WORD &Key,
:       TShiftState Shift)
: {
:     switch(Key)
:     {
:         case VK_UP:
:             x -= 15;
:             break;
:
:         case VK_DOWN:
:             x += 15;
:             break;
:
:         case VK_LEFT:
:             y -= kview->ClientWidth/1;
:             break;
:
:         case VK_RIGHT:
:             y += kview->ClientWidth/1;
:             break;
:     }
:
:     kview->sRect = Rect(ClientRect.top + y,1,20+ClientRect.top,ClientWidth/2);
:     //kview->Paint();
:     Invalidate();
: }

+ -

관련 글 리스트
45428 TCustomControl에서 키입력 받기에 질문이 있습니다.? 장동훈 1017 2006/06/24
45442     Re:TCustomControl에서 키입력 받기에 질문이 있습니다.? 박지훈.임프 1289 2006/06/26
45445         Re:Re:답변 감사 합니다.. 장동훈 802 2006/06/26
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.