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
[130] MyCompoEditor 마이너 업데이트 - 정렬기능 추가
이정구 [appleii] 50123 읽음    2007-05-15 23:42
이번에는 MyCompoEditor 에 약간의 기능추가를 해봅니다.
MyCompoEditor 에는 글자의 Style 을 4가지로 지정할 수 있습니다.
거기에 정렬기능을 추가해 봅시다. 그리고 TSpeedButton의 사용법에 대해서도 알아봅시다.

정렬기능을 추가하려면 TAlignment 라는 Type 을 이해해야 합니다. 다음과 같이 Classes.hpp 에 선언되어 있습니다.
enum TAlignment { taLeftJustify, taRightJustify, taCenter };

taLeftJustify    왼쪽으로 정렬
taRightJustify  오른쪽으로 정렬
taCenter         가운데로 정렬


TLabel 에는 다음과 같이 Alignment 속성이 있습니다.
__property Classes::TAlignment Alignment = {read=FAlignment, write=SetAlignment, default=0};

stdctrls.pas 에는 FAlignment , SetAlignment 가 다음과 같이 되어있습니다.
FAlignment: TAlignment;

 procedure TCustomLabel.SetAlignment(Value: TAlignment);
 begin
   if FAlignment <> Value then
   begin
     FAlignment := Value;
     Invalidate;
   end;
 end;


델파이 코드여서 살짝 당황스러울수 있는데 그렇게 어렵지는 않습니다.
FAlignment: TAlignment; 

이것은 TAlignment 타입의 변수입니다. Alignment 속성에서 read 방법을 FAlignment 로 지정했습니다. 즉, 변수값을
직접 읽겠다는 것입니다.
procedure TCustomLabel.SetAlignment(Value: TAlignment);
 begin
   if FAlignment <> Value then   //인수로 넘겨받은 Value 값이 기존의 FAlignment 와 다르면
   begin
     FAlignment := Value;          //FAlignment 를 Value 값으로 바꾼다.
     Invalidate;                        //컨트롤을 다시 그린다.
   end;
 end;

SetAlignment 는 기존의 값과 다르면 값을 새로 지정하고 화면을 다시 그립니다.

C++Builder 에서는 다음과 같이 사용합니다.

Label1->Alignment = taRightJustify;  //오른쪽으로 정렬


TLabel 과 TButton 을 폼에 drop 하고 Button1 의 OnClick 이벤트 핸들러에 위와 같이 작성해서 Button1을 Click 하면 오른쪽 정렬기능이 동작하는 것을 알 수 있습니다. 물론 , Label1 의 Autosize 를 false 로 하고 길이를 쭉~ 늘려야 합니다.

별 내용도 아닌데 이렇게 장황하게 설명한 것은 동작 원리를 알려면 델파이로 작성한 VCL 코드를 봐야 하기 때문입니다.
델파이 코드에 익숙해질 필요가 있으므로 살짝 소개하는 것입니다.

그럼 이 Alignment 를 어떻게 구현할 것인가. MS-Word , HWP 등을 보면 버튼을 누르면 정렬이 이루어지는 것을 알 수 있습니다. 정렬버튼 3개를 배치하고 버튼을 누르면 정렬이 되도록 하는 것입니다. 그리고 버튼에 그림이 있는 것을 알 수 있습니다. 그림을 넣을 수 있는 버튼은 TBitBtn, TSpeedButton 이 있습니다. 이 중에서 TSpeedButton 은 눌려진 효과를 나타내는
Down 속성이 있어서 선택되었다는 것을 나타내기에 편리합니다. 




TSpeedButton 3개를 폼에 drop 하고 Shift 키와 마우스 왼쪽 버튼을 눌러서 3개를 모두 선택합니다. Object Inspector 에서
GroupIndex 를 1로 합니다. 그럼 3개의 버튼은 같은 GroupIndex 를 가지기 때문에 하나의 버튼을 누르면 눌려진 효과가
나타나고 다른 버튼들은 안눌러진 효과가 나타납니다. 즉, 한번에 하나의 버튼만 누를 수 있습니다. GroupIndex 0 은 Down
속성이 무시됩니다.

그럼 위에 그림을 올려야 합니다. Object Inspector 에서 Glyph를 선택합니다. Picture Editor 가 나타나면서 그림을 불러올
수 있는 대화상자가 나타납니다. 그런데 그림을 어떻게 찾을까요. 자료실에 glypher.exe 라는 프로그램이 있습니다. 이 프로그램을 이용하여  정렬기능을 나타내는 3개의 파일을 저장합니다. 그리고 각각의 SpeedButton 의 Glyph 에서 부르면 됩니다.




다음과 같이 폼이 나타나기 전에 해야 하는 일들을 지정한후

MyCompoEditor->Memo->Alignment = MyCompo->Alignment; //MyCompoEditor 에 선택된 컴포넌트의 정렬을 알려준다.
  if(MyCompo->Alignment == taLeftJustify) MyCompoEditor->AlignLeft->Down = true;
  if(MyCompo->Alignment == taCenter) MyCompoEditor->AlignCenter->Down = true;
  if(MyCompo->Alignment == taRightJustify) MyCompoEditor->AlignRight->Down = true;

OK 버튼을 누르면 선택된 컴포넌트에 적용하고
MyCompo->Alignment = MyCompoEditor->Memo->Alignment;


이벤트 핸들러는 다음과 같이 작성합니다.

void __fastcall TMyCompoEditorForm::AlignLeftClick(TObject *Sender)
 {
   Memo->Alignment = taLeftJustify;  //왼쪽으로 정렬
 }

 void __fastcall TMyCompoEditorForm::AlignCenterClick(TObject *Sender)
 {
   Memo->Alignment = taCenter;  //가운데로 정렬
 }

 void __fastcall TMyCompoEditorForm::AlignRightClick(TObject *Sender)
 {
   Memo->Alignment = taRightJustify;  //오른쪽으로 정렬
 }



  그리고 이번에는 선택된 컴포넌트를 타입 캐스팅하는 방법을 조금 다르게 해 봅시다. 원래 C에서는 타입캐스팅방법에 제한이 없습니다. 하지만 C++ 에서는 타입 캐스팅방법을 다양하게 지정할 수 있습니다. 그 중에서도 실행중 타입을 알 수 있는 RTTI를 이용하는 타입 캐스팅방법을 알아 봅시다. 부모 타입의 포인터를 자식타입의 포인터로 다운 캐스팅할 때 안전하게 캐스팅하는 방법이 필요합니다. 부모 타입의 포인터는 부모 클래스형 객체를 가리킬수도 있고 자식 클래스형 객체를 가리킬수도 있습니다. 부모 타입의 포인터가 부모 클래스형, 자식 클래스형 객체 모두를 가리킬수 있으므로 다운 캐스팅이 위험할 수 있습니다. 자식은 부모가 가지는 것을 상속받으므로 부모가 가진 것을 모두 가지지만 부모는 자식에게 있는 것이 없을 수 있습니다. 부모 클래스형 객체를 가리키고 있는 상태에서 자식 클래스형 포인터로 다운 캐스팅해서 자식에게만 있는 멤버를 가리키면 문제가 생깁니다. 엉뚱한 주소를 가리킬 수 있기 때문입니다. 때문에 해서는 안되는 타입 캐스팅일 경우 거부하고 안전한 경우에만 캐스팅을 허가해야 할 필요가 생깁니다. C++ 에는 이러한 용도로 쓰기위한 dynamic_cast 연산자가 있습니다. dynamic_cast 를 이용해서 약간 다르게 캐스팅해 봅시다.

dynamic_cast<TLabel*>(Component);

TComponent 형으로 객체를 생성할 일이 없으므로 굳이 이렇게 쓸 필요없이 C형식으로 캐스팅해도 되지만 한번 써먹어 봅시다.

Delphi 에서는 RTTI 타입 캐스팅을 어떻게 할까요?

Component as TLabel;

as 를 이용하여 타입 캐스팅합니다.


SpeedButton 과 Alignment 가 다음과 같이 변하는 것을 알 수 있습니다.
GroupIndex 가 0 이면 눌려지는 효과가 나타나지 않습니다. 1이상부터 나타납니다.
그리고 GroupIndex 가 같은 것끼리만 반응합니다.

오른쪽정렬~ 버튼을 누르면 Label2->Alignment = taRightJustify; 가 되어서 오른쪽으로 정렬됩니다.

김태선 [cppbuilder]   2007-05-16 20:03 X
언제나 잘 보고 있습니다. ^^;

+ -

관련 글 리스트
130 MyCompoEditor 마이너 업데이트 - 정렬기능 추가 이정구 50123 2007/05/15
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.