본문 바로가기
Delphi Tip/그리드

DBGrid 동일값 셀병합(컬럼머지)

by MonoSoft 2024. 5. 27.
728x90
반응형

DBGrid 동일값 셀병합

 

728x90

 

 

 

 

개발을 하다보면, DBGrid 콤포넌트의 기능이 약해서,

제3자 Grid 콤포넌트를 많이 사용하게 된다.

 

그런데, 그 덩치큰 삼자 Grid 콤포넌트의 전체 기능이 필요한 것이 아니고,

한두가지 기능만 필요한 경우가 많다.

더우기, 퀀텀그리드 같은 경우는 전체 레코드를 메모리에 로딩하기 때문에,

필요한 한두가지 기능때문에 쓰기는 참 사치스럽기까지 하다.

 

속도향상을 위해 메모리테이블을 써야 되는 경우도 있는데,

퀀텀에서 또 내부적으로 메모리테이블을 사용하므로

이런 경우 이중으로 메모리를 낭비하는 셈이 된다.

 

물론, 요즘 일반적 컴 사양에서 별무리가 아니라 하더라도,

한두가지 기능때문에 이런 식으로 퀀텀을 쓰기에는

소 잡는 칼로 닭 잡는 수가 될 수도 있다는 얘기다.

 

이 예제는, 인접하는 칼럼의 값이 같을 경우에,

이를 Merge하는 기능을 가진 그리드를 임포스터 방식으로 만든 것이다.

 

퀀텀 그리드의 경우 칼럼 머지 기능이라고 하는 것 같다.

혹은 그룹칼럼 머지 기능이라고도 하는 것 같다.

 

어떻게 동작하는지는 첨부한 예제를 실행해보면 알것이다.

예제를 실행하면, 이전 이후 레코드의 Category필드의 값이 같은 경우,

이를 병합해서 표시할 것이다.

 

주의) 컴파일할려면 kbmMemTable이 필요합니다.

물론 소스를 수정하면 다른 메모리테이블이나 리스트같은 걸 사용해도 가능합니다.

 

// 가져다 쓰는 폼의 소스

unit mainf;

interface

uses

..., dbgridext;

type

TDbGrid = class(TGroupDbGrid);

TForm1 = class(TForm)

Grid: TDBGrid;

....

procedure FormCreate(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

 

var

Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.FormCreate(Sender: TObject);

begin

// 그룹으로 보야줄 필드명

Grid.GroupFieldName:= 'Category';

// 라인은 깜박임을 줄이기 위해 내부에서 직접 그려준다.

// 오브젝트 인스펙터에서 설정해도 됨

// 임포스터 클래스에서 설정하면 오브젝트인스펙터 설정값이 우선함

Grid.Options:= Grid.Options - [dgColLines, dgRowLines];

end;

end.

// 그루핑디비그리드 임포스터 클래스

// 내부적으로 메모리 테이블을 사용한다.

unit

dbgridext;

 

interface

 

uses

Windows, Messages, Classes, SysUtils, Types, Variants, Graphics, Db, Grids, DBGrids, KBMMemTable;

 

type

TGroupDbGrid = class(TDbGrid)

private

FPaintCol, FPaintRow: Integer;

FGroupFieldName: String;

FDrawTable: TKbmMemtable;

procedure WMMouseWheel(var Message: TMessage); message WM_MOUSEWHEEL;

protected

procedure DrawCell(ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState); override;

procedure DrawColumnCell(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); override; procedure Scroll(Distance: Integer); override;

public

constructor Create(AOwner: TComponent); override;

destructor Destroy; override;

property PaintCol: Integer read FPaintCol;

property PaintRow: Integer read FPaintRow;

property GroupFieldName: string read FGroupFieldName write FGroupFieldName;

end;

 

implementation

 

constructor TGroupDbGrid.Create(AOwner: TComponent);

begin

inherited Create(AOwner);

inherited DefaultDrawing := False;

FPaintCol:= -1;

FPaintRow:= -1;

FDrawTable := TkbmMemTable.Create(Self);

with FDrawTable do

begin

FieldDefs.Add('Col', ftInteger);

FieldDefs.Add('Row', ftInteger);

FieldDefs.Add('Text', ftString, 30);

CreateTable;

Active := True;

end;

end;

 

destructor TGroupDbGrid.Destroy;

begin

// FDrawTable.Free;

// FDrawTable:= nil;

inherited Destroy;

end;

 

procedure TGroupDbGrid.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState);

begin

FPaintCol:= ACol;

FPaintRow:= ARow;

inherited DrawCell(ACol, ARow, ARect, AState);

if (gdFixed in AState) then

begin

DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);

DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_TOPLEFT);

end;

end;

 

procedure TGroupDbGrid.DrawColumnCell(const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);

var

R: TRect;

i: Integer;

b: Boolean;

X, Y: Integer;

begin

if (gdFixed in State) then Exit;

R:= Rect;

if AnsiCompareText(Column.FieldName, FGroupFieldName) <> 0 then

begin

x:= 2; y:= 2;

Canvas.TextRect(R, R.Left + x, R.Top + y, Column.Field.DisplayText);

R.Bottom:= R.Bottom - 1;

R.Right:= R.Right - 1;

Canvas.Pen.Color:= clSilver;

Canvas.MoveTo(R.Right, R.Top);

Canvas.LineTo(R.Right, R.Bottom);

Canvas.LineTo(R.Left, R.Bottom);

Exit;

end;

Canvas.Brush.Color := Color;

Canvas.Font.Color := Column.Font.Color; Canvas.FillRect(R);

with FDrawTable do if Locate('Col;Row', VarArrayOf([PaintCol, PaintRow]), []) then

begin

Edit;

FieldByName('Text').AsString:= Column.Field.AsString;

Post;

end

else

begin

Insert;

FieldByName('Col').AsInteger:= PaintCol;

FieldByName('Row').AsInteger:= PaintRow;

FieldByName('Text').AsString:= Column.Field.AsString;

Post;

end;

i:= 0;

b:= True;

if PaintRow > 0 then while b do

begin

Inc(i);

b:= FDrawTable.Locate('Col;Row', VarArrayOf([PaintCol, PaintRow - i]), []) and

(Column.Field.AsString = FDrawTable.FieldByName('Text').AsString);

end;

R.Top:= R.Top - ((R.Bottom - R.Top) * (i - 1));

x:= R.Left + 2; y:= R.Top + ((R.Bottom - R.Top - Canvas.TextHeight('W')) div 2);

Canvas.TextRect(R, x, y, Column.Field.DisplayText);

R.Bottom:= R.Bottom - 1;

R.Right:= R.Right - 1;

Canvas.Pen.Color:= clSilver;

Canvas.MoveTo(R.Right, R.Top);

Canvas.LineTo(R.Right, R.Bottom);

Canvas.LineTo(R.Left, R.Bottom);

end;

 

procedure TGroupDbGrid.Scroll(Distance: Integer);

begin

inherited;

Invalidate;

end;

 

procedure TGroupDbGrid.WMMouseWheel(var Message: TMessage);

var

i: SmallInt;

begin

i := HiWord(Message.wParam); if i > 0 then

Perform(WM_KeyDown, VK_UP, 0) else

Perform(WM_KeyDown, VK_DOWN, 0);

end;

end.

 

 

3_groupgrid.zip
0.46MB

728x90
반응형

댓글