델파이의 Component Palette 에서 Data Controls 페이지를 보면, 표준 콤포넌트를 DB 용으로 사용할수 있도록 바꾸어 놓은 것들이 많이 있다. 예를 들면, DBEdit, DBMemo 와 같은 것이다. 그 뿐 아니라, Additional 페이지에 있는 StringGrid 와 비슷한 DBGrid 도 있다. 그런데 DBEdit 가 Edit 에 단순히 데이터를 인식할수 있는 기능을 첨가한 것인데 반하여, DBGrid 와 같은 것은 단순히 StringGrid 에 데이터 인식 기능을 추가한 것은 아니다. 그 외에 DBGrid 만 가져야 할 복잡한 기능들을 많이 가지고 있으며, 또한 StringGrid 에서는 있지만 DBGrid 에서는 필요 없는 기능은 가지고 있지 않다.
만일 사용자가 이와 같이 단순히 데이터만 넘겨주는 것 이상으로 DB 만을 위한 새로운 컴포넌트가 필요한 경우는 별 수 없이 사용자가 해당 콤포넌트를 만들어야 할 것이다. 예를 들면, DB 에 들어있는 데이터의 종류에 따라 다른 문구를 출력해 주는 콤포넌트가 필요한 경우가 이런 경우이다.
이 정도면 DB 를 인식하는 컴포넌트 중에 가장 간단한 것이다. 위의 컴포넌트는 지정된 Field 의 데이터가 1 이면 '1 입력', 2 이면 '2 입력', 3 이면 '3 입력' 이라고 출력해 주는 간단한, Label 에서 상속 받은 컴포넌트이다. 이러한 컴포넌트의 경우 1 개의 Field 만을 사용하며, 또한 단순히 데이터를 보여 주기만 한다. DBImage 같은 경우가 그러한 경우이다. 위의 소스를 잘 이해 한다면 DBImage 에서 지원되지 않는 그림 형식(예를 들면, GIF 같은 경우)을 지원하는 DBImageGif 와 같은 컴포넌트를 만들수 있다.
위에서 TFieldDataLink 라는 class 를 사용했는데, 이를 왜 사용 해야 하는지 궁금할 것이다. 먼저, 필자가 경험했던 일을 소개하자면, 전에 이러한 컴포넌트를 제작하는 일을 담당하게 되어 열심히 코딩을 하는데, 처음에는 TFieldDataLink 를 사용 하지 않고 바로 DataSource property 에 있는 DataSet property 를 이용하여 이벤트 처리를 하고, 데이터를 교환하는 방식으로 작성하였다. 그리고 그때 만든것은 지금것 처럼 단순히 DB 에서 읽어온 데이터를 보여 주는것 뿐 아니라 수정이 가능해야 했고, Field 도 한개가 아니고 전체 Field 를 모두 Access 해야 했다. 말하자면, DBGrid 와 같은 컴포넌트였다. 그런데, 앞서서 말한 방식대로 DataSet 를 직접 Access 해서 만들고 나니까 자꾸만 여러가지 문제가 발생하는 것이었다. 그래서 계속 인터넷을 뒤져가며 이에 대한 자료를 찾아본 결과 TDataLink 가 중간 관리를 담당 한다는 것을 알게 되었다. 아직도 이 DataLink 란 것이 정확히 무엇을 하는놈인지는 잘 모르지만, 한가지 확실한 것은 DB Access Component 를 만들때는 이것을 반드시 써야 한다는 점이다.
그러면, TDataLink 에 대해서 살펴보자.
먼저, TDataLink 에서 중요한 것들을 살펴보면,
property 들
ActiveRecord
- 내부 버퍼에 가지고 있는 레코드들 중의 현재 레코드를 나타낸다. 이 말이 무엇을 의미 하는지 좀 의아할 것이다. 예를 들면서 설명을 해 보면, DBGrid 에서 한번에 10 라인씩 보여 준다면, 이 10 라인 만큼을 버퍼에 가지고 있게 되는데, 이 중에서 현재 가리키고 있는 레코드를 나타 낸다는 것이다.
BufferCount
- 내부 버퍼의 크기를 정한다. 한번에 가지고 있어야 할 Record 의 갯수를 정한다. 앞에서와 같이 DBGrid 에서 10 라인을 보여주는 경우라면 이 property 를 10 으로 지정하면 된다.
DataSourceFixed
- DataSource 가 설정될 수 있는 상황 인지 알려준다. 현재 진행되는 작업이 끝나지 않은 상태에서, DataSource 가 바뀐다면 현재의 작업을 끝낼수가 없을 것이다. 이러한 경우는 이 property 가 True 로 setting 되러 DataSource 를 바꿀수 없는 상황임을 알려준다.
Editing
- 현재 DataSet 이 Edit 상태에 있는지를 나타낸다.
ReadOnly
- DataSet 이 수정이 가능한지를 나타낸다.
RecordCount
- 현재 내부 버퍼에 가지고 있는 Record 의 갯수를 나타낸다. BufferCount 가 10 인 경우라 하더라도 실제 Table 에 2 개의 Record 밖에 없다면, RecordCount 는 2 라는 값을 가질 것이다.
method 들
- ActiveChanged
protected level 에 존재하는 method 로 TDataLink 에서 상속받은 객체에서 처리하는 경우에 사용한다.
Active 상태가 바뀌면 호출된다.
- RecordChanged
역시 protected level 에 존재하며, Field 가 수정될 경우 호출된다.
이 외에도 자주 사용되는 프로퍼티나 메쏘드들이 많지만, 도움말에 잘 나와 있으므로 설명을 생략했다.
필자가 이에 관련된 Component 를 만들면서 제일 문제가 되었던 부분은 과연 어떻게 설계를 해야 하냐는 점이었다. 일반 콤포넌트와 제일 다른점은 외부에서 수정되는 내용이 이 콤포넌트가 나타내는 화면에 반영이 되어야 한다는 것이다. 만약, 이점을 고려하지 않고 제작에 들어간다면 나중에 흐름이 완전히 뒤엉켜 버리는 그런 느낌을 받게 될 것이다. 흐름이 뒤엉켜 버린다는 말의 의미는, 데이터 인식 콤포넌트의 경우 콤포넌트 내부에서 수정되는 내용이 DB 에 반영이 되고 다시 이것이 콤포넌트에 반영이 되게 되는데, 일반적인 콤포넌트의 경우는 이러한 과정을 거치지 않고 수정 사항이 바로 그 내부로 직접 반영되도록 하기 때문에, 만일 일반 콤포넌트와 같은 형식으로 만들게 된다면 수정 사항 반영이 2 번씩 되는 셈이 된다.
따라서, 위와 같이 수정을 할 때는 전적으로 DB 를 수정하고, 또한 그 수정에 대한 반응은 전적으로 DB 가 수정된 것에 대한 이벤트에 의해서 처리 되어야 한다. 이렇게 하기 위해서는 먼저 수정을 가하는 부분과 DB 가 수정된 것에 대해 반응하는 부분을 완전히 분리 하는것이 필요하다.
Data-Aware Component 를 만드는 방법에 대해서 개괄적으로 알아 보았다. 좀더 많은 내용을 소개했어야 하는데 하는 아쉬움이 남지만, 다음 기회로 미루도록 하고 이만 마치겠다.
파워러브 델파이 97년 12월호!!!
박성훈 wrote:
> 패널과 비슷한 모양의 컴포넌트(편의상 X라고 부르겠음)를 만들었걸랑요. X의 테이블속성에 TDataSet을 지정하면 자동으로 TDataset의 각 필드를 X의 각속성과 연결해주고 싶거든요. 그리고 X의 속성이 변하면 db를 갱신할 수 있게 하고 싶습니다.
델파이의 Component Palette 에서 Data Controls 페이지를 보면, 표준 콤포넌트를 DB 용으로 사용할수 있도록 바꾸어 놓은 것들이 많이 있다. 예를 들면, DBEdit, DBMemo 와 같은 것이다. 그 뿐 아니라, Additional 페이지에 있는 StringGrid 와 비슷한 DBGrid 도 있다. 그런데 DBEdit 가 Edit 에 단순히 데이터를 인식할수 있는 기능을 첨가한 것인데 반하여, DBGrid 와 같은 것은 단순히 StringGrid 에 데이터 인식 기능을 추가한 것은 아니다. 그 외에 DBGrid 만 가져야 할 복잡한 기능들을 많이 가지고 있으며, 또한 StringGrid 에서는 있지만 DBGrid 에서는 필요 없는 기능은 가지고 있지 않다.
만일 사용자가 이와 같이 단순히 데이터만 넘겨주는 것 이상으로 DB 만을 위한 새로운 컴포넌트가 필요한 경우는 별 수 없이 사용자가 해당 콤포넌트를 만들어야 할 것이다. 예를 들면, DB 에 들어있는 데이터의 종류에 따라 다른 문구를 출력해 주는 콤포넌트가 필요한 경우가 이런 경우이다.
그러면, 일단 위에서 예로 든 기능을 갖춘 간단한 컴포넌트를 만들어 보자.
unit DBLabel;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, dbCtrls, DB;
type
TDBNxLabel = class(TLabel)
private
{ Private declarations }
FDataLink : TFieldDataLink;
procedure FSetDataSource(Value : TDataSource);
function FGetDataSource:TDataSource;
procedure FSetDataField(Value : string);
function FGetDataField:string;
procedure FOnDataChange(Sender : TObject);
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
published
{ Published declarations }
property DataSource : TDataSource read FGetDataSource write FSetDataSource;
property DataField : string read FGetDataField write FSetDataField;
end;
procedure Register;
implementation
procedure TDBNxLabel.FSetDataSource(Value : TDataSource);
begin
FDataLink.DataSource := Value;
end;
function TDBNxLabel.FGetDataSource:TDataSource;
begin
Result := FDataLink.DataSource;
end;
procedure TDBNxLabel.FSetDataField(Value : string);
begin
FDataLink.FieldName := Value;
end;
function TDBNxLabel.FGetDataField:string;
begin
Result := FDataLink.FieldName;
end;
procedure TDBNxLabel.FOnDataChange(Sender : TObject);
begin
case FDataLink.Field.AsInteger of
1 : Caption := '1 입력';
2 : Caption := '2 입력';
3 : Caption := '3 입력';
end;
end;
constructor TDBNxLabel.Create(AOwner : TComponent);
begin
inherited;
FDataLink := TFieldDataLink.Create;
FDataLink.OnDataChange := FOnDataChange;
end;
destructor TDBNxLabel.Destroy;
begin
inherited;
FDataLink.Free;
end;
procedure Register;
begin
RegisterComponents('Samples', [TDBNxLabel]);
end;
end.
이 정도면 DB 를 인식하는 컴포넌트 중에 가장 간단한 것이다. 위의 컴포넌트는 지정된 Field 의 데이터가 1 이면 '1 입력', 2 이면 '2 입력', 3 이면 '3 입력' 이라고 출력해 주는 간단한, Label 에서 상속 받은 컴포넌트이다. 이러한 컴포넌트의 경우 1 개의 Field 만을 사용하며, 또한 단순히 데이터를 보여 주기만 한다. DBImage 같은 경우가 그러한 경우이다. 위의 소스를 잘 이해 한다면 DBImage 에서 지원되지 않는 그림 형식(예를 들면, GIF 같은 경우)을 지원하는 DBImageGif 와 같은 컴포넌트를 만들수 있다.
위에서 TFieldDataLink 라는 class 를 사용했는데, 이를 왜 사용 해야 하는지 궁금할 것이다. 먼저, 필자가 경험했던 일을 소개하자면, 전에 이러한 컴포넌트를 제작하는 일을 담당하게 되어 열심히 코딩을 하는데, 처음에는 TFieldDataLink 를 사용 하지 않고 바로 DataSource property 에 있는 DataSet property 를 이용하여 이벤트 처리를 하고, 데이터를 교환하는 방식으로 작성하였다. 그리고 그때 만든것은 지금것 처럼 단순히 DB 에서 읽어온 데이터를 보여 주는것 뿐 아니라 수정이 가능해야 했고, Field 도 한개가 아니고 전체 Field 를 모두 Access 해야 했다. 말하자면, DBGrid 와 같은 컴포넌트였다. 그런데, 앞서서 말한 방식대로 DataSet 를 직접 Access 해서 만들고 나니까 자꾸만 여러가지 문제가 발생하는 것이었다. 그래서 계속 인터넷을 뒤져가며 이에 대한 자료를 찾아본 결과 TDataLink 가 중간 관리를 담당 한다는 것을 알게 되었다. 아직도 이 DataLink 란 것이 정확히 무엇을 하는놈인지는 잘 모르지만, 한가지 확실한 것은 DB Access Component 를 만들때는 이것을 반드시 써야 한다는 점이다.
그러면, TDataLink 에 대해서 살펴보자.
먼저, TDataLink 에서 중요한 것들을 살펴보면,
property 들
ActiveRecord
- 내부 버퍼에 가지고 있는 레코드들 중의 현재 레코드를 나타낸다. 이 말이 무엇을 의미 하는지 좀 의아할 것이다. 예를 들면서 설명을 해 보면, DBGrid 에서 한번에 10 라인씩 보여 준다면, 이 10 라인 만큼을 버퍼에 가지고 있게 되는데, 이 중에서 현재 가리키고 있는 레코드를 나타 낸다는 것이다.
BufferCount
- 내부 버퍼의 크기를 정한다. 한번에 가지고 있어야 할 Record 의 갯수를 정한다. 앞에서와 같이 DBGrid 에서 10 라인을 보여주는 경우라면 이 property 를 10 으로 지정하면 된다.
DataSourceFixed
- DataSource 가 설정될 수 있는 상황 인지 알려준다. 현재 진행되는 작업이 끝나지 않은 상태에서, DataSource 가 바뀐다면 현재의 작업을 끝낼수가 없을 것이다. 이러한 경우는 이 property 가 True 로 setting 되러 DataSource 를 바꿀수 없는 상황임을 알려준다.
Editing
- 현재 DataSet 이 Edit 상태에 있는지를 나타낸다.
ReadOnly
- DataSet 이 수정이 가능한지를 나타낸다.
RecordCount
- 현재 내부 버퍼에 가지고 있는 Record 의 갯수를 나타낸다. BufferCount 가 10 인 경우라 하더라도 실제 Table 에 2 개의 Record 밖에 없다면, RecordCount 는 2 라는 값을 가질 것이다.
method 들
- ActiveChanged
protected level 에 존재하는 method 로 TDataLink 에서 상속받은 객체에서 처리하는 경우에 사용한다.
Active 상태가 바뀌면 호출된다.
- RecordChanged
역시 protected level 에 존재하며, Field 가 수정될 경우 호출된다.
이 외에도 자주 사용되는 프로퍼티나 메쏘드들이 많지만, 도움말에 잘 나와 있으므로 설명을 생략했다.
필자가 이에 관련된 Component 를 만들면서 제일 문제가 되었던 부분은 과연 어떻게 설계를 해야 하냐는 점이었다. 일반 콤포넌트와 제일 다른점은 외부에서 수정되는 내용이 이 콤포넌트가 나타내는 화면에 반영이 되어야 한다는 것이다. 만약, 이점을 고려하지 않고 제작에 들어간다면 나중에 흐름이 완전히 뒤엉켜 버리는 그런 느낌을 받게 될 것이다. 흐름이 뒤엉켜 버린다는 말의 의미는, 데이터 인식 콤포넌트의 경우 콤포넌트 내부에서 수정되는 내용이 DB 에 반영이 되고 다시 이것이 콤포넌트에 반영이 되게 되는데, 일반적인 콤포넌트의 경우는 이러한 과정을 거치지 않고 수정 사항이 바로 그 내부로 직접 반영되도록 하기 때문에, 만일 일반 콤포넌트와 같은 형식으로 만들게 된다면 수정 사항 반영이 2 번씩 되는 셈이 된다.
따라서, 위와 같이 수정을 할 때는 전적으로 DB 를 수정하고, 또한 그 수정에 대한 반응은 전적으로 DB 가 수정된 것에 대한 이벤트에 의해서 처리 되어야 한다. 이렇게 하기 위해서는 먼저 수정을 가하는 부분과 DB 가 수정된 것에 대해 반응하는 부분을 완전히 분리 하는것이 필요하다.
Data-Aware Component 를 만드는 방법에 대해서 개괄적으로 알아 보았다. 좀더 많은 내용을 소개했어야 하는데 하는 아쉬움이 남지만, 다음 기회로 미루도록 하고 이만 마치겠다.
파워러브 델파이 97년 12월호!!!
박성훈 wrote:
> 패널과 비슷한 모양의 컴포넌트(편의상 X라고 부르겠음)를 만들었걸랑요. X의 테이블속성에 TDataSet을 지정하면 자동으로 TDataset의 각 필드를 X의 각속성과 연결해주고 싶거든요. 그리고 X의 속성이 변하면 db를 갱신할 수 있게 하고 싶습니다.
> 이것 저것 생각하고 뒤져봤는데, 좀 가닥이 잡히질 않아서요.
>