본문 바로가기

프로그래밍(TA, AA)/델파이

[delphi] 컴포넌트 라이브러리 사용

이 장에서는 컴포넌트 라이브러리의 개요를 살펴보고 애플리케이션 개발 중에 사용할 수 있는 컴포넌트 중 일부를 소개합니다. Delphi에는 비주얼 컴포넌트 라이브러리(VCL)와 크로스 플랫폼용 컴포넌트 라이브러리(CLX)가 모두 포함되어 있습니다. VCL은 Windows 개발용이고 CLX는 Winodws와 Linux의 크로스 플랫폼 개발용입니다. 이 두 라이브러리는 서로 다른 클래스 라이브러리이지만 유사한 점이 많습니다. CLX에 없는 객체, 속성, 메소드 및 이벤트는 "VCL 전용"으로 표시합니다.



컴포넌트 라이브러리 이해


VCL 및 CLX는 객체로 구성된 클래스 라이브러리로서 이 객체 중 일부는 애플리케이션 개발 시 사용하는 컴포넌트 또는 컨트롤입니다. 두 라이브러리는 유사한 점이 많고 동일한 객체를 많이 가지고 있습니다. VCL의 일부 객체(예: 컴포넌트 팔레트의 ADO, BDE, QReport, COM+, Web Services 및 Servers 탭에 있는 객체)는 Windows에서만 사용할 수 있는 기능을 구현합니다. 반면 모든 CLX 객체는 Winodws와 Linux에서 사용할 수 있습니다.


VCL 및 CLX 객체는 모든 필요한 데이터와 데이터를 수정하는 "메소드"(코드)를 포함하는 활성 엔티티입니다. 데이터는 객체의 필드와 속성에 저장되고 코드는 필드와 속성값에 작용하는 메소드들로 구성됩니다. 각 객체는 "클래스"로 선언됩니다. 모든 VCL 객체와 CLX 객체는 오브젝트 파스칼에서 개발하는 객체를 비롯해서 TObject라는 조상 객체의 자손입니다.


객체의 서브셋은 컴포넌트입니다. 컴포넌트는 폼 또는 데이터 모듈에 두고 디자인 타임에 처리할 수 있는 객체입니다. 컴포넌트는 컴포넌트 팔레트에 나타납니다. 코드를 작성하지 않고 컴포넌트의 속성을 지정할 수 있습니다. 모든 VCL 또는 CLX 컴포넌트는 TComponent 객체의 자손입니다.


컴포넌트는 다음과 같은 이유 때문에 진정한 객체 지향 프로그래밍(OOP)으로 구현된 객체라고 볼 수 있습니다.


  • 데이터와 데이터 액세스 함수의 집합을 캡슐화합니다.
  • 조상 객체로부터 데이터와 행동을 상속받습니다.
  • 다형성이라는 개념을 통해 같은 조상에서 파생된 다른 객체와 상호 교환할 수 있습니다.


대부분의 컴포넌트와 달리 객체는 컴포넌트 팔레트에 나타나지 않습니다. 그 대신 기본 인스턴스 변수는 객체의 유닛에서 선언되거나 사용자가 자체적으로 선언해야 합니다.


컨트롤은 런타임에 사용자가 볼 수 있는 특별한 종류의 컴포넌트입니다. 컨트롤은 컴포넌트의 부분 집합입니다. 또한 컨트롤은 애플리케이션이 실행 중일 때 볼 수 있는 비주얼 컴포넌트입니다. 모든 컨트롤은 Height나 Width와 같은 비주얼한 속성을 지정하는 공통의 속성을 가집니다. 모든 컨트롤이 공통적으로 가지는 속성, 메소드 및 이벤트는 TControl에서 상속됩니다.


크로스 플랫폼 프로그래밍 및 Windows와 Linux 환경 간의 차이점에 대한 자세한 내용은 10장 "크로스 플랫폼 개발을 위한 CLX 사용"을 참조하십시오. 프로그래밍 중에 온라인 도움말을 사용하여 VCL 및 CLX의 모든 객체에 대한 자세한 참조 자료에 액세스할 수 있습니다. 코드 에디터 내에서 객체의 아무 곳에나 커서를 놓은 다음 F1 키를 누르면 VCL 또는 CLX 컴포넌트에 대한 도움말이 나타납니다.


Kylix를 사용하여 크로스 플랫폼 애플리케이션을 개발하는 경우, Linux 환경에 맞게 제작된 개발자 안내서가 Kylix에 포함되어 있습니다. Kylix 온라인 도움말에서 이 매뉴얼을 참조하거나 Kylix 제품과 함께 제공된 이 매뉴얼의 인쇄본을 참조할 수 있습니다.



속성, 메소드 및 이벤트


VCL 및 CLX는 모두 애플리케이션을 신속하게 개발할 수 있는 Delphi IDE에 연결된 객체 계층을 구성합니다. 두 컴포넌트 라이브러리의 객체는 속성, 메소드 및 이벤트에 기반합니다. 각각의 객체는 데이터 멤버(속성), 데이터에 작동하는 함수(메소드), 클래스의 사용자들과 상호 작용하는 방법(이벤트)을 포함합니다. VCL이 오브젝트 파스칼에서 작성되는 반면, CLX는 C++ 클랫 라이브러리인 Qt에 기반합니다.



속성

속성은 객체의 비주얼한 행동 또는 작동에 영향을 주는 객체의 특성입니다. 예를 들어, Visible 속성은 객체가 애플리케이션 인터페이스에서 보이는지 여부를 결정합니다. 속성을 잘 디자인하면 컴포넌트를 유지 관리하기가 쉽고 다른 사용자가 쉽게 사용할 수 있습니다.


속성의 장점은 다음과 같습니다.


  • 런타임에만 사용 가능한 메소드와는 달리 디자인 타임에 속성을 보고 변경할 수 있으며 IDE에서 컴포넌트가 변경될 때 즉시 피드백을 얻을 수 있습니다.
  • Object Inspector에서 속성에 액세스하여 객체 값을 비주얼하게 수정할 수 있습니다. 디자인 타임에 속성을 설정하여 코드를 직접 작성하는 노력을 줄이고 코드 유지관리를 쉽게합니다.
  • 데이터가 캡슐화되어 있으므로 데이터가 보호되며 실제 객체에 private으로 사용됩니다.
  • 값을 얻고 설정하는 실제 호출은 메소드이므로 특별한 처리를 수행하여 객체의 사용자에게 보이지 않도록 할 수 있습니다. 예를 들어, 데이터는 테이블에 상주할 수 있지만 프로그래머에게 일반적인 데이터 멤버로 나타날 수 있습니다.
  • 속성에 액세스하는 동안 이벤트를 트리거하거나 다른 데이터를 수정하는 로직을 구현할 수 있습니다. 예를 들어, 특정 속성 값을 변경하려면 다른 속성을 수정해야 합니다. 속성에 대해 만든 메소드를 변경할 수 있습니다.
  • 속성은 가상(virtual)일 수 있습니다.
  • 속성은 단일 객체에 국한되지 않습니다. 한 객체에 대한 속성을 변경하는 것은 여러 객체들에 영향을 미칠 수 있습니다. 예를 들어, 하나의 라디오 버튼에 Checked 속성을 설정하는 것은 그룹의 모든 라디오 버튼에 영향을 줍니다.


메소드

메소드는 클래스에 연결된 프로시저입니다. 메소드는 객체의 행동을 정의합니다. 클래스 메소드는 모든 public, protected, private 속성 및 클래스의 데이터 멤버에 액세스할 수 있고 일반적으로 클래스 메소드를 멤버 함수라고 합니다.



이벤트

이벤트는 프로그램에 의해 탐지된 동작이나 발생한 사건입니다. 대부분의 최근 애플리케이션은 이벤트에 응답하도록 디자인되기 때문에 이벤트 바익이라고 합니다. 프로그램에서 프로그래머는 사용자가 다음에 수행할 일련의 동작을 예측할 수 없습니다. 사용자는 메뉴 항목을 선택하거나 버튼을 클릭하거나 또는 텍스트 일부를 표시할 수도 있습니다. 항상 똑같은 순서로 실행되는 코드를 작성하기보다는 관련되어 있는 이벤트를 처리하는 코드를 작성할 수 있습니다.

 

이벤트 호출 방법에 상관없이 Delphi에서는 이벤트를 처리하는 코드를 작성했는지 확인합니다. 사용자가 이벤트를 처리하는 코드를 작성한 경우에는 이 코드를 실행하고, 그렇지 않은 경우에는 기본 이벤트 처리행동이 실행됩니다.

 

발생 가능한 이벤트의 종류는 크게 두 개의 범주로 나눌 수 있습니다.

  • 사용자 이벤트
  • 시스템 이벤트

 

이벤트 호출 방법에 상관 없이 Delphi는 해당 이벤트를 처리하기 위한 코드를 할당했는지 확인합니다. 할당된 코드가 있으면 이를 실행하고, 그렇지 않으면 아무 일도 일어나지 않습니다.

 

 

사용자 이벤트

사용자 이벤트는 사용자에 의해 시작되는 동작입니다. 사용자 이벤트의 예로 OnClick(사용자가 마우스 버튼을 클릭했을 때), OnKeyPress(사용자가 키보드의 키를 눌렀을 때), OnDblClick(사용자가 마우스 버튼을 더블 클릭했을 때) 등을 들 수 있습니다. 이러한 이벤트는 항상 사용자의 동작과 연결됩니다.

 

시스템 이벤트

시스템 이벤트는 운영 체제가 사용자를 위해 실행하는 이벤트입니다. 시스템 이벤트의 예로 OnTimer 이벤트(이미 정의된 시간 간격이 경과할 때마다 Timer 컴포넌트는 이러한 이벤트 중 하나를 실행함), OnCreate 이벤트(컴포넌트를 만드는 중임), OnPaint 이벤트(컴포넌트나 창을 다시 그려야 함) 등을 들 수 있습니다. 일반적으로 시스템 이벤트는 사용자에 의해 직접 시작되지 않습니다.

 

 

오브젝트 파스칼 및 클래스 라이브러리


표준 파스칼에 대한 일련의 객체 지향 확장 형태인 오브젝트 파스칼은 Delphi의 랭귀지입니다. Delphi의 컴포넌트 팔레트 및 Object Inspector를 사용하면 VCL 또는 CLX 컴포넌트를 폼에 놓을 수 있고 코드를 작성할 필요 없이 이러한 컴포넌트의 속성을 처리할 수 있습니다.

 

모든 객체는 생성, 소멸 및 메시지 처리와 같은 기본 행동을 캡슐화하는 메소드를 갖는 추상 클래스인 TObject의 자손입니다. TObject는 여러 일반 클래스의 직계 조상입니다.

 

VCL 또는 CLX의 컴포넌트는 추상 클래스인 TComponent의 자손입니다. 컴포넌트는 디자인 타임 시 폼에서 처리할 수 있는 객체입니다. 런타임에 화면에 나타나는 TForm과 TSpeedButton과 같은 비주얼 컴포넌트를 컨트롤이라고 하며 TControl의 자손입니다.

 

컴포넌트 라이브러리에는 비주얼 컴포넌트 외에 많은 넌비주얼(nonvisual) 객체가 포함되어 있습니다. IDE를 통해 폼에 가져다 놓으면 프로그램에 많은 넌비주얼 컴포넌트를 추가할 수 있습니다. 예를 들어, 데이터베이스에 연결하는 애플리케이션을 작성하는 경우에 폼에 TDataSource 컴포넌트를 놓을 수 있습니다. TDataSource는 넌비주얼이지만 런타임에 나타나지 않는 아이콘에 의해 폼에 나타냅니다. Object Inspector에서 TDataSource의 속성과 이벤트를 비주얼 컨트롤의 경우와 마찬가지로 처리할 수 있습니다.

 

오브젝트 파스칼에서 고유한 클래스를 작성하는 경우, 이 클래스는 사용하고자 하는 클래스 라이브러리에 있는 TObject의 자손이어야 합니다. Windows 애플리케이션을 작성하는 중이면 VCL을 사용하고 크로스 플랫폼 애플리케이션을 작성하는 중이면 CLX를 사용합니다. 새 클래스가 필수 기능을 포함하고 클래스 라이브러리의 다른 클래스를 사용할 수 있도록 해당 기본 클래스(또는 그 자손 중 하나)에서 새 클래스를 파생시킵니다.

 

 

객체 모델 사용


객체 지향 프로그래밍은 코드 재사용과 데이터의 기능별 캡슐화를 강조하는 구조적 프로그래밍의 확장입니다. 일단 객체(또는 공식적으로는 클래스)가 생성되면 다른 프로그래머가 생성된 객체를 다른 애플리케이션에 사용할 수 있으므로 개발 시간을 단축하고 생산성을 향상시킬 수 있습니다.

 

새 컴포넌트를 만드는 방법과 컴포넌트 팔레트에 놓는 방법에 대한 자세한 내용은 40장 "컴포넌트 생성 개요"를 참조하십시오.

 

객체의 개념

객체나 클래스는 단일 유닛에서 데이터와 데이터에 대한 작업을 캡슐화하는 데이터 타입입니다. 객체 지향 프로그래밍 개념이 일반화되기 전에는 데이터와 연산(함수)은 별도의 요소로 취급되었습니다.

 

오브젝트 파스칼의 레코드 또는 C의 구조체를 이해한다면 객체를 이해하기 시작한 것입니다. 레코드는 데이터를 포함하는 필드로 구성되며 이러한 필드는 각각 고유한 타입을 가집니다. 레코드를 사용하여 다양한 데이터 요소의 모음을 쉽게 참조할 수 있습니다.

 

또한 객체는 데이터 요소의 모음입니다. 그러나 레코드와 달리 객체에는 데이터에 작동하는 프로시저와 함수가 포함됩니다. 이러한 프로시저와 함수를 메소드라고 합니다.

 

객체의 데이터 요소는 속성을 통해 액세스됩니다. VCL 및 CLX 객체의 속성은 코드를 작성하지 않고 디자인 타임에 변경할 수 있는 값을 가집니다. 속성 값을 런타임에 변경하려면 약간의 코드만 작성하면됩니다.

 

단일 유닛의 데이터와 기능의 조합을 캡슐화(Encapsulation)라고 합니다. 캡슐화 이외에도 객체지향프로그래밍은 상속(Inheritance)과 다형성(Polymorphism)이라는 특징이 있습니다.

 

 

Delphi 객체 살펴 보기


새 프로젝트가 만들어지면 Delphi에서는 사용자 지정할 수 있는 새 폼이 나타납니다. 코드 에디터에서 Delphi는 폼의 새 클래스 타입을 선언하고 새로운 폼 인스턴스를 생성하는 코드를 만듭니다. 새 Windows 애플리케이션에 대해 생성된 코드는 다음과 같습니다.

 

unit Unit;
interface 

uses Windows, Classes, Graphics, Forms, Controls, Dialogs;

type
	TForm1 = class(TForm) { The type declaration of the form begins here }
	private
		{ Private declarations }
	public
		{ Public declarations }
	ends; { The type declaration of the form ends here }
var
	Form1:TForm1;
implementation { Beginning of implementation part }
{$R *.DEM}
end. { End of implementation part and unit }

새 클래스 타입은 TForm1이고 마찬가지로 클래스인 TForm 타입에서 파생됩니다. 클래스는 데이터 필드를 가지고 있다는 점에서 레코드와 유사하지만 클래스는 객체의 데이터에 작동하는 코드인 메소드도 포함합니다. 지금까지 폼에 컴포넌트(새 객체의 필드)를 추가하지 않고 이벤트 핸들러(새 객체의 메소드)를 만들지 않았기 때문에 TForm1은 필드나 메소드가 없는 것처럼 보입니다. 타입 선언에서 보이지 않지만 TForm1은 상속된 필드와 메소드를 포함합니다.

 

다음 변수 선언은 새 타입 TForm1와 Form1이라는 변수를 선언합니다.

 

var
	Form1:TForm1;

Form1은 클래스 타입 TForm1의 인스턴스 또는 객체를 나타냅니다. 클래스 타입의 인스턴스를 두 개 이상 선언할 수 있습니다. 예를 들어, 다중 문서 인터페이스(MDI) 애플리케이션에서 여러 개의 자식 창을 만들려고 할 때 두 개 이상의 인스턴스를 선언할 수 있습니다. 각 인스턴스는 자체 데이터를 유지하지만 모든 인스턴스는 동일한 코드를 사용하여 메소드를 실행합니다.

 

폼에 컴포넌트를 추가하거나 코드를 작성하지 않아도 컴파일하고 실행할 수 있는 완전한 Delphi 애플리케이션이 이미 있습니다. 이 애플리케이션을 실행하면 빈 폼이 표시됩니다.

 

이 폼에 버튼 컴포넌트를 추가하고 사용자가 버튼을 클릭하면 폼의 색상을 변경하는 OnClick 이벤트 핸들러를 가정한다고 가정합니다.

 

사용자가 버튼을 클랙할 때 폼의 색상이 녹생으로 바뀝니다. 다음은 버튼의 OnClick이벤트에 대한 이벤트 핸들러 코드입니다.


procedure TForm1.Button1Click(Sender:TObject); {The code of the new method}
begin
  Form1.Color := clGreen;
end;

 

객체는 데이터 필드로서의 다른 객체를 포함할 수 있습니다. 폼에 컴포넌트를 둘 때마다 새 필드가 폼의 타입 선언에 나타납니다. 위에 설명된 애플리케이션을 만들면 코드 에디터에서 다음 코드를 볼 수 있습니다.

 

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender:TObject);{ New method declaration }
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation
{$R *.dfm}

procedure TForm1.Button1Click(Sender:TObject); {The code of the new method}
begin
  Form1.Color := clGreen;
end;

end.


TForm1은 폼에 추가한 버튼에 해당하는 Button1 필드를 가집니다 TButton은 클래스 타입이므로 Button1은 객체를 참조합니다.


Delphi에서 작성한 모든 이벤트 핸들러는 폼 객체의 메소드입니다. 이벤트 핸들러를 만들 때마다 메소드가 폼 객체 타입으로 선언됩니다. 이제 TForm1 타입은 TForm1 타입 선언에서 선언된 새 메소드인 Button1Click 프로시저를 포함합니다. Button1Click 메소드를 구현하는 코드는 유닛의 implementation 부분에 나타납니다.


컴포넌트 이름 변경
컴포넌트의 이름을 변경하려면 항상 Object Inspector를 사용해야 합니다. 예를 들어, 폼의 이름은 기본 Form1에서 ColorBox와 같은 보다 구체적인 이름으로 변경하고자 한다고 가정합니다. Object Inspector에서 폼의 Name 속성을 변경하면 폼의 .dfm 또는 .xfm 파일(보통은 수동으로 편집하지 않음)과 Delphi가 생성하는 오브젝트 파스칼 소스 코드에 새 이름이 자동으로 반영됩니다.



버튼에 대한 OnClick 이벤트 핸들러의 코드가 변경되지 않았다는 것에 유의하십시오. 사용자가 코드를 작성했기 때문에 그 코드를 사용자가 업데이트하고 폼에 대한 참조를 수정해야 합니다.



객체로부터 데이터와 코드 상속


설명된 TForm1 객체는 단순해 보입니다. TForm1은 하나의 필드(Button1)와 하나의 메소드(Button1Click)를 포함하지만 속성은 포함하지 않습니다. 이제 폼을 보여주거나 숨기거나 크기를 조정할 수 있고, 표준 테두리 아이콘을 추가하거나 삭제할 수 있으며, MDI(Multiple Document Interface) 애플리케이션의 일부가 되도록 폼을 설정할 수 있습니다. 폼이 컴포넌트 TForm의 모든 속성과 메소드를 상속했기 때문에 이러한 작업을 수행할 수 있습니다. 프로젝트에 새 폼을 추가할 때 TForm을 시작한 다음에 컴포넌트를 추가하고 속성 값을 변경하고 이벤트 핸들러를 작성하여 폼을 사용자 지정합니다. 객체를 사용자 지정하려면 먼저 기존 객체로부터 새 객체를 파생시킵니다. 프로젝트에 새 폼을 추가하는 경우 Delphi는 자동으로 TForm 타입으로부터 새 폼을 파생시킵니다.


  TForm1 = class(TForm)


파생된 객체는 파생시킨 객체의 모든 속성, 이벤트 및 메소드를 상속 받습니다. 파생된 객체는 자손이라고 하고, 이 자손을 파생시킨 객체는 조상이라고 합니다. 온라인 도움말에서 TForm을 조회하면 TForm이 조상으로부터 상속받은 것을 포함하여 TForm의 속성, 이벤트 및 메소드의 목록을 볼 수 있습니다. 객체는 직계 조상을 단하나만 가질 수 있지만 직계 자손을 많이 가질 수 있습니다.



유효 범위(scope) 및 한정자


유효범위는 객체의 필드, 속성 및 메소드의 액세스 가능성을 결정합니다. 객체 내에서 선언된 모든 멤버는 객체 및 객체의 자손에서 사용할 수 있습니다. 메소드의 구현 코드가 객체 선언 밖에 나타나더라도 메소드는 객체 선언 내에서 선언되기 때문에 여전히 객체의 유효 범위 내에 있습니다.


메소드가 선언된 객체의 속성, 메소드 또는 필드를 참조하는 메소드를 구현하는 코드를 작성할 때 식별자를 객체 이름으로 시작할 필요는 없습니다. 예를 들어, 새 폼에 버튼을 놓는 경우 버튼의 OnClick 이벤트에 대한 이벤트 핸들러를 다음과 같이 작성할 수 있습니다.


procedure TForm1.Button1Click(Sender:TObject);
begin
  Color := clFuchsia;
  Button1.Click := clLine;
end;


첫번째 문장은 다음과 같습니다.

  Color := clFuchsia;


Button1Click 메소드가 TForm1의 일부이기 때문에 Form1을 사용하여 Color를 한정할 필요가 없고, 따라서 메소드 몸체의 식별자는 메소드가 호출되는 TForm1 인스턴스의 유효 범위 내에 있게 됩니다. 반면 두 번째 문장은 이벤트 핸들러가 선언된 폼이 아닌 버튼 객체의 색상을 참조하므로 한정되어야 합니다.


Delphi는 각 폼에 대하여 별도의 유닛(소스 코드) 파일을 만듭니다. 다른 폼의 유닛 파일로부터 특정 폼의 컴포넌트에 액세스하려면 다음과 같이 컴포넌트 이름을 한정해야 합니다.


Form2.Edit1.Color := clLime;


Button1Click 메소드가 TForm1의 일부이기 때문에 Form1을 사용하여 Color를 한정할 필요가 없고, 따라서 메소드 몸체의 식별자는 메소드가 호출되는 TForm1 인스턴스의 유효범위 내에 있게 됩니다. 반면 두 번째 문장은 이벤트 핸들러가 선언된 폼이 아닌 버튼 객체의 색상을 참조하므로 한정되어야 합니다.


Form1의 유닛 파일에서 Form2의 컴포넌트에 액세스하려면 Form2의 유닛을 Form1 유닛의 uses 절에 추가해야 합니다.


객체의 유효 범위가 객체의 자손으로 확장됩니다. 그러나 자손 객체 내에서 필드, 속성 및 메소드를 재선언할 수 있습니다. 그러한 재선언은 상속된 멤버를 숨기거나 오버라이드합니다.


유효 범위, 상속 및 uses 절에 대한 자세한 내용은 오브젝트 파스칼 랭귀지 안내서를 참조하십시오.



private, protected, public, published 선언


필드, 속성 또는 메소드를 선언할 때 새 멤버는 키워드 private, protected, public 또는 published 중의 하나에 의해 지시되는 가시성(visibility)을 갖습니다. 멤버의 가시성은 다른 객체와 유닛에 대한 멤버의 액세스 가능성을 결정합니다.


  • private 멤버는 멤버가 선언된 유닛 내에서만 멤버에 액세스할 수 있습니다. private 멤버를 가끔 클래스 내에서 사용하여 public 또는 published로 선언된 메소드와 속성을 구현합니다.
  • protected 멤버는 멤버의 클래스가 선언된 유닛과 자손 클래스 내에서 자손 클래스의 유닛에 상관없이 액세스 할 수 있습니다.
  • public 멤버는 멤버가 속하는 객체에 액세스할 수 있는 어디에서라도, 즉 클래스가 선언된 유닛과 그 유닛을 참조하는 모든 유닛에서 액세스할 수 있습니다.
  • published 멤버는 public 멤버와 동일한 가시성을 가지지만 컴파일러는 published 멤버에 대해 런타임 타입 정보를 생성합니다. published 속성은 디자인 타임시 Object Inspector에 나타납니다.


가시성에 대한 자세한 내용은 오브젝트 파스칼 랭귀지 안내서를 참조하십시오.



객체 변수 사용


변수들이 동일한 타입이거나 할당 호환이 있는 경우, 특정 객체 변수를 다른 객체 변수에 할당할 수 있습니다. 특히 할당하는 변수 타입이 할당되는 변수 타입의 조상인 경우에 객체 변수를 다른 객체 변수에 할당할 수 있습니다. 예를 들어, 다음 TDataForm 타입 선언(VCL 전용)의 변수 선언 섹션에서는 두 변수 AForm과 DataForm을 선언합니다.


type
  TDataForm = class(TForm)
  Button1:TButton;
    Edit1:TEdit;
    DataGrid1:TDataGrid;
    Database1:TDatabase;
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  AForm:TForm;
  DataForm:TDataForm;

AForm은 TForm 타입이고, DataForm은 TDataForm 타입입니다. TDataForm은 TForm의 자손이므로 다음과 같은 할당문이 적합합니다.


AForm := DataForm;

버튼의 OnClick 이벤트에 대한 이벤트 핸들러를 작성한다고 가정합니다. 버튼을 클릭하면 OnClick 이벤트에 대한 이벤트 핸들러가 호출됩니다. 각 이벤트 핸들러에는 다음과 같이 TObject 타입의 Sender 매개변수가 있습니다.


  procedure TForm1.Button1Click(Sender:TObject);
  begin
  .
  .
  .
  end;


Sender는 TObject 타입이므로 모든 객체는 Sender에 할당될 수 있습니다. Sender의 값은 항상 이벤트에 응답하는 컨트롤이나 컴포넌트입니다. 예약어 is를 사용하여 이벤트 핸들러를 호출한 컴포넌트나 컨트롤의 타입을 찾기 위해 Sender를 테스트할 수 있습니다. 예를 들어, 다음과 같습니다.


  if Sender is TEdit then
    DoSomething
  else
    DoSomethingElse;


객체 생성, 인스턴스화 및 소멸


버튼이나 편집 상자와 같이 Delphi에서 사용하는 객체 중의 다수는 디자인 타임과 런타임 모두에서 보입니다. 공통 대화 상자와 같은 일부 객체는 런타임에만 나타납니다. 그러나 타이머나 데이터소스 컴포넌트와 같은 객체들은 런타임에도 보이지 않습니다.


사용자가 객체를 직접 만들 수도 있습니다. 예를 들어 Name, Title, HourlyPayRate 속성이 포함된 TEmployee 객체를 만들 수 있습니다. 그런 다음 HourlyPayRate의 데이터를 사용하여 급여를 계산하는 CalculatePay 메소드를 추가할 수 있습니다. TEmployee 타입 선언은 다음과 같습니다.


type
  TEmployee = class(TObject)
  private
    FName:string;
    FTile:string;
    FHourlyPayRate:Double;
  public
    property Name:string read FName write FName;
    property Title:string read FTitle write FTitle;
    property HourlyPayRate:Double read FHourlyPayRate write FHourlyPayRate;
    function CalculatePay:Double;
  end;


사용자가 정의한 필드, 속성 및 메소드 외에 TEmployee는 TObject의 모든 메소드를 상속합니다. 유닛의 interface 또는 implementation 부분에 이와 비슷한 타입 선언을 한 다음 다음과 같이 TEmployee가 TObject에서 상속받은 Create 메소드를 호출하여 새 클래스의 인스턴스를 만들 수 있습니다.


var
  Employee:TEmployee;
begin
  Employee := TEmployee.Create;
end;


Create 메소드를 생성자라고 합니다. 이 메소드는 새 인스턴스 객체에 메모리를 할당하고 객체에 대한 참조를 반환합니다.


폼에 있는 컴포넌트는 Delphi에 의해서 자동으로 생성되고 소멸됩니다. 그러나 객체를 인스턴스화하는 코드를 직접 작성하는 경우에는 객체 소멸 역시 직접해야 합니다. 모든 객체는 소멸자라고 하는 Destroy 메소드를 TObject로부터 상속 받습니다. 하지만 객체를 소멸하려면 TObject에서 상속 받은 Free 메소드를 호출해야 합니다. 왜냐하면 Free 메소드가 Destroy를 호출하기 전에 nil 참조를 확인하기 때문입니다. 예를 들어


Employee.Free

이 문장은 Employee 객체를 소멸하고 메모리 할당을 해제합니다.



컴포넌트와 소유권


Delphi는 특정 컴포넌트가 다른 컴포넌트 해제를 책임지는 기본 제공 메모리 관리 메커니즘을 갖습니다. 컴포넌트를 해제하는 컴포넌트는 해제되는 컴포넌트를 소유(own)한다고 말합니다. 소유자(owner)의 메모리가 해제되면 소유자가 소유한 컴포넌트의 메모리는 자동으로 해제됩니다. 컴포넌트의 소유자(Owner 속성 값)는 컴포넌트가 생성될 때 생성자에게 전달된 매개변수에 의해 결정됩니다. 기본적으로 폼에 있는 모든 컴포넌트는 폼이 소유하고 폼은 애플리케이션이 소유합니다. 따라서 애플리케이션이 종료되면 애플리케이션의 모든 폼과 컴포넌트의 메모리를 해제됩니다.


소유권은 TComponent와 이 컴포넌트의 자손에만 적용됩니다. 예를 들어, TStringList 또는 TCollection 객체를 사용자가 생성하는 경우 생성한 객체가 폼에 연결되어 있더라도 사용자가 객체를 해제해야 합니다.


컴포넌트의 소유자와 그 부모를 혼동하지 마십시오. 3-19 페이지의 "부모 속성"을 참조하십시오.



객체, 컴포넌트 및 컨트롤


아래 그림은 객체, 컴포넌트 및 컨트롤 사이의 관계를 나타내는 상속 계층 구조를 아주 간단하게 보여줍니다.



모든 객체는 TObject로부터 상속 받으며 많은 객체들이 TComponent로부터 상속 받습니다. TControl로부터 상속 받는 컨트롤에는 런타임 시 자신을 나타내는 기능이 있습니다. TCheckBox와 같은 컨트롤은 TObject, TComponent 및 TControl의 모든 기능을 상속하고 고유한 특수 기능을 추가합니다.


다음 그림은 상속 트리의 주요 분기를 보여 주는 비주얼 컴포넌트 라이브러리(VCL)의 개요를 나타낸 것입니다. 크로스 플랫폼용 Borland 컴포넌트 라이브러리(CLX)는 거의 동일한 레벨을 갖지만 TWinControl이 TWidgetControl로 대체됩니다.

 



여러 개의 중요한 기본 클래스가 그림에 나타나 있습니다. 다음 표는 기본 클래스를 설명한 것입니다.


 클래스

 설명

 TObject

 모든 VCL 또는 CLX 객체의 기본 클래스 및 궁극적인 조상을 나타냅니다. TObject는 객체의 인스턴스 생성, 유지 관리 및 소멸과 같은 기본 기능을 수행하는 메소드를 소개하여 VCL/CLX의 모든 객체에 공통적인 기본 동작을 캡슐화합니다.

 Exception

 예외와 관련된 모든 클래스의 기본 클래스입니다. 예외는 오류 상태에 대해 일관된 인터페이스를 제공하고 애플리케이션이 오류 상태를 잘 처리하도록 합니다.

 TPersistent

 속성을 구현하는 모든 객체에 대한 기본 클래스입니다. TPersistent의 자손 클래스는 데이터를 스트림에 보내는 것을 처리하고 클래스의 할당을 허용합니다.

 TComponent

 TApplication과 같은 모든 넌비주얼(nonvisual) 컴포넌트에 대한 기본 클래스입니다. TComponent는 모든 컴포넌트의 공통 조상입니다. 이 클래스를 사용하여 컴포넌트 팔레트에 컴포넌트를 표시할 수 있고, 컴포넌트가 다른 컴포넌트를 소유할 수 있고, 컴포넌트를 폼에서 직접 처리할 수 있습니다.

 TControl

 런타임에 보이는 모든 컨트롤에 대한 기본 클래스입니다. TControl은 모든 비주얼 컴포넌트의 공통 조상이고 위치나 커서와 같은 표준 비주얼 컨트롤을 제공합니다. 이 클래스는 또한 마우스 동작에 응답하는 이벤트를 제공합니다.

 TWinControl

 widget라고도 하는 모든 사용자 인터페이스 객체의 기본 클래스입니다. TWinControl 아래의 컨트롤은 키보드 입력을 캡쳐할 수 있는 창이 있는 컨트롤입니다. CLX에서는 TwinControl이 TwidgetControl로 대체됩니다.


다음 몇 개의 단원에서는 각 분기가 포함하는 클래스 타입에 대한 일반적인 내용을 설명합니다. VCL 객체 계층 구조의 전체적인 개요는 이 제품과 함께 들어있는 VCL 객체 계층 구조 윌 차트(wall chart)를 참조하십시오. CLX에 대한 자세한 설명은 Kylix 제품 및 설명서에 포함된 CLX 객체 계층 구조 윌 차트(wall chart)를 참조하십시오.



TObject 분기


TObject 분기에는 TObject의 자손인 모든 객체들이 포함되지만 TPersistnet의 자손 객체는 포함되지 않습니다. 모든 VCL 또는 CLX 객체는 그 메소드가 생성, 소멸, 메시지 또는 시스템 이벤트 처리 등의 기본 동작을 정의하는 추상 클래스인 TObject의 자손입니다. VCL 또는 CLX 객체의 강력한 기능 대부분은 TObject에 있는 메소드에 의한 것입니다. TObject에 다음을 제공하는 메소드가 있어서 VCL 및 CLX의 모든 객체에 공통적인 기본 동작을 캡슐화합니다.


  • 객체 인스턴스가 생성되고 소멸될 때 응답하는 기능
  • 클래스 타입, 객체에 대한 인스턴스 정보 및 객체의 published 속성에 대한 런타임 타입 정보(RTTI)
  • 메시지 처리 지원(VCL 전용)


TObject는 여러 일반 클래스의 직계 조상입니다. 이 분기의 클래스들은 일시적인 클래스라는 한 가지 중요한 공통 특성이 있습니다. 이것은 클래스가 소멸되기 전에 상태를 저장하는 메소드를 가지지 않는다는 것을 의미하므로 이 클래스들이 영구적이지 않습니다.


이 분기에 있는 클래스의 주요 그룹 중 하나는 Exception 클래스입니다. 이 클래스는 0으로 나누기 오류, 파일 I/O 오류, 잘못된 변환 그리고 많은 기타 예외 상태를 자동으로 처리하여 대규모의 기본 제공 예외 클래스 집합을 제공합니다.


TObject 분기에 있는 그룹의 다른 타입은 데이터 구조를 캡슐화하는 다음과 같은 클래스들입니다.


  • TBits, 부울 값 "배열"을 저장하는 클래스
  • TList, 연결 리스트(linked list) 클래스
  • TStack, 포인터의 후입선출(LIFO) 배열을 유지 관리하는 클래스
  • TQueue, 포인터의 선입선출(FIFO) 배열을 유지 관리하는 클래스

또한 VCL에는 Windows 프린터 인터페이스를 캡슐화하는 TPrinter와 같은 외부 객체용 랩퍼(wrapper)와 시스템 레지스트리 및 여기서 작동하는 함수를 위한 저수준 랩퍼인 TRegistry가 포함되어 있습니다. 이러한 랩퍼는 Windows 환경에서만 사용됩니다.


TStream은 이 분기에서 다른 클래스 타입에 대한 좋은 예입니다. TStream은 디스크 파일, 동적 메모리 등과 같은 다양한 저장 매체로부터 읽고 쓸 수 있는 스트림 객체에 대한 기본 클래스 타입입니다.


이와 같이 이 분기에는 개발자가 매우 유용하게 사용할 수 있는 다양한 클래스 타입이 들어 있습니다.



TPersistent 분기


VCL 및 CLX의 이 분기에 있는 객체는 TComponent의 자손이 아니라 TPersistent의 자손입니다. TPersistent는 객체에 영구성을 추가합니다. 영구성은 폼 파일이나 데이터 모듈에 저장되는 것과 메모리에서 검색할 때 폼이나 데이터 모듈로 로드되는 것을 결정합니다.

이 분기에 있는 객체들은 컴포넌트의 속성을 구현합니다. 속성은 소유자(owner)가 있는 경우에 폼과 함께 로드되고 저장됩니다. 소유자는 컴포넌트여야 합니다. 이 분기에는 속성의 소유자를 결정할 수 있는 GetOwner 함수가 있습니다.


또한 이 분기에 있는 객체들은 속성이 자동으로 로드되고 저장될 수 있는 published 섹션을 포함하는 첫번째 객체입니다. DefineProperties 메소드를 사용하여 사용자는 속성을 로드하고 저장하는 방법을 지시할 수도 있습니다.


다음은 계층 구조의 TPersistent 분기에 있는 다른 클래스 들입니다.


  • TGraphicsObject는 TBrush, TFont 및 TPen과 같은 그래픽 객체의 추상 기본 클래스입니다.
  • TGraphic은 비주얼 이미지를 저장 및 표시할 수 있는 아이콘과 비트맵과 같은 객체, 즉 TBitmap, TIcon 및 Windows 개발 전용인 TMetafile의 추상 기본 클래스입니다.
  • TStrings는 문자열 목록을 나타내는 객체의 기본 클래스입니다.
  • TClipboard는 애플리케이션에서 잘라내거나 복사한 텍스트나 그래픽을 포함하는 클래스입니다.
  • TCollection, TOwnedCollection 및 TCollectionItem은 특별히 정의된 항목의 인덱스된 모음을 유지하는 클래스 입니다.


TComponent 분기


TComponent 분기는 TControl이 아닌 TComponent의 자손인 객체를 포함합니다. 이 분기에 있는 객체는 디자인 타임에 폼에서 처리할 수 있는 컴포넌트입니다. 이 객체는 다음을 수행할 수 있는 영구적인 객체입니다.


  • 컴포넌트 팔레트에 나타나고 폼 디자이너에서 변경할 수 있습니다.
  • 다른 컴포넌트를 소유하고 관리합니다.
  • 객체를 로드하고 저장합니다.


TComponent의 여러 메소드는 디자인 타임 동안 컴포넌트가 작동하는 방법과 그 컴포넌트와 함께 저장하는 정보를 지시합니다. VCL 및 CLX의 이 분기에는 스트리밍이 있습니다. Delphi는 대부분의 스트리밍 작업을 자동으로 처리합니다. 속성이 published인 경우 속성은 영구적이며 자동으로 스트리밍됩니다.


TComponent 클래스에는 VCL 및 CLX를 통해 전달되는 소유권의 개념도 있습니다. Owner와 Components 속성은 소유권 개념을 지원합니다. 각 컴포넌트는 다른 컴포넌트를 자신의 소유자로 참조하는 Owner 속성을 가집니다. 컴포넌트는 다른 컴포넌트를 소유할 수 있습니다. 이 경우에 모든 소유된 컴포넌트는 컴포넌트의 Array 속성으로 참조됩니다.


컴포넌트의 생성자는 새 컴포넌트의 소유자를 지정하는 데 사용되는 매개변수를 하나 가지고 있습니다. 전달된 소유자가 있으면 새 컴포넌트는 소유자의 컴포넌트 목록에 추가됩니다. 소유된 컴포넌트를 참조하는 컴포넌트 목록을 사용하는 것과 별도로, 이 속성은 소유된 컴포넌트의 자동 소멸 기능도 제공합니다. 컴포넌트의 소유자가 있으면 소유자가 소멸되면 소유된 컴포넌트도 함께 소멸됩니다. 예를 들어, TForm은 TComponent의 자손이므로 폼이 소유한 모든 컴포넌트는 소멸되고 컴포넌트의 메모리는 해제됩니다. 이것은 컴포넌트의 소멸자를 호출할 때 폼의 모든 컴포넌트가 제대로 해제된다는 것을 가정합니다.


속성 타입이 TComponent 또는 자손인 경우, 스트리밍 시스템은 읽을 때 해당 타입의 인스턴스를 생성합니다. 속성 타입이 TComponent가 아닌 TPersistnet인 경우, 스트리밍 시스템은 속성을 통해 사용 가능한 기존 인스턴스를 사용하고 해당 인스턴스에 대한 속성 값을 읽습니다.


폼 파일(폼에 있는 컴포넌트에 대한 정보를 저장하는 데 사용하는 파일)을 만들 때 폼 디자이너느 폼의 컴포넌트 배열에 폼의 모든 컴포넌트를 저장합니다. 각 컴포넌트는 스트림(이 경우에는 텍스트 파일)에 대한 변경된 속성을 작성하는 방법을 알고 있습니다. 반면 폼 디자니어는 컴포넌트의 속성을 폼 파일에 로드할 때 컴포넌트 배열에 있는 각 컴포넌트를 로드합니다.


이 분기에서 찾을 수 있는 클래스 타입은 다음과 같습니다.


  • TMainMenu는 폼에 대한 메뉴 바와 메뉴 바의 드롭다운 메뉴를 제공하는 클래스입니다.
  • TTimer는 타이머 기능이 들어있는 클래스입니다.
  • TOpenDialog, TSaveDialog TFontDialog, TFindDialog, TColorDialog 등은 공통적으로 사용되는 대화상자를 제공합니다.
  • TActionList는 메뉴 항목 및 버튼과 같이 컴포넌트 및 컨트롤과 함께 사용되는 동작의 목록을 유지 관리하는 클래스입니다.
  • TScreen은 애플리케이션에 의해 인스턴스와된 폼과 데이터 모듈, 활성폼, 폼의 활성 컨트롤, 화면 크기 및 해상도, 애플리케이션에 사용 가능한 커서 및 글꼴 등을 유지 관리하는 클래스입니다.

비주얼 인터페이스가 필요없는 컴포넌트는 TComponent에서 직접 파생될 수 있습니다. TTimer 장치와 같은 도구를 만들기 위해 TComponent에서 파생시킬 수 있습니다. 이러한 타입의 컴포넌트는 컴포넌트 팔레트에 있지만 런타임 시 사용자 인터페이스에 나타나지 않고 코드를 통해 액세스되는 내부 함수를 수행합니다.


CLX의 TComponent 분기에는 THandleComponent도 들어 있습니다. 이 클래스는 대화 상자나 메뉴와 같이 기본으로 사용한 Qt 객체에 대한 핸들을 요구하는 넌비주얼(nonvisual) 컴포넌트의 기본 클래스입니다.



TControl 분기


TControl 분기는 TWinControl(CLX의 경우 TWidgetControl)의 자손이 아니라 TControl의 자손인 컴포넌트로 구성됩니다. 이 분기의 객체는 애플리케이션 사용자가 런타임 시 보고 처리할 수 있는 비주얼 객체인 컨트롤입니다. 모든 컨트롤은 컨트롤의 위치, 컨트롤의 창(또는 CLX의 widget)에 연결된 커서, 컨트롤을 그리거나 이동하는 메소드 그리고 마우스 동작에 응답하는 이벤트 같은 컨트롤의 모양과 관련된 공통적인 속성, 메소드 및 이벤트를 갖습니다. 컨트롤은 키보드 입력을 받을 수 엇습니다.


TComponent가 모든 컴포넌트에 대한 행동을 정의하는 반면 TControl은 모든 비주얼컨트롤에 대한 행동을 정의합니다. 여기에는 드로잉 루틴, 표준 이벤트 및 포함 관계(containership) 등이 포함됩니다.


이 컨트롤의 두 가지 기본 타입은 다음과 같습니다.


  • 고유한 창(또는 widget)을 갖는 컨트롤
  • "부모"의 창(또는 widget)을 사용하는 컨트롤


고유한 창을 갖는 컨트롤은 "창 있는" 컨트롤(VCL) 또는 "widget 기반" 컨트롤(CLX)이라고 하며 TWinControl(CLX의 경우 TWidgetControl)의 자손입니다. 버튼과 체크 박스는 이 클래스에 속합니다.


부모 창(또는 widget)에 사용하는 컨트롤은 "그래픽" 컨트롤이라고 하며 TGraphicControl의 자손입니다. 이미지와 레이블이 이 클래스에 해당합니다. VCL에서 이러한 타입의 컴포넌트들 간의 주요한 차이점은 그래픽 컨트롤에서 유지 관리하는 창 핸들이 없어서 입력 포커스를 받을 수 없다는 것입니다. CLX의 경우 이러한 타입의 컴포넌트들 간의 주요한 차이점은 그래픽 컨트롤에 연결된 widget이 없어서 입력 포커스를 받을 수 없거나 다른 컨트롤에 포함할 수 없다는 것입니다. 그래픽 컨트롤에 핸들이 필요 없으므로 시스템 리소스에 대한 수요가 감소하고 그래픽 컨트롤을 widget 기반 컨트롤보다 더 빨리 그릴 수 있습니다.

 

TGraphicControl 컨트롤은 스스로 그려지고 다음과 같은 컨트롤을 포함해야만 합니다.

 

 컨트롤

 설명

 TImage

 그래픽 이미지를 표시합니다.

 TLabel

 폼에 텍스트를 표시합니다.

 TBevel

 빗면이 있는 액자 모양의 윤곽을 나타냅니다.

 TPaintBox

 애츨리케이션이 이미지를 그리거나 렌더링하는 데 사용할 수 있는 캔버스를 제공합니다.


여기에는 포커스를 받을 필요가 없는 공통 그리기 루틴(Repaint, Invalidate 등)을 포함한다는 것에 유의하십시오.

 

 

TWinControl/TWidgetControl 분기 


TWinControl분기(CLX에서는 TWinControl이 TWidgetControl로 대체됨)는 TWinControl의 자손인 모든 컨트롤을 포함합니다. TWinControl은 애플리케이션의 사용자 인터페이스에서 사용할 많은 항목을 비롯하여 창이 있는 모든 컨트롤의 기본 클래스입니다.


TWidgetControl은 모든 widget 기반 컨트롤 또는 widgets에 대한 기본 클래스입니다. widget은 "window"와 "gadget"을 합쳐 만든 용어입니다. widget은 애플리케이션의 사용자 인터페이스 어디에서나 사용할 수 있습니다. widget의 예로는 버튼, 레이블 및 스크롤 막대가 있습니다.


창이 있는 컨트롤과 widget 기반 컨트롤의 특징은 다음과 같습니다.


  • 두 컨트롤 모두 애플리케이션이 실행 중일때 포커스를 받을 수 있습니다.
  • 다른 컨트롤에서 데이터를 표시할 수 있지만 사용자는 키보드를 사용하여 창이 있는 컨트롤이나 widget 기반 컨트롤과 상호 작용할 수 있습니다.
  • 창이 있는 컨트롤이나 widget 기반 컨트롤은 다른 컨트롤을 포함할 수 있습니다.
  • 다른 컨트롤을 포함하는 컨트롤을 부모라고 합니다. 창이 있는 컨트롤이나 widget 기반 컨트롤만이 하나 이상의 자식 컨트롤의 부모가 될 수 있습니다.
  • 창이 있는 컨트롤은 창 핸들을 갖습니다. widget 기반 컨트롤은 연결된 widget을 가집니다.

 

TWinControl(CLX의 경우 TWidgetControl)의 자손은 포커스를 받을 수 있는 컨트롤이기 때문에 애플리케이션 사용자의 키보드 입력을 받을 수 있습니다. 이것은 더많은 표준 이벤트가 컨트롤에 적용된다는 것을 암시합니다.


이 분기에는 자동으로 그려지는 컨트롤(예: TEdit, TListBox, TComboBox, TPageControl 등)과 Delphi가 그려야 하는 사용자 지정 컨트롤(예: TDBNavigator, TMediaPlayer(VCL 전용)), TGaouge(VCL 전용) 등)이 모두 포함되어 있습니다. TWinControl(CLX의 경우 TWidgetControl)의 직계 자손은 일반적으로 편집 필드, 콤보 박스, 리스트 박스, 페이지 컨트롤 등과 같은 표준 컨트롤을 구현하므로 자신을 그리는 방법을 이미 알고 있습니다.


TCustomControl 클래스는 창 핸들은 필요로 하지만 핸들 자체를 다시 그리는 기능을 포함하는 표준 컨트롤을 캡슐화하지 않는 컴포넌트에 제공됩니다. 컨트롤이 자신을 렌더링하거나 이벤트에 응답하는 방법은 Delphi에서 완벽하게 캡슐화하므로 이 동작을 걱정할 필요는 전혀 없습니다.



TControl의 공통 속성


모든 비주얼 컨트롤(TControl의 자손)은 다음과 같은 특정 속성을 공유합니다.

  • 액션 속성
  • 위치, 크기 및 정렬 속성
  • 표시 속성
  • 부모 속성
  • 탐색 속성
  • 드래그 앤 드롭 속성
  • 드래그 앤 도킹 속성(VCL 전용)

TControl에서 상속되는 동안에 이러한 속성이 published로 선언되어 적용 가능한 컴포넌트에 대해서만 Object Inspector에 표시됩니다. 예를 들어, TImage는 Color 속성의 색이 표시되는 그래픽에 의해 결정되기 때문에 이 속성을 published로 선언하지 않습니다.



액션 속성

이를 통해 애플리케이션 상태에 따라 동작을 중앙 집중화된 단일 방식으로 설정 및 해제할 수 있을 뿐만 아니라 동작을 수행하는 공통적인 코드를 공유할 수 있습니다(예를 들어, 툴바 버튼과 메뉴 항목이 동일한 동작을 수행할 때).

  • Action은 컨트롤과 연결된 동작을 지정합니다.
  • ActionLink에는 컨트롤과 연결된 액션 링크 객체가 포함됩니다.


위치, 크기 및 정렬 속성

이 속성 집합은 부모 컨트롤 위에 놓인 컨트롤의 위치와 크기를 정의합니다.

  • Height는 세로 크기를 설정합니다.
  • Width는 가로 크기를 설정합니다.
  • Top은 위쪽 가장자리 위치를 설정합니다.
  • Left는 왼쪽 가장자리 위치를 설정합니다.
  • AutoSize는 컨트롤 크기 자체가 내용에 맞게 자동으로 바뀌는지 여부를 지정합니다.
  • Align은 컽느롤이 컨테이너(부모 컨트롤) 내에서 정렬되는 방법을 결정합니다.
  • Anchor는 컨트롤이 부모에 앵커(연결)되는 방법을 지정합니다(VCL 전용)


이 속성 집합은 컨트롤 클라이언트 영역의 높이, 너비 및 전체 크기를 결정합니다.

  • ClientHeight는 컨트롤 클라이언트 영역의 높이를 픽셀 단위로 지정합니다.
  • ClientWidth는 컨트롤 클라이언트 영역의 너비를 픽셀 단위로 지정합니다.


이러한 속성은 넌비주얼 컴포넌트에서 액세스할 수 없지만 Delphi는 폼 위에 컴포넌트 아이콘이 놓인 위치를 추적합니다. 대개는 이러한 속성을 설정 및 변경하기 위해 폼에서 컨트롤 이미지를 처리하거나 Alignment 팔레트를 사용할 것입니다. 하지만 이러한 속성은 런타임 시 변경할 수 있습니다.



표시 속성

  • 다음 속성은 컨트롤의 일반 모양을 제어합니다.
  • Color는 컨트롤의 배경색을 변경합니다.
  • Font는 텍스트의 색, 타입, 스타일 또는 크기를 변경합니다.
  • Cursor는 컨트롤 영역 안쪽으로 이동하는 마우스 포인터를 나타내는 데 사용되는 이미지를 지정합니다.
  • DesktopFont는 컨트롤에서 텍스트 작성 시 Windows 아이콘 글골을 사용하는지 여부를 지정합니다(VCL 전용).


부모 속성

애플리케이션에 걸쳐 일관된 모양을 유지하려면 부모 속성을 True로 설정하여 모든 컨트롤을 부모라고 부르는 컨테이너와 같은 모양으로 만듭니다.

  • ParentColor는 컨트롤이 색상 정보를 찾는 위치를 결정합니다.
  • ParentFont는 컨트롤이 글꼴 정보를 찾는 위치를 결정합니다.
  • ParentShowHint는 컨트롤이 도움말 힌트의 표시 여부를 찾는 위치를 결정합니다.


탐색 속성

다음 속성은 사용자가 폼에서 컨트롤 사이를 탐색하는 방법을 결정합니다.

  • Caption에는 컴포넌트의 레이블을 지정하는 텍스트 문자열이 포함됩니다. 문자열의 문자에 밑줄을 그으려면 해당 문자 앞에 앰퍼샌드를 포함합니다. 이러한 타입의 문자를 가속키라고 합니다. 사용자는 밑줄이 그어진 문자를 Alt 키를 동시에 눌러 컨트롤 또는 메뉴 항목을 선택할 수 있습니다.


드래그 앤 드롭 속성

다음 두 개의 컴포넌트 속성이 드래그 앤 드롭 동작에 영향을 미칩니다.

  • DragMode은 끌기가 시작되는 방법을 결정합니다. DragMode의 기본값은 dmManual이며 애플리케이션은 끌기를 시작하기 위해 BeginDrag 메소드를 호출해야 합니다. DragMode가 dmAutomatic이면 끌기는 마우스 버튼을 눌렀을 때 바로 시작됩니다.
  • DragCursor는 끌 수 있는 컴포넌트 위로 이동했을 때의 마우스 포인터 모양을 결정합니다(VCL 전용).


드래그 앤 도킹 속성(VCL 전용)

다음 속성은 드래그 앤 도킹 동작을 제어합니다.

  • Floating은 컨트롤이 부동인지 여부를 나타냅니다.
  • DragKind는 컨트롤 끌기가 일반적인 끌기인지, 도킹용 끌기인지 지정합니다.
  • DragMode는 컨트롤이 드래그 앤 드롭 또는 드래그 앤 도킹 동작을 시작하는 방법을 결정합니다.
  • FloatingDockSiteClass는 부동 상태일 때 컨트롤을 호스팅하는 임시 컨트롤의 클래스를 지정합니다.
  • DragCursor는 끌기 동안에 표시되는 커서입니다.
  • DockOrientation은 같은 부모에서 도킹된 다른 컨트롤을 기준으로 컨트롤이 도킹되는 방법을 지정합니다.
  • HostDockSite는 컨트롤이 도킹되는 컨트롤을 지정합니다.



TControl의 표준 공통 이벤트


VCL은 컨트롤에 대한 표준 이벤트 집합을 정의합니다. 다음 이벤트는 TControl 클래스의 일부로 선언되기 때문에 TControl에서 파생된 모든 클래스에서 사용할 수 있습니다.

  • Onclick은 사용자가 컨트롤을 클릭할 때 발생합니다.
  • OnContextPopjp은 사용자가 마우스 오른쪽 버튼으로 컨트롤을 클릭하거나 키보드 등을 사용하여 팝업 메뉴를 호출할 때 발생합니다.
  • OnCanResize는 컨트롤 크기를 조정하려는 경우에 발생합니다.
  • OnResize는 컨트롤 크기를 조정한 직후에 발생합니다.
  • OnConstrainedResize는 OnCanResize 직후에 발생합니다.
  • OnStartDock은 dkDock의 DragKind로 컨트롤 끌기를 시작할 때 발생합니다(VCL 전용).
  • OnEndDock은 객체를 도킹하거나 끌기를 취소하여 객체 끌기를 끝낼 때 발생합니다(VCL 전용).
  • OnStartDrag 는 컨트롤을 마우스 왼쪽 버튼으로 클릭한 상태에서 컨트롤이나 컨트롤에 포함된 객체를 끌기 시작할 때 발생합니다. 
  • OnEndDrag 는 객체를 끌어다 놓거나 끌기를 취소하여 객체 끌기를 끝낼 때 발생합니다. 
  • OnDragDrop 은 객체를 끌어다 놓을 때 발생합니다. 
  • OnMouseMove 는 컨트롤 위에서 마우스 포인터를 이동할 때 발생합니다. 
  • OnDblClick 은 컨트롤 위에 마우스 포인터를 놓고 기본 마우스 버튼을 더블 클릭할 때 발생합니다. 
  • OnDragOver 는 컨트롤 위에서 객체를 끌 때 발생합니다(VCL 전용).
  • OnMouseDown 은 사용자가 컨트롤 위에 마우스 포인터를 놓고 마우스 버튼을 누를 때 발생합니다. 
  • OnMouseUp 은 컴포넌트 위에 마우스 포인터를 놓고 눌렀던 마우스 버튼을 놓았을 때 발생합니다. 



TWinControl 및 TWidgetControl의 공통 속성


창이 있는 모든 컨트롤(VCL에서의 TWinControl 자손과 CLX에서의 TWidgetControl 자손)은 다음과 같은 특정 속성을 공유합니다.

  • 컨트롤에 관한 정보
  • 테두리 스타일 표시 속성
  • 탐색 속성
  • 드래그 앤 도킹 속성(VCL 적용)

TWinControl 및 TWidgetControl에서 상속되는 동안 이러한 속성이 published로 선언되며 적용 가능한 컨트롤에 대해서만 Object Inspector에 표시됩니다.


일반 정보 속성

일반 정보 속성은 TWinControl 및 TWidgetControl의 모양, 클라이언트 영역 크기 및 원점, 창에 할당된 정보, 도움말 컨텍스트 등에 대한 정보를 포함합니다.

  • ClientPrigin은 컨트롤 클라이언트 영역의 왼쪽 위 모서리의 화면 좌표를 픽셀 단위로 지정합니다. TWinControl이 아니라 TControl의 자손인 특정 컨트롤의 화면 좌표는 Left 및 Top 속성에 추가되는 해당 컨트롤 부모의 화면 좌표입니다.
  • ClientRect는 Top과 Left 속성이 0으로 설정되고 Bottom과 Right 속성이 각각 컨트롤의 Height 및 Width로 설정된 경우 사각형을 반환합니다. ClientRect는 Rect(0, 0, ClientWidth, ClientHeight)와 같습니다.
  • Brush는 컨트롤의 배경을 칠하는 데 사용되는 색과 패턴을 결정합니다.
  • HelpContext는 문맥에 맞는 온라인 도움말을 호출할 때 사용하는 컨텍스트 번호를 제공합니다.
  • Handle은 컨트롤의 창 또는 widget 핸들에 대한 액세스를 제공합니다.


테두리 스타일 표시 속성

경사 속성은 애플리케이션의 폼과 창이 있는 컨트롤에 있는 경사진 선, 상자 또는 프레임의 모양을 제어합니다.


VCL에서는 더 많은 객체가 이러한 속성을 published로 선언하지만 CLX에서는 이러한 속성 중 일부를 사용할 수 없기 때문에 더 적은 객체에서 테두리 스타일 속성이 published로 선언됩니다.

  • InnerBevel은 내부 경사 모양이 볼록, 오목 또는 평면인지 지정합니다(VCL 전용).
  • BevelKind는 컨트롤 가장자리가 경사진 경우 경사 타입을 지정합니다(VCL 전용).
  • BevelOuter는 외부 경사 모양이 볼록, 오목 또는 평면인지 지정합니다.
  • BevelWidth는 내부 및 외부 경사의 너비를 픽셀 단위로 지정합니다
  • BorderWidth는 컨트롤 테두리의 너비를 얻거나 설정하는데 사용됩니다.
  • BevelEdges는 컨트롤의 경사진 가장자리를 얻거나 설정하는 데 사용됩니다.


탐색 속성

다음 두 개의 추가적인 속성은 사용자가 폼에서 컨트롤 사이를 탐색하는 방법을 결정합니다.

  • TabOrder는 컨트롤 위치를 부모의 탭 순서로 나타내며 이 순서는 사용자가 Tab키를 눌렀을 때 컨트롤이 포커스를 받는 순서입니다. 원래 탭 순서는 컴포넌트가 폼에 추가된 순서이지만 TabOrder를 변경하여 이 순서를 변경할 수 있습니다. TabOrder는 TabStop이 True인 경우에만 의미가 있습니다.
  • TabStop은 사용자가 컨트롤에 탭을 지정할 수 있는지 결정합니다. TabStop이 True이면 컨트롤은 탭 순서를 가집니다.


드래그 앤 도킹 속성(VCL 전용)

다음 속성은 VCL 객체의 드래그 앤 도킹 동작을 관리합니다.

  • UseDockManager는 드래그 앤 도킹 작업에 도킹 관리자가 사용되는지 여부를 지정합니다.
  • VisibleDockClientCount는 창이 있는 컨트롤에서 도킹되는 가시적(visible) 컨트롤 개수를 지정합니다.
    DockManager는 컨트롤의 도킹 관리자 인터페이스를 지정합니다.
  • DockSite는 컨트롤이 드래그 앤 도킹 작업의 대상이 될 수 있는지 여부를 지정합니다.



TWinControl 및 TWidgetControl의 공통 이벤트


다음은 VCL의 TWinControl(Windows가 정의하는 모든 컨트롤도 포함) 및 CLX의 TWidgetControl에서 파생되는 모든 컨트롤에 있는 이벤트입니다. 이러한 이벤트는 모든 컨트롤에 존재하는 이벤트 이외의 추가적인 이벤트입니다.

  • OnEnter는 컨트롤이 포커스를 받으려고 할 때 발생합니다.
  • OnKeyDown은 키입력의 다운 스트로크에서 발생합니다.
  • OnKeyPress는 하나의 문자 키를 눌렀을 때 발생합니다.
  • OnKeyUp은 눌렀던 키를 놓을 때 발생합니다.
  • OnExit는 특정 컨트롤에서 다른 컨트롤로 입력 포커스가 전환될 때 발생합니다.
  • OnMouseWheel 은 마우스 휠이 회전할 때 발생합니다. 
  • OnMouseWheelDown 은 마우스 휠이 아래쪽으로 회전할 때 발생합니다. 
  • OnMouseWheelUp 은 마우스 휠이 위쪽으로 회전할 때 발생합니다. 


다음 이벤트는 도킹과 관련된 것으로서 VCL에서만 사용할 수 있습니다.

  • OnUnDock는 애플리케이션이 창이 있는 컨트롤에 도킹되는 컨트롤을 도킹 해제하려고 할때 발생합니다(VCL 전용).
  • OnDockDrop은 다른 컨트롤을 해당 컨트롤로 도킹할 때 발생합니다(VCL 전용).
  • OnDockOver는 다른 컨트롤을 해당 컨트롤로 끌어올 때 발생합니다(VCL 전용).
  • OnGetSiteInfo는 컨트롤의 도킹 정보를 반환합니다(VCL 전용).



애플리케이션 사용자 인터페이스 만들기


Delphi의 모든 비주얼 디자인 작업은 폼에서 이루어집니다. Delphi를 열거나 새프로젝트를 열 때 빈 폼이 화면에 표시됩니다. 이 폼을 사용하여 창, 메뉴 및 일반 대화 상자를 비롯한 애플리케이션 인터페이스 만들기를 시작할 수 있습니다.


버튼, 리스트 박스 등의 비주얼 컴포넌트를 폼에 배치 및 정렬하여 애플리케이션에 대한 그래픽 사용자 인터페이스의 룩앤필(look and feel)을 디자인합니다. Delphi에서는 기본이 되는 프로그래밍 세부 내용을 처리합니다. 또한 보이지 않는 컴포넌트를 폼에 놓아 데이터베이스 정보를 캡쳐하고, 계산을 수행하고, 기타 상호 작용을 관리할 수 있습니다.


6장 "애플리케이션 사용자 인터페이스 개발"에는 모달 폼을 동적으로 만들고, 폼에 매개변수를 전달하고, 폼으로부터 데이터를 검색하는 것과 같은 폼 사용에 관한 자세한 내용이 나와 있습니다.



Delphi 컴포넌트 사용


컴포넌트 팔레트에 있는 개발 환경 자체에서 많은 비주얼 컴포넌트가 제공됩니다. Delphi의 모든 비주얼 디자인 작업은 폼에서 이루어집니다. Kylix를 열거나 새 프로젝트를 열 때 빈 폼이 화면에 표시됩니다. 컴포넌트 팔레드에서 컴포넌트를 선택하여 폼에 가져다 놓습니다. 폼 위의 버튼과 리스트 박스와 같은 비주얼 컴포넌트를 정렬하여 애플리케이션 사용자 인터페이스의 룩앤필(look and feel)을 디자인합니다. 일단 비주얼 컴포넌트가 폼에 있으면 컴포넌트의 위치, 크기 및 기타 디자인 타임 속성을 조정할 수 있습니다. Delphi에서는 기본이 되는 프로그래밍 세부 내용을 처리합니다.


Delphi 컴포넌트는 기능별로 그룹화되어 컴포넌트 팔레트의 페이지에 다른 정렬되어 있습니다. 예를 들어 메뉴, 편집 상자 또는 버튼을 생성하는 컴포넌트 같이 공통으로 사용되는 컴포넌트는 컴포넌트 팔레트의 Standard 페이지에 있습니다. 타이머, 그림 상자, 미디어 플레이어, OLE 컨테이너 등의 편리한 VCL 컨트롤은 System 페이지에 있습니다.


언뜻 보면 Delphi의 컴포넌트는 다른 클래스와 비슷하게 나타납니다. 그러나 Delphi에 있는 컴포넌트와 많은 프로그래머들이 사용하는 표준 클래스 계층 구조간에 차이가 있습니다. 몇가지 차이점은 다음과 같습니다.


  • 모든 Delphi 컴포넌트는 TComponent의 자손입니다.
  • 컴포넌트는 기능을 추가하거나 변경하기 위해 서브 클래스인 "기본 클래스"로 사용하기보다는 대부분 있는 그대로 사용되고 속성을 통해 변경됩니다. 상속된 컴포넌트인 경우, 보통 기존 이벤트 핸들링 멤버 함수에 특정 코드를 추가해야 합니다.
  • 컴포넌트는 스택이 아니라 힙에만 할당될 수 있습니다.
  • 컴포넌트의 속성은 본질적으로 런타임 타입 정보를 포함합니다.
  • 컴포넌트는 Delphi 사용자 인터페이스의 컴포넌트 팔레트에 추가되어 폼에서 조작할 수 있습니다.


표준 클래스에서 일반적으로 수행되는 것보다 더 나은 캡슐화를 컴포넌트가 실현하는 경우가 종종 있습니다. 예를 들어, 푸시 버튼이 포함된 대화 상자를 가정해 보십시오. VCL 컴포넌트를 사용하여 개발한 Windows 프로그램의 경우, 사용자가 이 버튼을 클릭하면 시스템은 WM_LBUTTONDOWN 메시지를 생성합니다. 프로그램은 일반적으로 switch문, 메시지 맵 또는 응답 테이블에 있는 메시지를 가져와 메시지에 응답하여 실행할 루틴에 디스패칭해야 합니다.


디스패치란 준비 상태에서 실행 상태로 전이되는 과정을 말하며, 이는 작업 스케줄러가 해당 프로세스를 선택하여 실행되어지는 것으로, 이때 실행된 프로세스가 CPU를 점유하게 됩니다.


대부분의 Windows 메시지(VCL)나 시스템 이벤트(CLX)는 Delphi 컴포넌트에 의해 처리됩니다. 메시지에 응답하려면 이벤트 핸들러만 제공하면 됩니다.



컴포넌트 속성 설정


Published 속성은 디자인 타임 시 Object Inspector에서 설정하거나, 경우에 따라 특수 속성 편집기를 사용하여 설정할 수 있습니다.


런타임시 속성을 설정하려면 애플리케이션 소스 코드에서 속성에 새 값을 할당합니다.


Object Inspector 사용

폼 위의 컴포넌트를 선택하면 Object Inspector는 선택되니 컴포넌트의 published 속성을 표시하고 가능한 경우에는 사용자가 편집할 수 있게 해줍니다. Value 열과 Property 열사이를 토글하려면 Tab 키를 사용합니다. 커서가 Property 열에 있으면 속성 이름의 첫 문자를 입력하여 속성을 탐색할 수 있습니다. 부울 및 열거 타입의 속성인 경우, 드롭다운 목록에서 값을 선택하거나 Value 열을 더블 클릭하여 설정을 토글할 수 있습니다.


속성 이름 옆에 더하기(+) 기호가 있을 경우, 더하기 기호를 클릭하거나 속성에 포커스가 있을 때 '+'를 입력하면 해당 속성의 하위 값 목록이 표시됩니다. 마찬가지로 속성 이름 옆에 빼기(-) 기호가 있을 경우, 빼기 기호를 클릭하거나 '-'를 입력하면 하위 값이 숨겨집니다.


기본적으로 Legacy 범주의 속성은 표시되지 않습니다. 표시 필터를 변경하려면 Object Inspector에서 마우스 오른쪽 버튼을 클릭한 다음 View를 선택합니다. 자세한 내용은 온라인 도움말의 "property categories"를 참조하십시오.


둘 이상의 컴포넌트가 선택되면 Object Inspector는 선택된 컴포넌트가 공유하는 모든 속성(Name 제외)을 표시합니다. 선택된 컴포넌트 간에 공유 속성 값이 다른 경우, Object Inspector는 기본값을 표시하거나 처음 선택된 컴포넌트의 값을 표시합니다. 공유 속성을 변경하면 선택된 모든 컴포넌트에 변경 사항이 적용됩니다.


속성 편집기 사용

Font와 같은 일부 속성은 특수 속성 편집기를 갖고 있습니다. 이러한 속성은 Object Inspector에서 속성을 선택할 때 그 값 옆에 생략 기호(...)가 나타납니다. 속성 편집기를 열려면 Value 열을 더블 클릭하거나, 생략 기호를 클릭하거나, 속성이나 속성의 값에 포커스가 있을 때 Ctrl+Enter를 누릅니다. 일부 컴포넌트의 경우, 폼 위의 컴포넌트를 더블 클릭하면 속성 편집기가 함께 열립니다.


속성 편집기는 단일 대화 상자에서 복잡한 속성을 설정할 수 있게 해줍니다. 속성 편집기는 입력을 확인하고 종종 할당의 결과를 미리 볼 수 있게 해줍니다.


런타임시 속성 설정

쓰기 가능한 모든 속성은 런타임 시 소스 코드에서 설정할 수 있습니다. 예를 들어, 다음과 같이 폼에 캡션을 동적으로 할당할 수 있습니다.

Form1.Caption := MyString;



메소드 호출


메소드는 일반적인 프로시저 및 함수와 마찬가지로 호출됩니다. 예를 들어, 비주얼 컨트롤은 화면 상의 컨트롤 이미지를 새로 고치는 Repaint 메소드를 갖습니다. 그리기 그리드 객체의 Repaint 메소드를 다음과 같이 호출할 수 있습니다.

DrawGrid1.Repaint;


속성의 경우와 마찬가지로 메소드 이름의 유효 범위(scope)가 한정자의 필요성을 결정합니다. 예를 들어, 다음과 같이 폼의 자식 컨트롤 중 하나의 이벤트 핸들러 내에서 폼을 다시 그리려는 경우에는 폼 이름을 메소드 호출에 추가할 필요가 없습니다.

procedure TForm1.ButtonClick(Sender:TObject);
begin
  Repaint;
end;


유효 범위(scope)에 대한 자세한 내용은 3-8 페이지의 "유효 범위(scope) 및 한정자"를 참조합니다.



이벤트 및 이벤트 핸들러 작업


Delphi에서 작성되는 거의 모든 코드는 이벤트에 응답하여 직접적 또는 간접적으로 실행됩니다. 이벤트는 종종 사용자 동작인 런타임 발생을 나타내는 특수한 종류의 속성입니다. 이벤트에 직접 응답하는 코드, 즉 이벤트 핸들러는 오브젝트 파스칼 프로시저입니다. 다음 단원에서는 아래 작업을 수행하는 방법에 대해 설명합니다.

  • 새 이벤트 핸들러 생성
  • 컴포넌트의 기본 이벤트에 대한 핸들러 생성
  • 이벤트 핸들러 찾기
  • 이벤트를 기존 이벤트 핸들러에 연결
  • 메뉴 이벤트를 이벤트 핸들러에 연결
  • 이벤트 핸들러 삭제


새 이벤트 핸들러 생성

Delphi는 폼과 다른 컴포넌트에 대한 뼈대 이벤트 핸들러르 생성할 수 있습니다. 다음과 같은 방법으로 이벤트 핸들러를 작성합니다.

  1. 컴포넌트를 선택합니다.
  2. Object Inspector의 Event 탭을 클릭합니다. Object Inspector의 Events 페이지가 해당 컴포넌트에 대해 정의된 모든 이벤트를 표시합니다.
  3. 원하는 이벤트를 선택한 다음 Value 열을 더블 클릭하거나 Ctrl+Enter를 누릅니다. Delphi는 코드 에디터에서 이벤트 핸들러를 생성하고 begin...end 블록 안에 커서를 둡니다.
  4. begin...end 블록 안에 이ㅏ벤트 발생 시 실행할 코드를 입력합니다.


컴포넌트의 기본 이벤트에 대한 핸들러 생성

일부 컴포넌트는 가장 일반적으로 처리해야 하는 이벤트인 기본 이벤트를 갖습니다. 예를 들어, 버튼의 기본 이벤트는 OnClick입니다. 기본 이벤트 핸들러를 만들려면 폼 디자이너에서 컴포넌트를 더블 클릭합니다. 이렇게 하면 뼈대 이벤트 처리 프로시저가 생성되고 프로시저 몸체(body)에 커서가 놓인 상태에서 코드 에디터가 열리 때문에 코드를 쉽게 추가할 수 있습니다.


모든 컴포넌트가 기본 이벤트를 갖는 것은 아닙니다. TBevel과 같은 일부 컴포넌트는 어떤 이벤트에도 응답하지 않습니다. 다른 컴포넌트는 폼 디자이너에서 더블 클릭했을 때 다르게 응답합니다. 예를 들어, 많은 컴포넌트가 디자인 타임 시 더블 클릭했을 때 기본 속성 편집기나 대화 상자를 엽니다.



이벤트 핸들러 찾기

폼 디자이너에서 컴포넌트를 더블 클릭하여 컴포넌트에 대한 기본 이벤트 핸들러를 생성한 경우, 동일한 방법으로 기본 이벤트 핸들러를 찾을 수 있습니다. 컴포넌트를 더블클릭하면 코드 에디터가 열리면서 이벤트 핸들러 본문의 시작 부분에 커서가 위치하게 됩니다.


기본 이벤트 핸들러가 아닌 이벤트 핸들러는 다음과 같은 방법으로 찾습니다.

  1. 폼에서 찾고자 하는 이벤트 핸들러의 컴포넌트를 선택합니다.
  2. Object Inspector에서 Events 탭을 클릭합니다.
  3. 확인할 핸들러의 이벤트를 선택한 다음 Value 열을 더블 클릭합니다. 코드 에디터가 열리고 이벤트 핸들러 몸체(body)의 시작 부분에 커서가 놓입니다.


이벤트를 기존 이벤트 핸들러에 연결

둘 이상의 이벤트에 응답하는 이벤트 핸들러를 작성하여 코드를 재사용할 수 있습니다. 예를 들면, 많은 애플리케이셔에서 드롭다운 메뉴 명령에 해당하는 스피드 버튼을 제공합니다. 버튼이 메뉴 명령과 같은 동작을 일으키면 하나의 이벤트 핸들러를 작성하여 버튼 및 메뉴 항목의 OnClick 이벤트에 할당할 수 있습니다.


다음과 같은 방법으로 이벤트를 기존 이벤트 핸들러에 연결합니다.

  1. 폼 위에서 처리하고자 하는 이벤트를 갖는 컴포넌트를 선택합니다.
  2. Object Inspector의 Events 페이지에서 핸들러를 연결할 이벤트를 선택합니다.
  3. 이벤트 옆에 있는 Value 열에서 아래쪽 화살표를 클릭하여 이전에 작성한 이벤트 핸들러의 목록을 엽니다. 이 목록에는 동일한 폼에 있는 동일한 이름의 이벤트에 대해 작성된 이벤트 핸들러만 포함되어 있습니다. 이벤트 핸들러 이름을 클릭하여 목록에서 선택합니다.

위 절차는 이벤트 핸들러를 재사용할 수 있는 쉬운 방법입니다. 하지만 액션 리스트와 VCL의 액션 밴드는 사용자 명령에 응답하는 코드를 중앙에서 구성하기 위한 강력한 도구를 제공합니다. 액션 밴드와 달리 액션 리스트는 크로스 플랫폼 애플리케이션에서 사용할 수 있습니다.



Sender 매개변수 사용

이벤트 핸들러에서 Sender 매개변수는 이벤트를 받아 핸들러를 호출한 컴포넌트를 나타냅니다. 호출하는 컴포넌트에 따라 다르게 동작하는 이벤트 핸들러를 여러 컴포넌트가 공유하게 만드는 것은 경우에 따라 유용할 수 있습니다. 이렇게 하려면 if...then..else 문에서 Sender 매개변수를 사용합니다. 예를 들어, 다음 코드는 Button1이 OnClick 이벤트를 받은 경우에만 대화 상자의 캡션에 애플리케이션의 제목을 표시합니다.


procedure TMainForm.Button1Click(Sender:TObject);
begin
  if Sender = Button1 then
    AboutBox.Caption := 'About ' + Application.Title
  else
    AboutBox.Caption := '';
  AboutBox.ShowMoal;
end;


공유 이벤트 표시 및 코딩

컴포넌트가 이벤트를 공유할 경우, Object Inspector에 공유 이벤트를 표시할 수 있습니다. 우선 Sift 키를 누른 상태에서 폼 디자이너에서 컴포넌트를 클릭하여 선택한 다음 Object Inspector에서 Events 탭을 선택합니다. 이렇게 하면 Object Inspector의 Value 열에서 공유 이벤트에 대한 새 이벤트 핸들러를 만들거나 기존 이벤트 핸들러를 공유 이벤트에 할당할 수 있습니다.



메뉴 이벤트를 이벤트 핸들러에 연결

MainMenu 및 PopupMenu 컴포넌트와 함께 메뉴 디자이너는 애플리케이션에 드롭다운 및 팝업 메뉴를 쉽게 제공할 수 있게 해줍니다. 그러나 메뉴가 작동하려면 사용자가 메뉴 항목을 선택하거나 가속키 또는 단축키를 누를 때마다 발생하는 OnClick 이벤트에 각 메뉴 항목이 응답해야 합니다. 이 단원에서는 메뉴 항목에 이벤트 핸들러를 연결하는 방법을 설명합니다. 메뉴 디자이너 및 관련 컴포넌트에 대한 자세한 내용은 6-29 페이지의 "메뉴 생성 및 관리"를 참조하십시오.


다음과 같은 방법으로 메뉴 항목에 대한 이벤트 핸들러를 만듭니다.

  1. MainMenu 또는 PopupMenu 객체를 더블 클릭하여 메뉴 디자이너를 엽니다.
  2. 메뉴 디자이너에서 메뉴 항목을 선택합니다. Object Inspector에서 항목의 Name 속성에 값이 할당되었는지 확인합니다.
  3. 메뉴 디자이너에서 메뉴 항목을 더블 클릭합니다. Delphi는 코드 에디터에서 이벤트 핸들러를 생성하고 begin..end 블록 안에 커서를 놓습니다.
  4. begin..end 블록 안에서 사용자가 메뉴 명령을 선택할 때 실행할 코드를 입력합니다.


다음과 같은 방법으로 메뉴 항목을 기존 OnClick 이벤트 핸들러에 연결합니다.

  1. MainMenu 또는 PopupMenu 객체를 더블 클릭하여 메뉴 디자이너를 엽니다.
  2. 메뉴 디자이너에서 메뉴 항목을 선택합니다. Object Inspector에서 항목의 Name 속성에 값이 할당되었는지 확인합니다.
  3. Object Inspector의 Events 페이지에서 OnClick 옆에 있는 Value 열의 아래쪽 화살표를 클릭하여 이전에 작성된 이벤트 핸들러의 목록을 엽니다. 이 목록에는 이 폼의 OnClick 이벤트에 대해 작성된 이벤트 핸들러만 포함되어 있습니다. 이벤트 핸들러 이름을 클릭하여 목록을 선택합니다.


이벤트 핸들러 삭제

폼 디자이너를 사용하여 폼에서 컴포넌트를 삭제하면 Delphi는 폼의 타입 선언에서 컴포넌트를 제거합니다. 하지만 연결된 모든 메소드가 폼의 다른 컴포넌트에 의해 계속 호출될 수 있기 때문에 유닛 파일에서는 삭제되지 않습니다. 이벤트 핸들러 같은 메소드를 수동으로 삭제할 수 있지만 이 경우 유닛의 interface 섹션에 있는 메소드의 forward 선언과 implementation 섹션에 있는 그 구현을 모두 삭제해야 합니다. 그렇게 하지 않으면 프로젝트 빌드시 컴파일러 오류가 발생합니다.



VCL 및 CLX 컴포넌트


컴포넌트 팔레트에는 광범위한 프로그래밍 작업을 처리하는 여러 개의 컴포넌트들이 들어 있습니다. 팔레트에서 컴포넌트를 추가, 제거 및 재정렬할 수 있고 여러 컴포넌트를 그룹화하는 컴포넌트 템플릿 및 프레임을 만들 수 있습니다.


팔레트에 있는 컴포넌트는 용도와 기능별로 페이지에 정렬되어 있습니다. 기본 구성으로 표시되는 페이지는 현재 실행 중인 Delphi의 버전에 따라 달라집니다. 아래 표에는 애플리케이션 작성에 사용할 수 있는 일반적인 기본 페이지와 컴포넌트가 나열되어 있습니다. 일부 탭과 컴포넌트는 크로스 플랫폼이 아니며 이 표는 크로스 플랫폼 여부를 표시하고 있습니다. Windows 전용 CLX 애플리케이션에서 일부 VCL 특정 넌비주얼 컴포넌트를 사용할 수 있지만 이러한 코드 부분을 분리하지 않으면 애플리케이션은 크로스 플랫폼이 되지 않습니다.


 페이지 이름

 설명

 크로스 플랫폼 지원 여부

 Standard

 표준 컨트롤, 메뉴

 예

 Additional

 특수 컨트롤

 예(ApplicationEvents와 CustomizeDlg는 제외)

 Win32

 Windows 일반 컨트롤

 CLX 애플리케이션을 만들 때 대신 나타나는 Common Controls 탭의 동일한 컴포넌트(예: RichEdit, UpDown, HotKey, Animate, DataTimePicker, MonthCalendar, Coolbar, PageScroller 및 ComboBoxEx)는 대부분 크로스 플랫폼이 아닙니다.

 System

 타이머, 멀티미디어 및 DDE를 비롯한 시스템 수준 액세스를 위한 컴포넌트 및 컨트롤

 Timer는 크로스 플랫폼이지만 PaintBox, MediaPlayer, OleContainer 및 Dde 컴포넌트는 크로스 플랫폼이 아닙니다.

 Data Access

 특정 액세스 메커니즘에 연결되지 않은 데이터베이스 데이터 작업을 위한 컴포넌트

 예

 Data Controls

 비주얼, data-aware 컨트롤

 예(DBRichEdit, DBCtrlGrid 및 DBChart 제외)

 dbExpress

 동적 SQL 처리를 위한 메소드를 제공하는 크로스 플랫폼의 데이터베이스 독립계층인 dbExpress를 사용하는 데이터베이스 컨트롤. SQL 서버 액세스를 위한 일반 인터페이스를 정의합니다.

 예

 DataSnap

 다계층 데이터베이스 애플리케이션 작성에 사용되는 컴포넌트

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 BDE

 Borland Database Engine을 통해 데이터 액세스를 제공하는 컴포넌트

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 ADO

 ADO 프레임워크를 통해 데이터 액세스를 제공하는 컴포넌트

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 InterBase

 InterBase에 대한 직접 액세스를 제공하는 컴포넌트

 예

 InternetExpress

 웹서버 애플리케이션이자 동시에 다계층 데이터베이스 애플리케이션의 클라이언트인 컴포넌트

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 Internet

 인터넷 통신 프로토콜과 웹 애플리케이션용 컴포넌트

 예(ClientSocket, ServerSocket, QueryTableProducer, XMLDoc 및 WebBrowser 제외)

 WebSnap

 웹서버 애플리케이션 작성을 위한 컴포넌트

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 FastNet

 NetMasters Internet 컨트롤

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 QReport

 내장 보고서 작성을 위한 QuickReport 컴포넌트

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 Dialogs

 일반 대화 상자

 예(OpenPictureDialog, SavePictureDialog, PrinterSetup-Dialog 및 PageSetupDialog 제외)

 Win 3.1

 이전 스타일 Win 3.1 컴포넌트

 아니오

 Samples

 예제 사용자 지정 컴포넌트

 아니오

 ActiveX

 예제 ActiveX 컨트롤

 아니오

 COM+

 COM+ 이벤트를 처리하는 컴포넌트

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 WebServices

 SOAP 기반 웹서비스를 구현하거나 사용하는 애플리케이션 작성을 위한 컴포넌트

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 Servers

 Microsoft Excel, Word 등에 대한 COM 서버 예제(Microsoft MSDN 설명서 참조)

 Windows CLX 애플리케이션에서 사용될 수 있습니다.

 Indy Clients

 클라이언트용 크로스 플랫폼 인터넷 컴포넌트(공개 소스 Winshoes Internet 컴포넌트)

 예

 Indy Servers

 서버용 크로스 플랫폼 인터넷 컴포넌트(공개 소스 Winshoes Internet 컴포넌트)

 예

 Indy Misc

 추가적인 크로스 플랫폼 인터넷 컴포넌트(공개 소스 Winshoes Internet 컴포넌트)

 예


온라인 도움말은 컴포넌트 팔레트의 컴포넌트에 관한 정보를 제공합니다. 하지만 ActiveX, Servers 및 Samples 페이지의 일부 컴포넌트는 예제만 제공되고 따로 설명되지 않습니다.



컴포넌트 팔레트에 사용자 지정 컴포넌트 추가

직접 작성했거나 협력업체에서 작성한 사용자 지정 컴포넌트를 컴포넌트 팔레트에 설치하여 애츨리케이션에서 사용할 수 있습니다. 컴포넌트를 작성하려면 5부 "사용자 지정 컴포넌트 생성"을 참조하십시오. 기존의 컴포넌트를 설치하려면 11-5 페이지의 "컴포넌트 패키지 설치"를 참조하십시오.



그리드


그리드는 정보를 행과 열로 표시합니다. 데이터베이스 애플리케이션을 작성하는 경우, 15장 "데이터 컨트롤 사용"에 설명된 TDBGrid 또는 TDBCtrlGrid 컴포넌트를 사용합니다. 그외의 경우에는 표준 그리기 그리드나 문자열 그리드를 사용합니다.



그리기 그리드

그리기 그리드(TDrawGrid)는 임의의 데이터를 표 형식으로 표시합니다. OnDrawCell 이벤트 핸들러를 작성하여 그리드의 셀을 채웁니다.

  • CellRect 메소드는 지정된 셀의 화면 좌표를 반환하지만, MouseToCell 메소드는 지정된 화면 좌표에 있는 셀의 열과 행을 반환합니다. Selection 속성은 현재 선택한 셀의 테두리를 나타냅니다.
  • TopRow 속성은 현재 그리드의 상단에 있는 행을 결정합니다. LeftCol 속성은 왼쪽에서 첫번째 비주얼 열을 결정합니다. VisibleColCount와 VisibleRowCount는 그리드에서 보이는 열과 행의 수입니다.
  • ColWidths 속성과 RowHieghts 속성을 사용하여 열이나 행의 너비 또는 높이를 변경할 수 있습니다. GridLineWidth 속성을 사용하여 그리드 선의 너비를 설정합니다. ScrollBars 속성을 사용하여 스크롤 막대를 그리드에 추가합니다.
  • FixedCols 속성과 FixedRows 속성을 사용하여 고정되거나 스크롤이 없는 열과 행을 갖도록 선택할 수 있습니다. FixedColor 속성을 사용하여 고정된 열과 행에 색상을 지정합니다.
  • Options, DefaultColWidth 및 DefaultRowHeight 속성은 그리드의 모습과 행동에 영향을 미칠 수 있습니다.


문자열 그리드

문자열 그리드 컴포넌트는 특수한 기능을 추가하여 문자열의 표시를 단순화하는 TDrawGrid의 자손입니다. Cells 속성은 그리드의 각 셀에 대한 문자열을 나열하고 Objects 객체는 각 문자열에 연결된 객체를 나열합니다. 모든 문자열과 특정한 열이나 행에 관련된 객체는 Cols 속성 또는 Rows 속성을 통해 액세스할 수 있습니다. 



값 목록 편집기(VCL 전용)


TValueListEditor는 Name=Value 형태로 이름/값 쌍을 포함하는 문자열 목록을 편집하기 위한 특수 그리드입니다. 이름과 값은 Strings 속성 값인 TStrings 자손으로 저장됩니다. Values 속성을 사용하면 모든 이름의 값을 조회할 수 있습니다. 크로스 플랫폼 프로그래밍에서는 TValueListEditor를 사용할 수 없습니다.


이 그리드에는 이름과 값을 위한 열이 각각 하나씩 포함되어 있습니다. 기본적으로 Name 열의 이름은 "Key"이고 Value 열의 이름은 "Value"입니다. TitleCaptions 속성을 사용하면 이러한 기본 이름을 바꿀 수 있습니다. 또한 컨트롤 크기를 조정할 때 컨트롤 크기 조정을 제어하는 역할도 수행하는 DisplayOptions 속성을 사용하면 이러한 열이름을 생략할 수 있습니다.


KeyOptions 속성을 사용하면 사용자가 Name 열을 편집할 수 있는지 여부를 제어할 수 있습니다. KeyOptions에는 이름을 편집 또는 삭제하고, 새 이름을 추가하고, 새 이름이 고유해야 하는지 여부를 제어할 수 있도록 허용하는 별도의 옵션이 포함되어 있습니다.


ItemProps 속성을 사용하면 사용자가 Value 열에서 항목을 편집하는 방법을 제어할 수 있습니다. 각 항목은 다음 작업을 수행할 수 있게 해주는 별도의 TItemProp 객체를 가집니다.


  • 편집 마스크를 제공하여 유효 입력을 제한합니다.
  • 최대값 길이를 지정합니다.
  • 값을 읽기 전용으로 표시합니다.
  • 값 목록 편집기를 지정하여 사용자가 값을 선택할 수 있도록 선택 목록을 여는 드롭다운 화살표를 표시하거나 사용자가 값을 입력할 수 있도록 대화 상자를 표시하는 데 사용할 수 있는 이벤트를 실행하는 생략 버튼을 표시합니다.
    드롭다운 화살표를 표시하도록 지정할 경우, 사용자가 값을 선택할 수 있도록 목록을 제공해야 합니다. 이러한 값 목록은 정적 목록(TItemProp 객체의 PickList 속성)으로 만들거나 값 목록 편집기의 OnGetPickList 이벤트를 사용하여 런타임 시 동적으로 추가할 수 있습니다. 또한 이러한 방법을 결합하여 OnGetPickList 이벤트 핸들러가 수정하는 정적 목록을 만들 수도 있습니다.
    생략 버튼을 표시하도록 지정할 경우에는 사용자가 생략 버튼을 클릭했을 때 방생하는 응답(해당 사항이 있는 경우 값 설정 포함)을 제공해야 합니다. 이러한 응답은 OnEditButtonClick 이벤트 핸들러를 작성하여 제공합니다.


대화 상자 개발


컴포넌트 팔레트의 Dialog 페이지에 있는 대화 상자 컴포넌트들은 애플리케이션에서 다양한 대화 상자를 사용할 수 있게 합니다. 이러한 대화 상자는 파일 열기 및 저장과 같은 공통된 파일 작업을 수행할 수 있는 친숙하고 일관성 있는 인터페이스를 애플리케이션에 제공합니다. 대화 상자는 데이터를 표시하거나 얻습니다.


대화 상자는 Execute 메소드가 호출되면 열립니다. Execute는 부울 값을 반환합니다. OK를 선택하여 대화 상자의 변경 사항을 승인하는 경우 Execute는 True를 반환하고, Cancle을 선택하여 변경 사항을 저장하지 않고 대화 상자를 빠져 나가는 경우 Execute는 False를 반환합니다.


크로스 플랫폼 애플리케이션을 개발하는 경우, QDialogs 유닛의 CLX에서 제공하는 대화 상자를 사용할 수 있습니다. 파일 열기나 저장, 글꼴 또는 색 변경 등과 같은 일반 작업을 위한 원시 대화 상자 유형을 가진 운영체제의 경우, UseNativeDialog 속성을 사용할 수 있습니다. 이러한 환경에서 실행되는 애플리케이션에 대해 Qt 대화 상자 대신 원시 대화상자를 사용하려면 UseNativeDialog를 True로 설정합니다.



열린 대화 상자 사용

공통으로 사용되는 대화 상자 컴포넌트 중의 하나는 TOpenDialog입니다. 이 컴포넌트는 보통 폼의 메인 메뉴 바에 있는 File 옵션 아래의 New 또는 Open 메뉴 항목에 의해 호출됩니다. 대화 상자는 와일드카드 문자를 사용하여 파일 그룹을 선택하고 디렉토리를 통해 탐색할 수 있는 컨트롤을 포함합니다.


TOpenDialog 컴포넌트는 Open 대화 상자를 애플리케이션에 사용할 수 있도록 합니다. 이 대화 상자의 용도는 사용자에게 열려는 파일을 선택하도록 하는 것입니다. Execute 메소드를 사용하여 대화 상자를 표시합니다.


사용자가 대화 상자에서 OK를 선택하면 사용자의 파일은 TOpenDialog의 FileName 속성에 저장된 후에 원하는 대로 처리할 수 있습니다.


다음 코드를 Action에 둘 수 있고 TMainMenu 하위 항목의 Action 속성에 연결하거나 하위 항목의 OnClick 이벤트에 둘 수 있습니다.


if OpenDialog1.Execute then
  filename := OpenDialog1.FileName;


이 코드는 대화 상자를 보여주고 사용자가 OK 버튼을 누르면 이전에 선언한 filename이라는 AnsiString 변수에 파일 이름을 복사합니다.



Helper 객체 사용


VCL 및 CLX에는 일반 프로그래밍 작업을 단순화하는 다양한 넌비주얼 객체가 포함되어 있습니다. 이 단원에서는 다음 작업을 보다 쉽게 수행할 수 있게 하는 몇 개의 Helper 객체에 대해 설명합니다.

  • 목록 사용
  • 문자열 목록 사용
  • Windows 레지스트리 및 .INI 파일 변경
  • 스트림 사용

다음 객체는 목록 생성 및 관리를 위한 기능을 제공합니다.


 객체 

 보유

 TList

 포인터 목록

 TObjectList

 인스턴스 객체의 메모리 관리 목록

 TComponentList

 컴포넌트의 메모리 관리 목록(즉, TComponent의 자손 클래스의 인스턴스)

 TQueue

 포인터의 선입선출(FIFO) 목록

 TStack

 포인터의 후입선출(LIFO) 목록

 TObjectQueue

 객체의 선입선출 목록

 TObjectStack

 객체의 후입선출 목록

 TClassList

 클래스 타입의 목록

 TCollection,
 TOwnedCollection,
 TCollectionItem

 특수하게 정의된 항목의 인덱스된 모음

 TStringList

 문자열 목록



문자열 목록 사용


경우에 따라 애플리케이션은 문자열 목록을 관리해야 합니다. 문자열 목록의 예로는 콤보박스의 항목, 메모의 행, 글꼴 이름, 문자열 그리드의 열과 행 이름이 있습니다. VCL 및 CLX는 TStrings라는 객체와 이 객체의 자손인 TStringList를 통해 모든 문자열 목록에 공통 인터페이스를 제공합니다. TStringList는 TStrings에 있는 추상 속성과 메소드를 구현하고, 속성, 이벤트 및 메소드를 사용하여 다음을 수행합니다.

  • 목록에서 문자열을 정렬합니다.
  • 정렬된 목록에서 문자열 중복을 금합니다.
  • 목록 내용의 변경 사항에 응답합니다.

문자열 목록을 보유하는 기능을 제공하는 것 외에도 이러한 객체들은 상호 운용성을 용이하게 합니다. 예를 들어, TStrings의 인스턴스인 메모의 행을 편집한 다음 이 행들을 TStrings의 인스턴스인 콤보 박스의 항목으로 사용할 수 있습니다.


문자열 목록 속성을 Value 열의 TStrings와 함께 Object Inspector에 표시됩니다. TStrings를 더블 클릭하여 행을 편집, 추가 또는 삭제할 수 있는 문자열 목록 편집기를 엽니다.


런타임에 문자열 목록 객체를 사용하여 다음과 같은 작업을 수행할 수 있습니다.

  • 문자열 목록의 로드 및 저장
  • 새 문자열 목록 작성
  • 목록에서 문자열 처리
  • 문자열 목록에 객체 연결


문자열 목록의 로드 및 저장

문자열 목록 객체는 SaveToFile 메소드와 LoadFromFile 메소드를 제공하므로 사용자는 문자열 목록을 텍스트 파일에 저장하고 텍스트 파일을 문자열 목록에 로드할 수 있습니다. 텍스트 파일의 각 행은 목록의 문자열에 해당합니다. 이러한 메소드를 사용하면 파일을 메모 컴포넌트에 로드하여 단순한 텍스트 편집기를 만들거나 콤보 박스의 항목 목록을 저장할 수 있습니다.


다음 예제는 WIN.INI 파일 사본을 메모 필드로 로드하고 WIN.BAK라는 이름의 백업사본을 만듭니다.


procedure EditWinIni;
var
  FileName:string;{ storage for file name }
begin
  FileName := 'C:\WINDOWS\WIN.INI';{ set the file name }
  with Form1.Memo1.Lines do
  begin
    LoadFormFile(FileName);{ load frodm file }
    SaveToFile(ChangeFileExt(FileName, '.back'));{ save into backup file }
  end;
end;


새 문자열 목록 작성

문자열 목록은 일반적으로 컴포넌트의 일부입니다. 그러나 조회 테이블용 문자열을 저장하는 것과 같이 독립적인 문자열 목록을 만드는 것이 편리할 때가 있습니다. 문자열 목록의 작성 및 관리 방법은 단일 루틴 내에서 생성, 사용 및 소멸되는 목록의 기간이 짧은지 애플리케이션이 종료할 때까지 사용할 만큼 기간이 긴지에 따라 다릅니다. 생성한 문자열 목록의 종류에 상관없이 사용자는 종료시 목록을 해제해야 합니다.



기간이 짧은 문자열 목록

문자열 목록을 단일 루틴 기간 동안만 사용하는 경우 그 문자열 목록을 한 루틴 내에서 생성, 사용 및 소멸할 수 있습니다. 이것은 문자열 목록을 사용하는 가장 안전한 방법입니다. 문자열 목록 객체는 목록 자체와 목록의 문자열에 대해 메모리를 할당하기 때문에 예외가 발생하더라도 try...finally 블록을 사용하여 메모리가 해제되었는지 확인해야 합니다.


  1. 문자열 목록 객체를 생성합니다.
  2. try...finally 블록의 try 부분에서 문자열 목록을 사용합니다.
  3. finally 부분에서 문자열 목록 객체를 해제합니다.

다음 이벤트 핸들러는 문자열 목록을 생성, 사용 및 소멸함으로써 버튼 클릭에 응답합니다.

procedure TForm1.Button1Click(Sender:TObject);
var
  TempList:TStrings;{ declare the list }
begin
  TempList := TStringList.Create;{ construct the list object }
  try
    { use the string list }
  finally
    TempList.Free;{ destroy the list object }
  end;
end;



기간이 긴 문자열 목록

애플리케이션을 실행하는 동안 항상 문자열 목록을 사용 가능하도록 하려면 애플리케이션 시작 시 목록을 생성하고 애플리케이션 종료 전에 소멸합니다.


  1. 애플리케이션의 메인 폼에 대한 유닛 파일에서 TStrings 타입의 필드를 폼의 선언에 추가합니다.
  2. 메인 폼의 생성자에 대한 이벤트 핸들러를 작성합니다. 이 이벤트 핸들러는 폼이 나타나기 전에 실행됩니다. 생성자는 문자열 목록을 만들어서 첫번째 단계에서 선언한 필드에 할당해야 합니다.
  3. 폼의 OnClose 이벤트용 문자열 목록을 해제하는 이벤트 핸들러에서 작성합니다.


이 예제에서는 기간이 긴 문자열 목록을 사용하여 메인 폼에서 사용자의 마우스 클릭을 기록한 다음 애플리케이션이 종료하기 전에 목록을 파일에 저장합니다.


unit Unit1;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
{For CLX:uses SysUtils, Classes, QGraphics, QControls, QForms, Qialogs;}

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender:TObject);
    procedure FormDestroy(Sender:TObject);
    procedure FormMouseDown(Sender:TObject; Button:TMouseButton;
      Shift:TShiftState; X, Y:Integer);
  private
    { Private declarations }
  public
    { Public declarations }
    ClickList:TStrings;{ declare the field }
  end;

  var
    Form1:TForm1;

  implementation

  {$R *.DFM}

  procedure TForm1.FormCreate(Sender:TObject);
  begin
    ClickList := TStringList.Create;{ construct the list }
  end;

  procedure TForm1.FormPaint(Sender:TObject);
  begin
    ClickList.SaveToFile(ChangeFileExt(Application.ExeName, '.LOG'));{ save the list }
    ClickList.Free;{ destroy the list object }
  end;

  procedure TForm1.FormMouseDown(Sender:TObject; Button:TMouseButton;
      Shift:TShiftState; X, Y:Integer);
  begin
    ClickList.Add(Format('Click at (%d, %d)', [X, Y])); { add a string to the list }
  end;

  end.


목록에서 문자열 처리

다음은 문자열 목록에서 공통으로 수행되는 작업입니다.

  • 목록의 문자열 수
  • 특정 문자열 액세스
  • 목록에서 문자열 위치 찾기
  • 목록에서 문자열 반복
  • 목록에 문자열 추가
  • 목록 내에서 문자열 이동
  • 목록에서 문자열 삭제
  • 문자열 목록 전체 복사


Windows 레지스트리 및 INI 파일(VCL 전용)


Windows 시스템 레지스트리는 애플리케이션이 구성 정보를 저장하는 계층 데이터베이스입니다. VCL 클래스 TRegistry는 레지스트리를 읽고 쓰는 메소드를 제송합니다.


Windows 95까지는 대부분의 애플리케이션이 일반적으로 확장명이 .INI인 초기화 파일에 구성 정보를 저장하였습니다. VCL은 INI 파일을 사용하는 프로그램의 유지 관리 및 마이그레이션을 용이하게 하기 위해 다음과 같은 클래스를 제공합니다.

  • 레지스트리를 사용하기 위한 TRegistry(VCL 전용)
  • INI 파일을 사용하기 위한 TIniFile(VCL 전용) 또는 TMemIniFile
  • 레지스트리 및 INI 파일 모두를 사용하기 위한 TRegistryIniFile(VCL 전용)
    TRegistryIniFile은 TIniFile과 유사한 속성 및 메소드를 갖지만 시스템 레지스트리에 대해 읽기와 쓰기를 수행합니다. TCustomIniFile(TIniFile, TMemIniFile 및 TRegistryIniFile의 공통 조상) 타입의 변수를 사용하면 호출 위치에 따라 레지스트리 또는 INI 파일을 액세스하는 일반 코드를 작성할 수 있습니다.

크로스 플랫폼 프로그래밍에서는 TMemIniFile만 사용할 수 있습니다.



TIniFile 사용(VCL 전용)

INI 파일 형식은 여전히 많이 사용되면 DSK Desktop 설정 파일과 같은 많은 Delphi 구성 파일이 이 형식입니다. 이 파일 형식이 지금까지 많이 사용되기 때문에 VCL은 이러한 파일을 쉽게 읽고 쓸 수 있는 클래스를 제공합니다. 단, 크로스 플랫폼 프로그래밍에서는 TIniFile을 사용할 수 없습니다.


TIniFile 객체를 인스턴스화할 때 INI 파일 이름을 매개변수로서 생성자에 전달합니다. 이 파일은 존재하지 않을 경우 자동으로 만들어집니다. 이렇게 하면 ReadString, ReadInteger 또는 ReadBool을 사용하여 값을 자유롭게 읽을 수 있습니다. INI 파일의 전체 섹션을 읽으려는 경우에는 ReadSection 메소드를 사용할 수 있습니다. 마찬가지로 WriteBoll, WriteInteger 또는 WriteString을 사용하여 값을 쓸 수 있습니다.


각 Read 루틴은 세 개의 매개변수를 가집니다. 첫번째 매개변수는 INI 파일의 섹션을 식별합니다. 두 번째 매개변수는 읽고자 하는 값을 식별하고, 세번째 매개변수는 섹션이나 값이 INI 파일에 존재하지 않을 경우 기본값이 됩니다. 마찬가지로 Write 루틴도 섹션 및/또는 값이 존재하지 않을 경우 새로 만듭니다. 다음 예제 코드는 처음 실행될 때 INI 파일을 만듭니다.


[Form]

Top=185

Left=280

Caption=Default Caption

InitMax=0


이 애플리케이션이 다음 번에 실행되면 폼이 작성되는 동안 INI 값을 읽고 OnClose 이벤트에 이 값을 다시 기록합니다.



TRegistry 사용

대부분의 32비트 애플리케이션은 INI 파일 대신 레지스트리에 정보를 저장합니다. 이는 레지스트리가 계층적이고, 더 견고하고, INI 파일과 달리 크기 제한이 없기 때문입니다. TRegistry 객체에는 키 열기, 닫기, 저장, 이동, 복사 및 삭제를 위한 메소드가 포함되어 있습니다.


크로스 플랫폼 프로그래밍에서는 TRegistroy를 사용할 수 없습니다.



TRegIniFile 사용

INI 파일을 사용하는 데 익숙한 경우, TRegIniFile 클래스를 사용하여 구성 정보를 레지스트리로 이동할 수 있습니다. TRegIniFile은 레지스트리 항목을 INI 파일 항목처럼 보이도록 디자인된 클래스입니다. TRegIniFile에는 TIniFile의 모든 메소드(읽기 및 쓰기)가 존재합니다.


TRegIniFile 객체를 생성할 경우, 전달되 매개변수 (IniFile 객체의 파일이름)는 레지스트리의 사용자 키에서 키 값이 되고 모든 섹션과 값은 이 루트에서 분기됩니다. 실제 실제로 이 객체는 레지스트리 인터페이스를 현저하게 단순화하기 때문에 기존 코드를 포팅하는 중이 아니더라도 TRegistry 컴포넌트 대신 이 객체를 사용할 수 있습니다.


크로스 플랫폼 프로그래밍에서는 TRegIniFile을 사용할 수 없습니다.



인쇄


VCL TPrinter 객체는 Windows 프린터의 세부 정보를 캡슐화합니다. 설치되어 있는 사용가능한 프린터 목록을 보려면 Printers 속성을 사용합니다. TPrinter 객체는 프린터에 그리는 그리기 장치입니다. 이 장치는 포스트스크립트를 생성하여 lpr, lp 또는 다른 프린트 명령에 포스트스크립트를 보냅니다.


프린터 객체는 폼의 TCanvas와 동일한 TCanvas를 사용하므로 폼에 그릴 수 있는 모든 것을 또한 인쇄할 수 있습니다. 이미지를 인쇄하려면 BeginDoc 메소드를 호출한 다음 인쇄하려는 캔버스 그래픽과 텍스트(TextOut 메소드 사용)를 나열한 후, EndDoc 메소드를 호출하여 인쇄할 작업을 프린터에 보냅니다.


이 예제에서는 폼에 버튼과 메모를 사용합니다. 사용자가 버튼을 클릭하면 메모의 내용은 페이지 주위의 200픽셀을 테두리로 인쇄됩니다.


이 예제를 성공적으로 실행하려면 Printers를 uses 절을 추가합니다.


procedure TForm2.btnPrnClick(Sender: TObject);
var
  r:TRect;
  i:Integer;
begin
  with Printer do
    begin
      r := Rect(200, 200, (Pagewidth - 200), (PageHeight - 200));
      BeginDoc;
      for i:= 0 to Memo1.Lines.Count do
        Canvas.TextOut(200, 200 + (i *
          Canvas.TextHeigth(Memo1.Lines.Strings[i])),
                                    Memo1.Lines.Strings[i]);
        Canvas.Brush.Color := clBlack;
        Canvas.FrameRect(r);
        EndDoc;
      end;
    end;
end;



스트림 사용


스트림은 데이터를 읽고 쓰는 수단입니다. 스트림은 메모리, 문자열, 소켓 및 BLOB 스트림과 같은 다른 매체에 읽고 쓰기 위한 공통적인 인터페이스를 제공합니다.


다음 스트리밍 예제에서는 스트림을 사용하여 한 파일을 다른 파일에 복사합니다. 애플리케이션에는 두 가지 편집 컨트롤(From 및 To)과 Copy File 버튼이 있습니다.


procedure TForm1.CopyFileClick(Sender:TObject);
var
  stream1, stream2:TStream;
begin
  stream1:=TFileStream.Create(From.Text, fmOpenRead or fmShareDenyWrite);
  try
    stream2:=TFileStream.Create(To.Text, fmOpenCreate or fmShareDenyRead);
    try
      stream2.CopyFrom(Stream1, Stream1.Size);
    finally
      stream2.Free;
  finally
    stream1.Free;
end;


저장 매체를 읽고 쓰려면 특수한 스트림 객체를 사용합니다. TStream의 각 자손은 디스크 파일, 동적 메모리 등 특정 매체에 액세스하기 위한 메소드를 구현합니다. TStream 자손으로는 TFileStream, TStringStream 및 TMemoryStream이 있습니다. 읽기 및 쓰기용 메소드 이외에 이러한 객체는 애플리케이션에서 스트림의 임의 위치를 찾을 수 있습니다. TStream의 속성은 크기 및 현재 위치와 같은 스트림에 대한 정보를 제공합니다.