Delphi Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
델파이 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
FreePascal/Lazarus
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
델마당
볼랜드포럼 광고 모집

델파이 강좌/문서
Delphi Programming Tutorial&Documents
[107] 디비그리드의 같은 값을 가진 셀병합(칼럼머지) 구현 예제
이경환.단디 [lncsoft] 9651 읽음    2006-09-15 13:10
디비그리드의 같은 값을 가진 셀병합(칼럼머지) 구현 예제

간만에 서울 올라갔다 내려오는길에 버스안에서 별로 할 짓도 없구해서 이것저것 생각하다가 문득 생각이 나길래 함 만들어 본 것입니다. 팁란에 올리려다 아래에 있는 임포스터 클래스 강좌와 같이 보는 게 나을 거 같아 여기에 올립니다.

아래에, 임포스터 클래스에 대해서 주정섭씨가 좋은 글을 써 주셨습니다.
주정섭님의 글에 대해서 김재철님이 좋은 댓글을 올려 주셨는데, 어차피 같은 내용으로 보여지므로 상황에 따라 편리한 방법을 선택하면 될 거 같습니다.

개발을 하다보면, DBGrid 콤포넌트의 기능이 약해서, 제3자 Grid 콤포넌트를 많이 사용하게 된다. 그런데, 그 덩치큰 삼자 Grid 콤포넌트의 전체 기능이 필요한 것이 아니고, 한두가지 기능만 필요한 경우가 많다.

더우기, 퀀텀그리드 같은 경우는 전체 레코드를 메모리에 로딩하기 때문에, 필요한 한두가지 기능때문에 쓰기는 참 사치스럽기까지 하다. 속도향상을 위해 메모리테이블을 써야 되는 경우도 있는데, 퀀텀에서 또 내부적으로 메모리테이블을 사용하므로 이런 경우 이중으로 메모리를 낭비하는 셈이 된다.

물론, 요즘 일반적 컴 사양에서 별무리가 아니라 하더라도, 한두가지 기능때문에 이런 식으로 퀀텀을 쓰기에는 소 잡는 칼로 닭 잡는 수가 될 수도 있다는 얘기다.

이 예제는, 인접하는 칼럼의 값이 같을 경우에, 이를 Merge하는 기능을 가진 그리드를 임포스터 방식으로 만든 것이다. 퀀텀 그리드의 경우 칼럼 머지 기능이라고 하는 것 같다. 혹은 그룹칼럼 머지 기능이라고도 하는 것 같다. 어떻게 동작하는지는 첨부한 예제를 실행해보면 알것이다. 예제를 실행하면, 이전 이후 레코드의 Category필드의 값이 같은 경우, 이를 병합해서 표시할 것이다.

주의) 컴파일시 kbmMemTable이 필요합니다. 
kbmMemTable 주소: www.components4programmers.com

썩 좋은 예제는 아니지만 필요한 분들에게 참고가 되길 바랍니다.

이하 소스...

// 가져다 쓰는 폼의 소스
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.
주정섭 [jjsverylong]   2006-09-15 13:52 X
아!!. 강좌 게시판에 다시 봄이 오려나... 좋은 강좌가 많아져야 하는데... 고맙슴니다. 경환님..

+ -

관련 글 리스트
107 디비그리드의 같은 값을 가진 셀병합(칼럼머지) 구현 예제 이경환.단디 9651 2006/09/15
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.