저작권에 대한 공지
이 문서에 포함된 모든 글과 소스 코드는 작자인 저 김성동의 지적 재산이지만 무단으로 배포하거나 책이나 강의 교재등을 위한 복제 등 저작권을 저해하는 행위를 제외하고는 자유롭게 사용할 수 있습니다.
또한 이 페이지에 대한 링크는 자유롭게 할 수 있으나 전문을 전제하는 일은 허용하지 않습니다.


2. 콤포넌트 개발 실전

2.1. 개요

이번 장에서는 1장에서 공부한 콤포넌트를 만들기 위한 기초 지식을 바탕으로 간단한 콤포넌트들을 직접 만들어 보도록 하겠다...

2.2. 콤포넌트 개발 과정

콤포넌트를 개발하는 과정은 델파이로 어플리케이션을 개발하는 것과 사뭇 다른 과정을 거친다. 어플리케이션을 개발할 때는 대부분의 경우 델파이 File|New Application 메뉴를 선택해서 어플리케이션의 골격을 생성한 다음 필요한 각종 폼을 생성한다. 그리고 생성된 폼을 적절하게 설계하고 비즈니스 로직에 따라 이벤트 핸들러를 작성해 주고 나서 컴파일 하면 된다. 하지만 콤포넌트를 개발할 때에는 먼저 어떤 콤포넌트를 만들고자 하는지에 따라 부모 클래스를 결정해야 하고 일일이 파생된 클래스를 구현해 주어야 한다. 그리고 실행 시와 설계 시에 콤포넌트가 목적하는 대로 동작하는지 검사하는 과정을 거친 다음 콤포넌트를 설계 시에 사용할 수 있도록 콤포넌트 팔레트에 등록도 해 주어야 한다.
개발 과정을 쉽게 이해하기 위해 간단한 콤포넌트를 하나 만들어 보겠다. 이 콤포넌트는 시스템에서 사용 가능한 글꼴에 대한 리스트를 보여 주는 리스트 박스 콤포넌트로서 화면 글꼴과 인쇄 글꼴 각각 또는 모두를 보여주도록 할 것이다. 콤포넌트의 이름은 TdpbFontListBox로 하겠다.
2.2.1. 부모 클래스 결정
부모 클래스를 결정하는 것은 콤포넌트 개발에 있어 아주 중요하다. 기존에 있는 콤포넌트에 기능을 추가해서 확장하고 싶은 경우에는 기존에 있는 많은 콤포넌트들을 부모 클래스로 결정하면 된다. TdpbFontListBox의 경우에는 리스트 박스의 기능에 글꼴 리스트만 보여 주는 기능만 추가하면 되므로 TCustomListBox 클래스를 부모 클래스로 선택하면 될 것이다. 처음부터 완전히 새로운 콤포넌트를 개발하려 한다면 이전 장의 VCL 절에서도 얘기했듯이 TComponent, TGraphicControl, TWinControl, TCustomControl 클래스 등을 부모 클래스로 사용한다.
2.2.2. 콤포넌트 작성
부모 클래스를 결정했으면 콤포넌트를 실제로 구현할 유닛 파일을 만든다. 유닛 파일은 콤포넌트 엑스퍼트를 이용하면 쉽게 만들 수 있다.
델파이 Component 메뉴에서 New Component를 선택하면 아래 그림처럼 콤포넌트 엑스퍼트가 나타난다. 먼저 부모 클래스를 선택하고 새로 만들 클래스의 이름을 입력한다. 그리고 콤포넌트를 델파이 IDE에 설치할 때 콤포넌트 팔레트의 어떤 페이지에 등록할지를 선택한다. 팔레트 페이지를 새로 만들려면 그냥 새로 만들 페이지의 이름을 입력해 준다. 그 다음 콤포넌트의 유닛 파일이름을 지정한다. 마지막으로 유닛 파일을 저장할 디렉토리가 기존 라이브러리 검색 경로에 없다면 유닛 파일이 있는 경로를 검색 경로에 입력해 준다.
콤포넌트의 이름을 지을 때는 콤포넌트의 역할을 잘 표현하는 이름을 사용한다. 그런데 아래 그림에서는 TdpbFontListBox라고 이름을 지었는데 dpb는 뭘까라고 생각하는 독자가 있을 것이다. 델파이에서 모든 클래스의 이름은 유일해야 한다. 따라서 만약에 독자가 TFontListBox라는 콤포넌트를 만들어서 배포하는데 다른 개발자가 같은 이름을 사용한다면 충돌이 발생하게 된다. 이와 같이 이름에 의해 발생하는 충돌을 최소화하고자 이 책의 제목인 Delphi Programming Bible의 약자를 사용해서 dpb라는 접두어를 붙인 것이다. 하지만 이렇게 해준다고 해서 충돌이 발생하지 말라는 법은 없다. 그래서 인터넷의 델파이 커뮤니티에서는 비록 강제성은 없지만 내가 사용하는 접두어를 등록해서 가급적이면 다른 개발자가 사용하지 않도록 해 주는 사이트(http://developers.href.com/-dpr:homepage)를 만들게 되었다. 만약에 상용 콤포넌트를 개발하는 개발자라면 이 사이트에서 접두어를 등록해 주는 것이 좋을 것이다. 예로 Raize Components는 rz, TurboPower사의 AsyncPro는 apd, Orpheus는 ovc, TopSupport사의 TopGrid는 ts를 사용한다.

그림 2-1 콤포넌트 엑스퍼트


콤포넌트 엑스퍼트를 실행해서 위의 그림처럼 입력하고 OK 버튼을 누르면 아래와 같은 코드가 생성될 것이다.

리스트 2.1 dpbFontListBox.pas
unit dpbFontListBox;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TdpbFontListBox = class(TCustomListBox)
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('dpb', [TdpbFontListBox]);
end;

end.


말이 엑스퍼티이지 실제로 해주는 건 거의 없다. 클래스의 가장 기본적인 뼈대와 콤포넌트 등록을 위한 프로시저인 Register만 만들어 준다. 때문에 굳이 콤포넌트 엑스퍼트를 사용하지 않고 새 유닛을 만들어서 직접 코딩하는 개발자들도 많다. 경제적으로 여유 있는 개발자들은 6장의 처음에 얘기한 상용 또는 공개 콤포넌트 엑스퍼트를 사용할 수도 있을 것이다.
Register 프로시저는 콤포넌트를 델파이 IDE에 등록할 때 사용하는 프로시저이다. 콤포넌트가 델파이 IDE에 정상적으로 설치되면 그 콤포넌트는 설계 시에 사용할 수 있도록 콤포넌트 팔레트에 나타난다. 콤포넌트를 등록할 팔레트 페이지의 이름과 등록할 콤포넌트 리스트를 인자로 입력해 주면 된다. 등록되지 않은 콤포넌트는 콤포넌트 팔레트에 나타나지 않기 때문에 설계 시에 사용할 수 없다. 때문에 콤포넌트를 설계 시에 사용하고 싶다면 반드시 Register 프로시저를 제공해 주어야 한다.
오브젝트 파스칼 컴파일러는 코드의 대/소문자를 구분하지 않는다. 그래서 procedure, Procedure, PROCEDURE는 모두 같은 키워드로 인식된다. 하지만 단 하나 예외가 있다. 콤포넌트를 팔레트에 등록할 때 사용되는 프로시저인 Register는 반드시 첫 글자만 대문자로 써야 한다. 왜냐하면 VCL은 볼랜드의 또 다른 RAD 툴인 C++ Builder에서도 그대로 사용하는데 대/소문자를 가리는 C++ Builder와의 호환성을 유지하기 위해 콤포넌트 등록 프로시저 Register만은 반드시 첫 글자만 대문자로 써야 한다.
새로 만들 콤포넌트의 뼈대는 콤포넌트 엑스퍼트를 이용해서 만들었으니 이제 우리가 만들려고 하는 콤포넌트의 기능을 작성해 보자. 글꼴 리스트를 보여 주는 콤포넌트이므로 글꼴 디바이스를 선택하는 프로퍼티와 현재 선택된 글꼴을 알 수 있는 프로퍼티를 추가하고 글꼴 리스트를 Items 프로퍼티에 자동으로 채워 주는 프로시저를 만들어야겠다.
Protected 영역에 아래 코드를 추가하고

procedure CreateWnd; override;
procedure FillFontList;


Public 영역에 아래 코드를 추가하고

constructor Create(AOwner : TComponent); override;
property SelectedFont : string read GetSelectedFont write SetSelectedFont;


Published 영역에 아래 코드를 추가한다.

property Device : TdpbFontDevice read FDevice write SetDevie;


여기까지 입력한 상태에서 델파이 4.0부터 제공되어 온 Code Completion 기능을 이용해 보자. 커서를 클래스가 선언된 영역 내에 있도록 이동해 주고 Shift+Ctrl+C 키를 눌러 보자. 델파이가 자동으로 구현해야할 프로시저와 함수를 Implementation 영역 아래에 만들어 주고 필요한 데이터 필드도 자동으로 만들어 준다.
다음으로 완성된 콤포넌트의 소스인 아래 리스트처럼 해당 코드를 입력하자.

리스트 2.2 완성된 dpbFontListBox.pas
unit dpbFontListBox;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Printers;

type
  TdpbFontDevice = ( dfdAll, dfdScreen, dfdPrinter );

  TdpbFontListBox = class(TCustomListBox)
  private
    { Private declarations }
    FDevice : TdpbFontDevice;

    function GetSelectedFont: string;
    procedure SetDevie(const Value: TdpbFontDevice);
    procedure SetSelectedFont(const Value: string);
  protected
    { Protected declarations }
    procedure CreateWnd; override;
    procedure FillFontList;
  public
    { Public declarations }
    constructor Create(AOwner : TComponent); override;
    property SelectedFont : string read GetSelectedFont write SetSelectedFont;
  published
    { Published declarations }
    property Device : TdpbFontDevice read FDevice write SetDevie;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('dpb', [TdpbFontListBox]);
end;

{ TdpbFontListBox }

constructor TdpbFontListBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ExtendedSelect := False;
  MultiSelect := False;
  FDevice := dfdAll;
end;

procedure TdpbFontListBox.CreateWnd;
begin
  inherited CreateWnd;
  FillFontList;
end;

procedure TdpbFontListBox.FillFontList;
var
  nIndex : Integer;
begin
  Items.BeginUpdate;
  Items.Clear;
  if (FDevice = dfdScreen) or (FDevice = dfdAll) then
    Items.AddStrings(Screen.Fonts);

  if (FDevice = dfdPrinter) or (FDevice = dfdAll) then
  begin
    for nIndex := 0 to Pred(Printer.Fonts.Count) do
    begin
      if Items.IndexOf(Printer.Fonts[nIndex]) = -1 then
        Items.Add(Printer.Fonts[nIndex]);
    end;
  end;
  Sorted := True;
  Items.EndUpdate;
  if Items.Count > 0 then
    ItemIndex := 0;
end;

function TdpbFontListBox.GetSelectedFont: string;
begin
  Result := '';
  if ItemIndex <> -1 then
    Result := Items[ItemIndex];
end;

procedure TdpbFontListBox.SetDevie(const Value: TdpbFontDevice);
begin
  if FDevice <> Value then
  begin
    FDevice := Value;
    FillFontList;
  end;
end;

procedure TdpbFontListBox.SetSelectedFont(const Value: string);
begin
  ItemIndex := Items.IndexOf(Value);
end;

end.


FillFontList 프로시저가 시스템에서 사용 가능한 글꼴 리스트를 구하는 프로시저이다. 이 프로시저에서 시스템에서 사용 가능한 글꼴 리스트는 전역 객체인 Screen과 Printer 객체의 Fonts 프로퍼티를 이용하도록 했다. CreateWnd 메소드를 오버라이드해서 처음 윈도 핸들이 생성되면 FillFontList를 호출해서 글꼴 리스트를 구하고 Device 프로퍼티의 값이 변경될 때마다 SetDevice 프로시저에서 FillFontList를 호출하도록 했다.
나머지는 1장을 꼼꼼하게 읽은 독자라면 쉽게 이해할 것이다.
2.2.3. 콤포넌트 동작 검사
콤포넌트 코드 작성을 마쳤으면 콤포넌트가 정상적으로 동작하는 지 검사해 볼 차례이다. 콤포넌트는 일반 어플리케이션과 달리 실행 시에 정상적으로 동작하는지를 검사하는 것은 물론이고 설계 시에도 정상적으로 동작하는지 검사해야한다. 실행 시 검사는 주로 Public 영역에 선언된 프로퍼티나 메소드를 검사하는 것이고 설계 시 검사는 Published 영역에 선언된 프로퍼티 즉 오브젝트 인스펙터에 나타나는 프로퍼티들이 정상적으로 동작하는 지를 검사하는 것이라고 볼 수 있다. 하지만 아직 콤포넌트를 콤포넌트 팔레트에 등록하지 않았기 때문에 어플리케이션을 개발 하듯이 콤포넌트를 팔레트에서 끌어다 폼 위에 놓고 프로퍼티를 조작해보거나 이벤트 핸들러를 작성해서 검사할 수는 없다. 그렇다면 등록하면 되지 않느냐라고 얘기할 수도 있지만 콤포넌트를 개발할 때 개발한 콤포넌트가 정상적으로 동작하는지 확인 해보지 않고 무턱대고 콤포넌트를 팔레트에 등록하면 예기치 않은 많은 문제를 발생시킬 소지가 있다. 심지어는 델파이를 정지시켜 버리고 시스템까지 재시작해야 할 경우도 생긴다. 따라서 콤포넌트를 델파이 IDE에 등록하기에 앞서 콤포넌트를 동적으로 생성해서 정상적으로 동작하는지 검사해 본다.
간단한 어플리케이션을 하나 만들어 보자. 새 어플리케이션을 하나 만들고 폼을 아래 그림과 같이 설계한다.

그림 2-2 글꼴 리스트 박스 검사 메인 폼


그리고 메인 폼의 유닛 파일을 아래 리스트와 같이 작성한다.

리스트 2.3 FontListBoxTest.pas
unit FontListBoxTest;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, dpbFontListBox;

type
  TfrmFontListBoxTest = class(TForm)
    btnNewFontListBox: TButton;
    btnGetSelectedFont: TButton;
    btnSetGulim: TButton;
    panSelectedFont: TPanel;
    procedure btnNewFontListBoxClick(Sender: TObject);
    procedure btnGetSelectedFontClick(Sender: TObject);
    procedure btnSetGulimClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    FontListBox : TdpbFontListBox;
  end;

var
  frmFontListBoxTest: TfrmFontListBoxTest;

implementation

{$R *.DFM}

procedure TfrmFontListBoxTest.btnNewFontListBoxClick(Sender: TObject);
begin
  FontListBox := TdpbFontListBox.Create(Self);
  FontListBox.Width := 133;
  FontListBox.Height := 145;
  FontListBox.Left := 144;
  FontListBox.Top := 4;
  FontListBox.Parent := Self;
end;

procedure TfrmFontListBoxTest.btnGetSelectedFontClick(Sender: TObject);
begin
  if FontListBox <> nil then
    panSelectedFont.Caption := FontListBox.SelectedFont;
end;

procedure TfrmFontListBoxTest.btnSetGulimClick(Sender: TObject);
begin
  if FontListBox <> nil then
    FontListBox.SelectedFont := '굴림';
end;

end.


위 리스트를 작성하고 나서 실행을 시키고 새 글꼴 리스트 박스 버튼과 현재 선택된 글꼴 버튼, 굴림 글꼴 선택 버튼을 차례대로 눌러 보면 아래와 같이 동작할 것이다.

그림 2-3 글꼴 리스트 박스 검사 실행 화면


이와 같이 콤포넌트를 등록하지 않은 상태에서 콤포넌트의 객체를 동적으로 생성하는 방법을 통하여 콤포넌트가 실행 시에 정상적으로 동작하는지 검사할 수 있다.
이렇게 실행 시 검사를 해서 콤포넌트가 큰 이상없이 동작한다고 생각되면 이를 콤포넌트 팔레트에 등록하고 콤포넌트가 설계 시에도 정상적으로 동작하는 지 검사해 볼 차례이다. 먼저 콤포넌트를 등록하기 전에 델파이 3.0부터 도입된 개념인 패키지에 대해 잠깐 알아 보겠다.
2.2.4. 패키지
델파이 3.0 버전이 나오면서 새로운 개념들이 많이 등장했는데 그 중에 패키지라는 개념이 있다.
대부분의 사람들이 인터넷이나 PC통신에서 파일을 다운로드 받을 때 그 파일의 크기가 클 경우보다는 작은 경우를 더 좋아할 것이다. 예를 들어 어플리케이션의 주 실행부만 변경되고 어플리케이션에 사용된 라이브러리나 콤포넌트등은 같다고 할 경우에 델파이 2.0까지만 해도 전체 프로그램을 모두 다시 설치해야만 했다. 하지만 델파이 3.0부터는 패키지를 이용해서 어플리케이션을 여러 조각으로 나누어 만들 수 있도록 해 준다. 그리고 패키지로 나누어진 어플리케이션 조각은 다른 어플리케이션에서도 같이 사용할 수 있다. 마치 DLL(Dynamic Linking Library)처럼 여러 어플리케이션이 하나의 패키지를 공유할 수 있기 때문에 시스템의 메모리와 자원을 절약할 수 있다는 얘기가 된다.
패키지가 주는 또 다른 이점은 델파이 IDE에서 콤포넌트를 설치/삭제하는 데 소요되는 시간을 줄일 수 있다는 것이다. 왜냐하면 델파이 3.0이후의 VCL은 개발자가 콤포넌트에 어떤 변경을 가한다고 해서 모든 콤포넌트를 다시 컴파일하는 것이 아니고 그 콤포넌트가 소속된 패키지만 컴파일하기 때문이다. 이 이점은 콤포넌트뿐 만이 아니고 개발자가 만든 어플리케이션에도 적용된다. 만약 프로젝트 옵션 대화상자의 Packages 페이지에 있는 "Build with runtime packages"가 선택되어 있다면 패키지에 대한 컴파일은 이미 되어 있으므로 어플리케이션 자체에 대한 컴파일만 하면 되므로 컴파일 속도가 향상될 것이기 때문이다.
비록 패키지가 표준 DLL은 아니지만(다른 컴파일러에서 사용할 수 없으니까?) 실제로 DLL이라고 볼 수 있다. 델파이는 패키지로 컴파일된 코드를 마치 실행 파일에 포함된 모듈처럼 사용할 수 있도록 일종의 매핑을 알아서 해준다. 개발자는 걱정할 필요 없이 예전에 델파이로 프로그램을 개발할 때 처럼 하면 된다.
델파이는 패키지를 컴파일할 때 DCP 확장자를 가진 파일에 심볼 정보를 저장하며 이것은 실행 파일을 컴파일할 때 패키지에 대한 정보를 얻기 위해 사용된다. 컴파일된 패키지는 델파이 3.0 때는 DPL(Delphi Packages Library) 확장자를 가졌으나 델파이 4.0부터는 BPL(Borland Packages Library) 확장자를 가진다.
모든 것은 델파이가 알아서 처리하므로 개발자가 생각해야 할 것은 어떤 모듈을 어플리케이션의 실행부에 두느냐 패키지에 두느냐만 결정하면 된다. 소스가 있는 콤포넌트를 가지고 있다면 사용자 패키지에 추가하거나 새 패키지를 만들 수 있다. 패키지를 컴파일하고 나서 설치하면 델파이 IDE의 콤포넌트 팔레트에 설치한 콤포넌트들이 나타난다. 패키지에는 콤포넌트뿐만 아니라 일반적인 루틴이나 클래스도 포함될 수 있다.
패키지를 만들고 나서 개발자는 패키지의 크기에 약간 놀랄 지도 모르겠지만 델파이는 패키지를 링크할 때 스마트 링킹(Smart Linking)을 하지 않는다. 패키지는 여러 어플리케이션에서 공동으로 사용할 수 있기 때문에 컴파일러는 콤포넌트의 어떤 루틴과 클래스가 어플리케이션에 의해서 사용될지 알 수가 없다. 그래서 델파이는 패키지를 컴파일할 때 콤포넌트의 소스 코드에 있는 모든 기능을 패키지에 넣는다. 이 때문에 패키지의 파일 크기가 커지는 것이다. 독립 어플리케이션이라면 VCL중 필요한 기능만을 링크하겠지만 패키지에는 콤포넌트의 모든 기능이 들어간다.
델파이는 IDE에 설치되는 설계 시간 패키지와 실행 패키지 두가지 종류의 패키지를 만들 수 있다.
만들고 싶은 패키지의 형식은 패키지 옵션 페이지에서 지정할 수 있다. 설계 시간 패키지의 주 기능은 어플리케이션 개발자가 사용할 콤포넌트에 대한 부가적인 도구 즉 프로퍼티 에디터나 콤포넌트 에디터 등을 제공해 줄 수 있다는 것이다. 이들 도구는 설계 시간에만 필요한 것이지 실행시에는 필요하지 않기 때문에 실행 파일에는 포함 시킬 필요가 없다.
콤포넌트를 설치하려면 콤포넌트를 기존에 존재하는 패키지나 새 패키지를 만들어서 그 패키지에 포함되도록 해서 패키지를 컴파일하여야 하며 정상적으로 컴파일된 패키지를 설치해야만 콤포넌트 팔레트에 등록된다. 이때서야 비로소 폼을 설계할 때 사용할 수 있다.
패키지에 대해서는 이 장의 마지막에서 좀 더 자세하게 알아 보겠다.
2.2.5. 설치
콤포넌트를 설치하기 위해서 콤포넌트 유닛 파일을 델파이 코드 에디터에서 열고 Component | Install Component 메뉴를 선택하면 아래 그림과 같은 대화상자가 나타난다. 먼저 콤포넌트를 기존 패키지에 설치할 것인지 아니면 새 패키지에 설치할 것인지를 결정한다. TdpbFontListBox는 새 패키지에 설치해 보자.

그림 2-4 콤포넌트 설치 대화상자


Into new package 페이지를 선택하고 설치할 콤포넌트 유닛 파일을 Unit file name 란에 입력하고 새로 만들 패키지의 이름을 입력한다. 패키지 파일은 일종의 프로젝트 파일로서 DPK 확장자를 가진다. 그리고 OK 버튼을 누르면 아래 그림처럼 패키지 프로젝트 창과 패키지를 컴파일하고 설치한다는 대화 상자가 나타난다.

그림 2-5 패키지 설치


그림 2.5에서 Yes 버튼을 누르면 패키지를 컴파일하고 정상적으로 컴파일이 완료되고 설치 작업도 마쳤다면 아래 그림 2.7과 같은 대화 상자가 나타난다.

그림 2-6 패키지 프로젝트 창




그림 2-7 패키지 설치 완료


이 대화 상자는 패키지가 정상적으로 컴파일 되었으며 패키지에 포함된 콤포넌트들을 델파이 IDE에 등록했다는 것을 알려 준다.
TdpbFontListBox는 콤포넌트 팔레트 DPB 페이지에 등록했으므로 정상적으로 등록되었다면 콤포넌트 팔레트에 아래 그림처럼 보일 것이다.

그림 2-8 등록된 TdpbFontListBox


팔레트에 등록된 TdpbFontListBox는 위의 그림처럼 콤포넌트를 나타내는 이미지가 다른 페이지에 있는 다른 콤포넌트의 이미지와 다르다는 것을 알 수 있다. 델파이는 콤포넌트의 유닛 파일이 패키지 프로젝트에 처음 추가될 때 유닛 파일과 이름은 같고 확장자만 DCR(Dynamic Component Resource)인 파일을 찾아서 패키지 파일에 같이 추가해 준다. DCR 파일은 윈도 리소스 파일이며 주로 콤포넌트가 팔레트에 등록될 때 사용할 이미지를 담고 있게 된다. 따라서 위의 경우 우리가 dpbFontListBox 파일에 대한 DCR 파일을 만들어 주지 않았으니까 델파이는 기본 이미지를 사용하고 있는 것이다. 콤포넌트 리소스 파일을 만들기 위해서는 델파이와 함께 제공되는 Image Editor를 이용한다. 콤포넌트 이미지는 24X24 크기를 가지는 비트맵 이미지로 만들며 리소스의 이름은 콤포넌트의 클래스 이름과 같도록 지정해야 한다.

그림 2-9 Image Editor


위 그림처럼 DCR 파일을 만들고 패키지를 다시 컴파일해도 팔레트에는 지정해준 콤포넌트 이미지가 나타나지 않는다. 왜냐하면 델파이는 패키지 파일에 콤포넌트 유닛 파일이 처음 추가될 때만 딱 한번 DCR 파일을 찾기 때문이다. 콤포넌트 이미지가 정상적으로 나오도록 DPB.DPK 패키지에서 dpbFontListBox.pas를 삭제한 뒤 다시 추가해서 컴파일 해 보자. 정상적으로 콤포넌트 팔레트에 콤포넌트 이미지가 나타날 것이다. 콤포넌트 유닛 파일을 삭제하고 다시 추가하는 방법 대신에 패키지 프로젝트 파일인 DPK 파일을 직접 편집해서 {$R *.RES} 행 아래에 {$R 'dpbFontListBox.dcr'} 를 추가해 주고 다시 컴파일해도 된다.

그림 2-10 정상적으로 등록된 콤포넌트 이미지


이렇게 콤포넌트가 팔레트에 등록되고 나면 다른 콤포넌트를 사용하는 것처럼 팔레트에서 콤포넌트를 폼으로 끌어다 놓고 콤포넌트의 프로퍼티들을 조작하면서 정상적으로 동작하는지를 검사할 수 있다.
TdpbFontListBox의 경우 오브젝트 인스펙터에서 Device 프로퍼티의 값을 변경했을 때 글꼴 리스트가 정상적으로 변경되는지를 보면 된다. 그런데 일반 리스트 박스 콤포넌트를 폼에 놀려 놓고 오브젝트 인스펙터를 보면 많은 프로퍼티와 이벤트가 있는데 TdpbFontListBox는 몇 개 없다. 왜 그럴까? TdpbFontListBox의 부모 클래스인 TCustomListBox와 TCustomListBox의 부모인 TWinControl은 많은 프로퍼티와 이벤트를 protected 멤버로 선언해 놓았다. 이전 장에서도 얘기했지만 이들 프로퍼티와 이벤트를 TdpbFontListBox가 사용할 수 있도록 하기 위해서는 Published 영역에 다시 선언해 주어야 한다. 그래서 TdpbFontListBox의 Published 영역에 아래와 같이 부모 클래스의 프로퍼티와 이벤트를 선언해 주고 다시 컴파일하면 된다.

property Align;
property Anchors;
property BiDiMode;
property BorderStyle;
property Color;
property Columns;
property Constraints;
property Ctl3D;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property Font;
property ImeMode;
property ImeName;
property IntegralHeight;
property ItemHeight;
property Items;
property ParentBiDiMode;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Sorted;
property Style;
property TabOrder;
property TabStop;
property TabWidth;
property Visible;
property OnClick;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnDrawItem;
property OnEndDock;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMeasureItem;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDock;
property OnStartDrag;


TdpbFontListBox는 다중 선택을 지원하지 않도록 하기 위해서 ExtendedSelect, MultiSelect 프로퍼티는 다시 선언하지 않았다. 따라서 이 두 프로퍼티는 오브젝트 인스펙터에 나타나지 않는다.

이렇게 해서 콤포넌트를 개발하는 일반적인 과정에 대해 알아 보았다. 설명이 길어 복잡해 보일 수 도 있지만 자주 해 보면 아주 간단한 작업이다. 다음 절에서는 실제로 어플리케이션을 개발할 때 사용할 수 있는 수준의 콤포넌트를 간단하게나마 개발해 보도록 하겠다.


저작권에 대한 공지
이 문서에 포함된 모든 글과 소스 코드는 작자인 저 김성동의 지적 재산이지만 무단으로 배포하거나 책이나 강의 교재등을 위한 복제 등 저작권을 저해하는 행위를 제외하고는 자유롭게 사용할 수 있습니다.
또한 이 페이지에 대한 링크는 자유롭게 할 수 있으나 전문을 전제하는 일은 허용하지 않습니다.