这几天在学JS前端,贴一下我十年前写的DELPHI列表控件

unit MiniGrid;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, ExtCtrls, Graphics, ComCtrls, Dialogs, StdCtrls,
  Forms, MiniCombobox, MiniDTPicker, MiniButton, MiniBoxLabel;

const
  TEXT_LENGTH=64;

type
  //TEditControlType=(_Edit,_Combobox,_DTPicker); //某个单元格要编辑的类型。
  PEditCtrlInfo=^TEditCtrlInfo;
  TEditCtrlInfo=record //
      ACol: integer;
      ARow: integer;
      Text: string[TEXT_LENGTH];
      Ctrl: TWinControl;
  end;

type
  PBufText=^TBufText;
  TBufText=record
    Checked: Boolean;       //如果显示,则此元素代表值。
    ImageIndex: integer;    //显示图片的序号(TImageList的序号)
    BackColor: TColor;
    Text: array[0..TEXT_LENGTH-1] of Char; //string[64*SizeOf(Char)];array[0..ROW_BUFSIZE-1] of Char;
  end;

  TColData=record
     Caption: array[0..TEXT_LENGTH-1] of Char; //string[64*SizeOf(Char)];
       Width: WORD;
   Alignment: TAlignment;
ShowCheckBox: Boolean;        //是否显示选择框
        Text: Pointer;
  end;

const
  TITLEHEIGHT=19; //标题条的高度。
  SCROLLWIDTH=18; //滚动条的宽度。
  SCROLLMINHEIGHT=8; //滚动条最矮的高度。
  ROW_BUFSIZE=SizeOf(TBufText);

const
  WM_INPUTTEXT=WM_USER+35;

type
  TMiniGrid=class;
  TTitles=class;

  TTitle=class(TCollectionItem)
  private
    FWidth: WORD;
    FAlignment: TAlignment;
    FCaption: string;
    FShowCheckBox: Boolean;
    //FCollection: TTitles;
    procedure SetWidth(Value: WORD);
    procedure SetAlignment(Value: TAlignment);
    procedure SetCaption(Value: string);
    procedure SetShowCheckBox(Value: Boolean);
  protected
    function GetDisplayName: string; override;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property Width: WORD read FWidth write SetWidth;
    property Alignment: TAlignment read FAlignment write SetAlignment;
    property Caption: string read FCaption write SetCaption;
    property ShowCheckBox: Boolean read FShowCheckBox write SetShowCheckBox;
  end;

  TTitles=class(TCollection)
  private
    FMiniGrid: TMiniGrid;
    function GetItem(Index: integer): TTitle;
    procedure SetItem(Index: integer; Value: TTitle);
  protected
    procedure Update(Item: TCollectionItem); override;
    //procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); override;
  public
    constructor Create(MiniGrid: TMiniGrid);
    function Add: TTitle;
    procedure Delete(Index: Integer);
    property Items[Index: integer]: TTitle read GetItem write SetItem; default;
  end;

  TMouseState=(zxcDown,zxcUp);
  TOnScroll=procedure(Sender: TObject; CurrentTopID: integer) of Object;
  TMiniScroll=class(TCustomControl)
  private
    FOnScroll: TOnScroll;
    BL: Single;   //移动滚条一个点代表多少ROW的数量
    ScrlCount: integer;  //滚条可移动多少个点。
    FHideCount: integer;
    FShowRect: TRect;
    //CurrPosition: integer; //当前滚条的位置。
    //BarHeight: integer;
    MouseState: TMouseState;
    OldPoint: TPoint; //
    bkBitmap: TBitmap;
    procedure SetHideCount(Value: integer);
    procedure SetShowRect(Value: TRect);
    //procedure WMERASEBKGND(var Msg: TWMERASEBKGND);  message WM_ERASEBKGND;
    //procedure DrawScrollBar(NewPosition: integer);
  protected
    is3D: Boolean;
    procedure Paint; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    //procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
    procedure Change(TopRowID: integer);
    property OnScroll: TOnScroll read FOnScroll write FOnScroll;
    property HideCount: integer read FHideCount write SetHideCount;
    property ShowRect: TRect read FShowRect write SetShowRect;
  end;

  TEditType=(miniNUM,miniSINGLE,miniSTR);
  TEditBox = class(TEdit)
  private
    bkCtrl: TMiniBoxLabel;
    procedure ProcessInput;
    procedure WmKillFocus(var Msg: TMessage); message WM_KILLFOCUS;
    procedure CustomKeyPress(Sender: TObject; var Key: Char);
  public
    ARow: integer;
    ACol: integer;
    EditType: TEditType;
    constructor Create(Aowner: TComponent; bkBoxLabel: TMiniBoxLabel); overload;
    destructor Destroy; override;
  end;

  TComboboxBox = class(TMiniCombobox)
  private
    procedure ProcessInput;
    //procedure WmKillFocus(var Msg: TMessage); message WM_KILLFOCUS;
    procedure CustomKeyPress(Sender: TObject; var Key: Char);
    procedure CustomExit(Sender: TObject);
  public
    ARow: integer;
    ACol: integer;
    constructor Create(Aowner: TComponent); override;
  end;

  TDTPickerBox = class(TMiniDTPicker)
  private
    procedure ProcessInput;
    procedure WmKillFocus(var Msg: TMessage); message WM_KILLFOCUS;
    procedure CustomKeyPress(Sender: TObject; var Key: Char);
  public
    ARow: integer;
    ACol: integer;
    constructor Create(Aowner: TComponent); override;
  end;

  TOnMouseEnter=procedure(Sender: TObject) of Object;
  TOnMouseLeave=procedure(Sender: TObject) of Object;
  TOnSelectChanged=procedure(Sender: TObject; ARow: integer) of Object;
  TOnSetFontColor=procedure(Sender: TObject; ACol, ARow: integer; var RowColor: TColor) of object;
  TOnChecked=procedure(Sender: TObject; ACol,ARow: integer; Checked: Boolean) of Object;
  TOnSetEdit=procedure(Sender: TObject; ACol, ARow: integer; var CanEdit: Boolean; var EditType: TEditType; var MaxInputLength: integer) of object;
  TOnSetCombobox=procedure(Sender: TObject; ACol, ARow: integer; var CanEdit: Boolean; var Style: TComboboxStyle; var InputList: TStringList) of object;
  TOnSetDTPicker=procedure(Sender: TObject; ACol, ARow: integer; var CanEdit: Boolean; var ADateTime: TDateTime) of object;
  TOnSetMouseDown=procedure(Sender: TObject; Button: TMouseButton; ACol, ARow: integer; var CanEdit: Boolean; var AText: string) of object;
  TOnEditTextChanged=procedure(Sender: TObject; ACol, ARow: integer; Text: string) of object;

  TMiniGrid = class(TCustomControl)
  private
    FOnSelectChanged: TOnSelectChanged;
    FOnSetFontColor: TOnSetFontColor;
    FOnMouseEnter: TOnMouseEnter;
    FOnMouseLeave: TOnMouseLeave;
    FOnChecked: TOnChecked;
    FOnSetEdit: TOnSetEdit;
    FOnSetCombobox: TOnSetCombobox;
    FOnSetDTPicker: TOnSetDTPicker;
    FOnSetMouseDown: TOnSetMouseDown;
    FOnEditTextChanged: TOnEditTextChanged;

    FBackBitmap: TBitmap;
    //FBackPicture: TPicture;
    FShowTitle: Boolean;
    FTitles: TTitles;
    FTitleFont: TFont;
    FGridFont: TFont;
    FRowCount: integer;
    FRowHeight: integer;
    FShowScrollBar: Boolean;
    FShowSelection: Boolean;
    Fis3D: Boolean;
    FSelectionColor: TColor;
    SelectionID: integer;
    
    PenColor: TColor;
    TitleBitmap: TBitmap; //标题条的自定义位图
    _1BufferBtm: TBitmap; //整个控件的内存缓冲图。
    _2BufferBtm: TBitmap;
    Data: array of TColData; //网格数据
    GridTop: integer; //网格相对于本控件的Y轴位置。
    TopRowID: integer; //当前顶部所显示的Row的ID号.
    ShowRowCount: integer; //根据当前控件高度得到的显示的Row的数量。

    ScrollBar: TMiniScroll;
    FImageList: TImageList;
    FImgLstBitmap: TBitmap;

    procedure SetShowTitle(Value: Boolean);
    procedure SetTitles(Value: TTitles);
    procedure SetRowCount(Value: integer);
    procedure SetRowHeight(Value: integer);
    procedure SetShowSelection(Value: Boolean);
    procedure SetShowScrollBar(Value: Boolean);
    procedure Setis3D(Value: Boolean);
    procedure SetSelectionColor(Value: TColor);
    function GetCells(ACol, ARow: Integer): string;
    procedure SetCells(ACol, ARow: Integer; Value: string);
    procedure SetTitleFont(Value: TFont);
    procedure SetGridFont(Value: TFont);
    procedure AdjustParameter;
    procedure DrawTitles;

    function PointToColRow(Pt: TPoint; var ACol,ARow: integer): Boolean;
    procedure Show_Selection(NewARow,OldARow: integer);
    procedure WmSize(var Msg: TMessage); message WM_SIZE;

    procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
    procedure WmKeyDown(var Msg: TMessage); message WM_KEYDOWN;
    procedure WmMouseWheel(var Msg: TWmMouseWheel); message WM_MOUSEWHEEL;
    //procedure WmLbuttonDown(var Msg: TMessage); message WM_LBUTTONDOWN;
    procedure FontChanged(Sender: TObject);
    procedure ScrollChanged(Sender: TObject; CurrentTopID: integer);
    procedure DrawCell(ACol,ARow: integer);
    //procedure PictureChanged(Sender: TObject);

    procedure WmInputText(var Msg: TMessage); message WM_INPUTTEXT;
  protected
    procedure Paint; override;
    procedure CreateWnd; override;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure AdjustClientRect(var Rect: TRect); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure UpdateTitle(Item: TTitle);
    procedure UpdateTitles;
    procedure MouseEnter(var Msg: TMessage); message CM_MOUSEENTER;
    procedure MouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;
  public
    constructor Create(Aowner: TComponent); override;
    destructor Destroy; override;
    procedure DrawGrid;
    procedure Clear;
    function GetSelected: integer;
    function GetRowAt(X,Y: integer): integer;
    function GetColAt(X,Y: integer): integer;
    function Delete(ARow: integer): Boolean;
    function Add(ARow: integer): Boolean;
    procedure MoveRow(Direction: integer; MoveCount: integer);
    function ColRowToRect(ACol,ARow: integer; var R: TRect): Boolean;
    function GetChecked(ACol,ARow: integer): Boolean;
    procedure SetChecked(ACol,ARow: integer; Checked: Boolean);
    procedure SetImage(ImageList: TImageList);
    procedure SetCellImage(ACol,ARow: integer; ImageIndex: integer);
    procedure SetRowColor(ARow, Color: TColor);
    procedure SetBackgroudPicture(Picture: TBitmap);
    property Cells[ACol, ARow: Integer]: string read GetCells write SetCells;
  published
    property ShowTitle: Boolean read FShowTitle write SetShowTitle;
    property Titles: TTitles read FTitles write SetTitles;
    property RowCount: integer read FRowCount write SetRowCount;
    property RowHeight: integer read FRowHeight write SetRowheight;
    property ShowSelection: Boolean read FShowSelection write SetShowSelection;
    property ShowScrollBar: Boolean read FShowScrollBar write SetShowScrollBar;
    property TitleFont: TFont read FTitleFont write SetTitleFont;
    property GridFont: TFont read FGridFont write SetGridFont;
    //property BackPicture: TPicture read FBackPicture write SetBackPicture;
    property is3D: Boolean read Fis3D write Setis3D;
    property SelectionColor: TColor read FSelectionColor write SetSelectionColor;
    property Enabled;
    property Hint;
    property ShowHint;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Color;
    property Align;
    property OnSelectChanged: TOnSelectChanged read FOnSelectChanged write FOnSelectChanged;
    property OnSetFontColor: TOnSetFontColor read FOnSetFontColor write FOnSetFontColor;
    property OnMouseDown;
    property OnDblClick;
    property OnKeyDown;
    property OnkeyPress;
    property OnEnter;
    property OnExit;
    property OnDragDrop;
    property OnDragOver;
    property OnResize;
    property OnMouseEnter: TOnMouseEnter read FOnMouseEnter write FOnMouseEnter;
    property OnMouseLeave: TOnMouseLeave read FOnMouseLeave write FOnMouseLeave;
    property OnChecked: TOnChecked read FOnChecked write FOnChecked;
    property OnSetEdit: TOnSetEdit read FOnSetEdit write FOnSetEdit;
    property OnSetCombobox: TOnSetCombobox read FOnSetCombobox write FOnSetCombobox;
    property OnSetDTPicker: TOnSetDTPicker read FOnSetDTPicker write FOnSetDTPicker;
    property OnSetMouseDown: TOnSetMouseDown read FOnSetMouseDown write FOnSetMouseDown;
    property OnEditTextChanged: TOnEditTextChanged read FOnEditTextChanged write FOnEditTextChanged;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('MiniControl', [TMiniGrid]);
end;

{ TMiniGrid }

constructor TMiniGrid.Create(Aowner: TComponent);
var
  i,rC,gC,bC: integer;
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle+[csAcceptsControls];

  Width := 185;
  Height := 80;
  FShowTitle:=True;
  FRowCount:=0;
  FRowHeight:=20;
  FShowSelection:=False;
  FShowScrollBar:=False;
  Fis3D:=True;
  FSelectionColor:=clSkyBlue;
  PenColor:=RGB(0,200,255);
  ParentColor:=False;
  //Color:=$00F4F4F4;

  TitleBitmap:=TBitmap.Create;
  TitleBitmap.Width:=2;
  TitleBitmap.Height:=18;
  rC:=0; gC:=0; bC:=0;
  for i:=0 to 17 do
  begin
    TitleBitmap.Canvas.Pen.Color:=RGB(255-rC,255-gC,255-bC);
    TitleBitmap.Canvas.MoveTo(0,i);
    TitleBitmap.Canvas.LineTo(TitleBitmap.Width,i);
    Inc(rC,4);
    Inc(gC,3);
    Inc(bC,2);
  end;

  FTitleFont:=TFont.Create;
  FGridFont:=TFont.Create;
  FTitleFont.OnChange:=FontChanged;
  FGridFont.OnChange:=FontChanged;

  _1BufferBtm:=TBitmap.Create;
  _2BufferBtm:=TBitmap.Create;
  FBackBitmap:=TBitmap.Create;
  FBackBitmap.Width:=0;

  FTitles:=TTitles.Create(Self);

  FImageList:=nil;
  FImgLstBitmap:=TBitmap.Create;
end;

destructor TMiniGrid.Destroy;
var
  i: integer;
begin
  TitleBitmap.Free;
  _1BufferBtm.Free;
  _2BufferBtm.Free;
  FBackBitmap.Free;
  FTitleFont.Free;
  FGridFont.Free;       
  FTitles.Free;
  if ScrollBar<>nil then
    ScrollBar.Free;

  for i:=0 to High(Data) do
    if Data[i].Text<>nil then
      FreeMem(Data[i].Text,FRowCount*ROW_BUFSIZE);
  FImgLstBitmap.Free;
  inherited;
end;

procedure TMiniGrid.CreateWnd;
begin
  inherited;

  TopRowID:=0;
  SelectionID:=0;
  AdjustParameter;
end;

procedure TMiniGrid.AdjustParameter;
begin
  _1BufferBtm.Width:=Width;
  _1BufferBtm.Height:=Height;
  _2BufferBtm.Width:=Width;
  _2BufferBtm.Height:=Height;

  if FShowTitle then
  begin
    GridTop:=TITLEHEIGHT;
    if ((Height-TITLEHEIGHT) mod RowHeight-1)<>0 then
      ShowRowCount:=((Height-TITLEHEIGHT) div RowHeight)+1
    else
      ShowRowCount:=((Height-TITLEHEIGHT) div RowHeight);
  end
  else
  begin
    GridTop:=0;
    if (Height mod RowHeight)<>0 then
      ShowRowCount:=(Height div RowHeight)+1
    else
      ShowRowCount:=(Height div RowHeight);
  end;

  if FShowScrollBar and(ScrollBar<>nil) then
  begin
    ScrollBar.ShowRect:=Rect(Width-SCROLLWIDTH-2,GridTop+2,Width-2,Height-2);
    ScrollBar.HideCount:=FRowCount-ShowRowCount;
  end;
end;

procedure TMiniGrid.AdjustClientRect(var Rect: TRect);
begin
  //AdjustParameter;
  inherited AdjustClientRect(Rect);
end;

procedure TMiniGrid.WmSize(var Msg: TMessage);
begin
  AdjustParameter; //重新调整坐标等参数。
  inherited;      //调整后调用默认的过程重新画控件。
end;

function TMiniGrid.ColRowToRect(ACol, ARow: integer; var R: TRect): Boolean;
var
  i,X,Y: integer;
begin
  Result:=False;
  if (FRowCount>0)and(ACol in[0..High(Data)])and(ARow>=TopRowID)and(ARow<=(TopRowID+ShowRowCount-1)) then
  begin
    X:=0;
    for i:=0 to ACol do
      Inc(X,Data[i].Width);
    Y:=GridTop;
    for i:=TopRowID to ARow do
      Inc(Y,RowHeight);

    R:=Rect(X-Data[ACol].Width+1,Y-RowHeight+1,X,Y); //是某个格子的内框。
    Result:=True;
  end;
end;

function TMiniGrid.GetCells(ACol, ARow: Integer): string;
var
  lpText: PBufText;
begin
  Result:='';
  if (ACol in[0..High(Data)])and(ARow>=0)and(ARow<=(FRowCount-1)) then
  begin
    lpText:=Data[ACol].Text;
    Inc(lpText,ARow);
    Result:=lpText^.Text;
  end;
end;

procedure TMiniGrid.SetCells(ACol, ARow: Integer; Value: string);
var
  lpText: PBufText;
begin
  if (not (ACol in[0..High(Data)]))or(ARow<0)or(ARow>(FRowCount-1)) then
    Exit;

  lpText:=Data[ACol].Text;
  Inc(lpText,ARow);
  if Length(Value)>TEXT_LENGTH then
    System.Delete(Value,TEXT_LENGTH+1,Length(Value)-TEXT_LENGTH);
  //lpText^.Text:=Value;
  ZeroMemory(@lpText^.Text,Length(lpText^.Text)*SizeOf(Char));
  CopyMemory(@lpText^.Text,Pointer(Value),Length(Value)*SizeOf(Char));

  if (ARow>=TopRowID)and(ARow<=(TopRowID+ShowRowCount-1)) then //说明设置的格子是在当前显示区域内。则要重新画相应的格子。
  begin
    _1BufferBtm.Canvas.Font:=GridFont;
    DrawCell(ACol,ARow);
    if FShowSelection and(ARow=SelectionID) then
      Show_Selection(SelectionID,-1);
  end;
end;

procedure TMiniGrid.SetRowCount(Value: integer);
var
  i: integer;
begin
  if Value<0 then
    Exit;
  if FRowCount<>Value then
  begin
    if not (csDesigning in ComponentState) then
      for i:=0 to High(Data) do
      begin
        if Data[i].Text=nil then //第一次分配。
        begin
          ReallocMem(Data[i].Text,Value*ROW_BUFSIZE);
          ZeroMemory(Data[i].Text,Value*ROW_BUFSIZE);
        end
        else      //再次调整内存大小。
        begin
          ReallocMem(Data[i].Text,Value*ROW_BUFSIZE);
          if Value>FRowCount then //如果是把内存变大,需要清空增加的内存。
            ZeroMemory(Pointer(DWORD(Data[i].Text)+FRowCount*ROW_BUFSIZE),(Value-FRowCount)*ROW_BUFSIZE);
        end;
      end;

    TopRowID:=0;
    SelectionID:=0;
    FRowCount:=Value;
    AdjustParameter;
    DrawGrid;
    //Repaint;
  end;
end;

procedure TMiniGrid.SetRowHeight(Value: integer);
begin
  if Value<=0 then
    Exit;
  if FRowHeight<>Value then
  begin
    FRowheight:=Value;
    AdjustParameter;
    Invalidate;
  end;
end;

procedure TMiniGrid.SetShowTitle(Value: Boolean);
begin
  if Value<>FShowTitle then
  begin
    FShowTitle:=Value;
    AdjustParameter;
    Invalidate;
  end;
end;

procedure TMiniGrid.SetTitles(Value: TTitles);
begin
  FTitles.Assign(Value);
end;

procedure TMiniGrid.DrawTitles;
var
  i,X: integer;
  R: TRect;
  Text: string;
begin
  if FShowTitle then
  begin
    Canvas.Font:=FTitleFont;
    if Fis3D then
      Canvas.CopyRect(Rect(1,1,Width-1,TITLEHEIGHT),TitleBitmap.Canvas,Rect(1,0,TitleBitmap.Width,TitleBitmap.Height))
    else
      if FBackBitmap.Width>0 then
        BitBlt(Canvas.Handle,1,1,Width-2,TITLEHEIGHT,FBackBitmap.Canvas.Handle,1,1,SRCCOPY)
      else
        Canvas.FillRect(Rect(1,1,Width-1,TITLEHEIGHT));
    Canvas.MoveTo(1,TITLEHEIGHT);
    Canvas.LineTo(Width-1,TITLEHEIGHT);

    SetBkMode(Canvas.Handle,TRANSPARENT);
    //Canvas.Brush.Style:=bsClear;
    //GetTextExtentPoint(Canvas.Handle,'MINI',Length('MINI'),Size);
    X:=0;
    for i:=0 to High(Data) do
    begin
      R:=Rect(X+1,1,X+Data[i].Width-1,TITLEHEIGHT-1);
      X:=X+Data[i].Width;
      Canvas.MoveTo(X,1);
      Canvas.LineTo(X,TITLEHEIGHT);
      Text:=Data[i].Caption;
      DrawText(Canvas.Handle,PChar(Text),Length(Text),R,DT_CENTER or DT_VCENTER or DT_SINGLELINE);
    end;
  end;
end;

procedure TMiniGrid.DrawGrid;
var
  i,j,X,Y,lCCount,lRCount: integer;
begin
  _1BufferBtm.Canvas.Font:=FGridFont;
  _1BufferBtm.Canvas.Pen.Color:=PenColor;
  _1BufferBtm.Canvas.Brush.Style:=bsSolid;
  _1BufferBtm.Canvas.Brush.Color:=Color;

  if FBackBitmap.Width>0 then
  begin
    BitBlt(_1BufferBtm.Canvas.Handle,1,GridTop+1,Width-2,Height-2,FBackBitmap.Canvas.Handle,1,GridTop+1,SRCCOPY);
    BitBlt(_2BufferBtm.Canvas.Handle,1,GridTop+1,Width-2,Height-2,FBackBitmap.Canvas.Handle,1,GridTop+1,SRCCOPY);
  end
  else
    _1BufferBtm.Canvas.FillRect(Rect(1,GridTop+1,Width-1,Height-1));

  if FRowCount>0 then
  begin
    if (FRowCount-TopRowID)<ShowRowCount then
      lRCount:=FRowCount-TopRowID
    else
      lRCount:=ShowRowCount;

    lCCount:=Length(Data);
    X:=0;
    for i:=0 to lCCount-1 do
    begin
      X:=X+Data[i].Width;
      _1BufferBtm.Canvas.MoveTo(X,GridTop);
      _1BufferBtm.Canvas.LineTo(X,GridTop+(lRCount*RowHeight)+1);

      Y:=GridTop;
      for j:=TopRowID to TopRowID+lRCount-1 do
      begin
        if Data[i].Text<>nil then //not(csDesigning in ComponentState) then
          DrawCell(i,j);
        if i=lCCount-1 then //i的最后一次循环时画ROW的横线。
        begin
          _1BufferBtm.Canvas.MoveTo(0,Y+RowHeight);
          _1BufferBtm.Canvas.LineTo(X,Y+RowHeight);
        end;
        Inc(Y,RowHeight);
      end;
    end;
  end;
  Canvas.CopyRect(Rect(1,GridTop+1,Width-1,Height-1),_1BufferBtm.Canvas,Rect(1,GridTop+1,Width-1,Height-1));
  if FShowSelection then
    Show_Selection(SelectionID,-1);
end;

procedure TMiniGrid.DrawCell(ACol, ARow: integer);
var
  R,R1: TRect;
  Size: TSize;
  Text: string;
  lpText: PBufText;
  lColor: TColor;
begin
  if Data[ACol].Text<>nil then
  begin
    lpText:=Data[ACol].Text;
    Inc(lpText,ARow);
    Text:=lpText^.Text;
    ColRowToRect(ACol,ARow,R);
    if FBackBitmap.Width>0 then
      Bitblt(_1BufferBtm.Canvas.Handle,R.Left,R.Top,R.Right-R.Left,R.Bottom-R.Top,_2BufferBtm.Canvas.Handle,R.Left,R.Top,SRCCOPY)
    else
    begin
      _1BufferBtm.Canvas.Brush.Style:=bsSolid;
      if lpText^.BackColor>0 then
        _1BufferBtm.Canvas.Brush.Color:=lpText^.BackColor
      else
        _1BufferBtm.Canvas.Brush.Color:=Color;
      {if Self.FShowSelection and (Self.GetSelected=ARow) then
        _1BufferBtm.Canvas.Brush.Color:=Self.FSelectionColor; }
      _1BufferBtm.Canvas.FillRect(R);
    end;
    _1BufferBtm.Canvas.Brush.Style:=bsClear;

    R1:=R;
    if Data[ACol].ShowCheckBox then
    begin
      _1BufferBtm.Canvas.Rectangle(R.Left+2,R.Top+2,R.Left+2+15,R.Top+2+15);//R.Bottom-1);
      if lpText^.Checked then
      begin
        R1:=Rect(R.Left+2,R.Top+2,R.Left+2+15,R.Top+2+15);
        _1BufferBtm.Canvas.Pen.Color:=PenColor;
        _1BufferBtm.Canvas.Pen.Width:=2;
        _1BufferBtm.Canvas.MoveTo(R1.Left+3,R1.Top+5);
        _1BufferBtm.Canvas.LineTo(R1.Left+3,R1.Bottom-3);
        _1BufferBtm.Canvas.LineTo(R1.Right-3,R1.Top+3);
        _1BufferBtm.Canvas.Pen.Width:=1;
        //_1BufferBtm.Canvas.Pen.Color:=PenColor;
      end;
      R1.Left:=R1.Right+1;
    end;

    if (lpText^.ImageIndex>0)and(FImageList<>nil) then
    begin
      FImgLstBitmap.Canvas.FillRect(Rect(0,0,FImgLstBitmap.Width,FImgLstBitmap.Height));
      if FImageList.GetBitmap(lpText^.ImageIndex-1,FImgLstBitmap) then
      begin
        Size.cx:=0; Size.cy:=0;
        if Text<>'' then
          GetTextExtentPoint(_1BufferBtm.Canvas.Handle,PChar(Text),Length(Text),Size);
        case Data[ACol].Alignment of
          taLeftJustify: ;
         taRightJustify: R1.Left:=R1.Right-(16+1+Size.cx);
               taCenter: R1.Left:=R1.Left+(((R1.Right-R1.Left)-(16+1+Size.cx)) div 2);
        end;
        TransparentBlt(_1BufferBtm.Canvas.Handle,R1.Left,R1.Top+((R1.Bottom-R1.Top-16)div 2),16,16,FImgLstBitmap.Canvas.Handle,
                     0,0,FImgLstBitmap.Width,FImgLstBitmap.Height,FImgLstBitmap.Canvas.Pixels[0,FImgLstBitmap.Height-1]);
        R1.Left:=R1.Left+1+16+1;
        R1.Right:=R1.Left+Size.cx;
      end;
    end;

    if Text<>'' then
    begin
      //SetBkMode(_1BufferBtm.Canvas.Handle,TRANSPARENT);
      lColor:=0;
      if Assigned(FOnSetFontColor) then
      begin
        lColor:=FGridFont.Color;
        FOnSetFontColor(Self,ACol,ARow,lColor);
        _1BufferBtm.Canvas.Font.Color:=lColor;
      end;
      //R1.Left:=R1.Left+1;
      case Data[ACol].Alignment of
        taLeftJustify: DrawText(_1BufferBtm.Canvas.Handle,PChar(Text),Length(Text),R1,DT_LEFT or DT_VCENTER or DT_SINGLELINE);
       taRightJustify: DrawText(_1BufferBtm.Canvas.Handle,PChar(Text),Length(Text),R1,DT_RIGHT or DT_VCENTER or DT_SINGLELINE);
             taCenter: DrawText(_1BufferBtm.Canvas.Handle,PChar(Text),Length(Text),R1,DT_CENTER or DT_VCENTER or DT_SINGLELINE);
      end;
      if _1BufferBtm.Canvas.Font.Color<>FGridFont.Color then
        _1BufferBtm.Canvas.Font.Color:=FGridFont.Color;
    end;
    if R.Bottom>(Height-1) then
      R.Bottom:=Height-1;
    if R.Right>(Width-1) then
      R.Right:=Width-1;
    Canvas.CopyRect(R,_1BufferBtm.Canvas,R);
  end;
end;

procedure TMiniGrid.Paint;
begin
  Canvas.Pen.Color:=PenColor;
  Canvas.Brush.Style:=bsSolid;
  Canvas.Brush.Color:=Color;
  Canvas.Rectangle(0,0,Width,Height);

  {if FBackBitmap.Width>0 then
  begin
    SetStretchBltMode(_1BufferBtm.Canvas.Handle, HALFTONE); //防止图片缩小时失真。
    SetStretchBltMode(_2BufferBtm.Canvas.Handle, HALFTONE); //防止图片缩小时失真。
    StretchBlt(_1BufferBtm.Canvas.Handle,1,1,Width-2,Height-2,FBackBitmap.Canvas.Handle,0,0,FBackBitmap.Width,FBackBitmap.Height,SRCCOPY);
    StretchBlt(_2BufferBtm.Canvas.Handle,1,1,Width-2,Height-2,FBackBitmap.Canvas.Handle,0,0,FBackBitmap.Width,FBackBitmap.Height,SRCCOPY);
  end
  else
    _1BufferBtm.Canvas.FillRect(Rect(1,GridTop+1,Width-1,Height-1));  }

  if Length(Data)>0 then
  begin
    if FShowTitle then
      DrawTitles;

    DrawGrid;
  end;
end;

procedure TMiniGrid.UpdateTitle(Item: TTitle);
var
  X: integer;
begin
  if Titles.Count>0 then
  begin
    X:=Item.Index;
    //Data[X].Caption:=Item.Caption;
    ZeroMemory(@Data[X].Caption,Length(Data[X].Caption)*SizeOf(Char));
    CopyMemory(@Data[X].Caption,Pointer(Item.Caption),Length(Item.Caption)*SizeOf(Char));
    Data[X].Width:=Item.Width;
    Data[X].Alignment:=Item.Alignment;
    Data[X].ShowCheckBox:=Item.ShowCheckBox;
      //SetLength(FData[i].Text,FRowCount);
    Invalidate;
  end;                   
end;

procedure TMiniGrid.UpdateTitles;
var
  i: integer;
begin
  if Length(Data)>0 then
  begin                           
    for i:=0 to High(Data) do
      if Data[i].Text<>nil then
      begin
        FreeMem(Data[i].Text,FRowCount*ROW_BUFSIZE);
        Data[i].Text:=nil;
      end;
    SetLength(Data,0);
    Data:=nil;
  end;
  if Titles.Count>0 then
  begin
    SetLength(Data,Titles.Count);
    for i:=0 to High(Data) do
    begin
      ZeroMemory(@Data[i].Caption,Length(Data[i].Caption)*SizeOf(Char));
      CopyMemory(@Data[i].Caption,Pointer(Titles.Items[i].Caption),Length(Titles.Items[i].Caption)*SizeOf(Char));
      //Data[i].Caption:=Titles.Items[i].Caption;
      Data[i].Width:=Titles.Items[i].Width;
      Data[i].Alignment:=Titles.Items[i].Alignment;
      Data[i].ShowCheckBox:=Titles.Items[i].ShowCheckBox;
      {if not (csDesigning in ComponentState) then
      begin
        GetMem(Data[i].Text,FRowCount*ROW_BUFSIZE); 
        ZeroMemory(Data[i].Text,FRowCount*ROW_BUFSIZE);
      end;  }
    end;
  end;              
  Invalidate;
end;

procedure TMiniGrid.Show_Selection(NewARow,OldARow: integer);
var
  i: integer;
  R,R1: TRect;
  Size: TSize;
  Text: string;
  lpText: PBufText;
  lColor: TColor;
begin
  if (not FShowSelection) or (FRowCount=0) then
    Exit;
  if ColRowToRect(High(Data),OldARow,R) then
  begin
    R.Left:=1;
    if R.Bottom>(Height-1) then
      R.Bottom:=Height-1;
    if R.Right>(Width-1) then
      R.Right:=Width-1;
    Canvas.CopyRect(R,_1BufferBtm.Canvas,R); //恢复老的选择区域。
  end;

  if ColRowToRect(High(Data),NewARow,R) then  //画新的选择区域。
  begin
    Canvas.Font:=Self.GridFont;
    for i:=0 to High(Data) do
      if Data[i].Text<>nil then
      begin
        lpText:=Data[i].Text;
        Inc(lpText,NewARow);
        Text:=lpText^.Text;
        ColRowToRect(i,NewARow,R);
        Canvas.Brush.Color:=FSelectionColor;
        Canvas.FillRect(R);

        R1:=R;
        if Data[i].ShowCheckBox then
        begin
          Canvas.Rectangle(R.Left+2,R.Top+2,R.Left+2+15,R.Top+2+15);//R.Bottom-1);
          if lpText^.Checked then
          begin
            R1:=Rect(R.Left+2,R.Top+2,R.Left+2+15,R.Top+2+15);
            Canvas.Pen.Color:=PenColor;
            Canvas.Pen.Width:=2;
            Canvas.MoveTo(R1.Left+3,R1.Top+5);
            Canvas.LineTo(R1.Left+3,R1.Bottom-3);
            Canvas.LineTo(R1.Right-3,R1.Top+3);
            Canvas.Pen.Width:=1;
          end;
          R1.Left:=R1.Right+1;
        end;

        if (lpText^.ImageIndex>0)and(FImageList<>nil) then
        begin
          FImgLstBitmap.Canvas.FillRect(Rect(0,0,FImgLstBitmap.Width,FImgLstBitmap.Height));
          if FImageList.GetBitmap(lpText^.ImageIndex-1,FImgLstBitmap) then
          begin
            Size.cx:=0; Size.cy:=0;
            if Text<>'' then
              GetTextExtentPoint(Canvas.Handle,PChar(Text),Length(Text),Size);
            case Data[i].Alignment of
              taLeftJustify: ;
             taRightJustify: R1.Left:=R1.Right-(16+1+Size.cx);
                   taCenter: R1.Left:=R1.Left+(((R1.Right-R1.Left)-(16+1+Size.cx)) div 2);
            end;
            TransparentBlt(Canvas.Handle,R1.Left,R1.Top+((R1.Bottom-R1.Top-16)div 2),16,16,FImgLstBitmap.Canvas.Handle,
                         0,0,FImgLstBitmap.Width,FImgLstBitmap.Height,FImgLstBitmap.Canvas.Pixels[0,FImgLstBitmap.Height-1]);
            R1.Left:=R1.Left+1+16+1;
            R1.Right:=R1.Left+Size.cx;
          end;
        end;

        if Text<>'' then
        begin
          //SetBkMode(_1BufferBtm.Canvas.Handle,TRANSPARENT);
          lColor:=0;
          if Assigned(FOnSetFontColor) then
          begin
            lColor:=FGridFont.Color;
            FOnSetFontColor(Self,i,NewARow,lColor);
            Canvas.Font.Color:=lColor;
          end;
          case Data[i].Alignment of
            taLeftJustify: DrawText(Canvas.Handle,PChar(Text),Length(Text),R1,DT_LEFT or DT_VCENTER or DT_SINGLELINE);
           taRightJustify: DrawText(Canvas.Handle,PChar(Text),Length(Text),R1,DT_RIGHT or DT_VCENTER or DT_SINGLELINE);
                 taCenter: DrawText(Canvas.Handle,PChar(Text),Length(Text),R1,DT_CENTER or DT_VCENTER or DT_SINGLELINE);
          end;
          if Canvas.Font.Color<>FGridFont.Color then
            Canvas.Font.Color:=FGridFont.Color;
        end;
      end;
    if ColRowToRect(High(Data),NewARow,R) then
      if R.Bottom>(Height-1) then
      begin
        Canvas.Pen.Color:=PenColor;
        Canvas.MoveTo(0,Height-1);
        Canvas.LineTo(Width,Height-1);
      end;
    {R.Left:=1;
    //R.Top:=R.Top+1;
    //R.Bottom:=R.Bottom-1;
    if R.Bottom>(Height-1) then
      R.Bottom:=Height-1;
    if R.Right>(Width-1) then
      R.Right:=Width-1;
    //Canvas.Brush.Color:=clSkyBlue;
    //Canvas.FillRect(R);
    Bitblt(Canvas.Handle,R.Left,R.Top,R.Right-R.Left,R.Bottom-R.Top,_1BufferBtm.Canvas.Handle,R.Left,R.Top,SRCCOPY);//NOTSRCCOPY);
    Canvas.Brush.Style:=bsClear;
    Canvas.Pen.Color:=clBlack;
    Canvas.Rectangle(R);   }
    //TransparentBlt(Canvas.Handle,R.Left,R.Top,R.Right-R.Left,R.Bottom-R.Top,_1BufferBtm.Canvas.Handle,R.Left,R.Top,R.Right-R.Left,R.Bottom-R.Top,clRed);
  end;

  if Assigned(FOnSelectChanged) and (OldARow<>-1) and (NewARow<>OldARow) then
    FOnSelectChanged(Self,NewARow);
end;

procedure TMiniGrid.MoveRow(Direction: integer; MoveCount: integer);
begin
  case Direction of
    VK_UP: begin  //上移动
             if FShowSelection then
             begin
               if (SelectionID-MoveCount)>=0 then
               begin
                 if ((SelectionID-MoveCount)>=TopRowID)and((SelectionID-MoveCount)<=(TopRowID+ShowRowCount-1)) then  //如果在当前显示范围内。
                 begin
                   Dec(SelectionID,MoveCount);
                   Show_Selection(SelectionID,SelectionID+MoveCount);
                 end
                 else
                 begin
                   Dec(SelectionID,MoveCount);
                   if (TopRowID-MoveCount)=SelectionID then
                     TopRowID:=SelectionID
                   else
                   begin
                     TopRowID:=SelectionID-ShowRowCount+1;
                     if TopRowID<0 then
                       TopRowID:=0;
                   end;

                   DrawGrid;
                   Show_Selection(SelectionID,SelectionID-MoveCount);

                   if FShowScrollBar and(ScrollBar<>nil) then
                     ScrollBar.Change(TopRowID);
                 end;
               end
               else
                 if TopRowID>0 then
                 begin
                   TopRowID:=0;
                   DrawGrid;
                   Show_Selection(SelectionID,-1);

                   if FShowScrollBar and(ScrollBar<>nil) then
                     ScrollBar.Change(TopRowID);
                 end;
             end
             else
               if TopRowID>0 then
               begin
                 Dec(TopRowID);
                 DrawGrid;

                  if ScrollBar.Visible then
                    ScrollBar.Change(TopRowID);
               end;
           end;
  VK_DOWN: begin  //下移动
             if FShowSelection then
             begin
               if (SelectionID+MoveCount)<=(FRowCount-1) then
               begin
                 if ((SelectionID+MoveCount)>=TopRowID)and((SelectionID+MoveCount)<=(TopRowID+ShowRowCount-1)) then
                 begin
                   Inc(SelectionID,MoveCount);
                   Show_Selection(SelectionID,SelectionID-MoveCount);
                 end
                 else
                 begin
                   Inc(SelectionID,MoveCount);
                   TopRowID:=SelectionID-ShowRowCount+1;
                   if TopRowID<0 then
                     TopRowID:=0;
                   DrawGrid;
                   Show_Selection(SelectionID,SelectionID-MoveCount);

                   if FShowScrollBar and(ScrollBar<>nil) then
                     ScrollBar.Change(TopRowID);
                 end;
               end
               else
                 if TopRowID<(SelectionID-ShowRowCount+2) then
                 begin
                   TopRowID:=SelectionID-ShowRowCount+2;
                   //Inc(TopRowID);
                   DrawGrid;
                   Show_Selection(SelectionID,SelectionID-1);

                    if FShowScrollBar and(ScrollBar<>nil) then
                      ScrollBar.Change(TopRowID);
                 end;
             end
             else
               if (TopRowID+ShowRowCount)<=FRowCount then
               begin
                 Inc(TopRowID);
                 DrawGrid;

                 if FShowScrollBar and(ScrollBar<>nil) then
                   ScrollBar.Change(TopRowID);
               end;
           end;
  end;
end;

procedure TMiniGrid.WmKeyDown(var Msg: TMessage);
begin
  inherited;
  case Msg.WParam of
      VK_UP: MoveRow(VK_UP,1);  //上移动
    VK_DOWN: MoveRow(VK_DOWN,1); //下移动
  end;
end;

procedure TMiniGrid.WmMouseWheel(var Msg: TWmMouseWheel);
begin
  if Msg.WheelDelta>0 then  //上移动
    MoveRow(VK_UP,1)
  else //下移动
    MoveRow(VK_DOWN,1);
end;

procedure TMiniGrid.WMGetDlgCode(var Msg: TWMGetDlgCode);
begin
  Msg.Result:=DLGC_WANTARROWS;  //防止移动方向键时移动控件的焦点!!!
end;

procedure TMiniGrid.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do
    Style:=Style or WS_TABSTOP;
end;

function TMiniGrid.PointToColRow(Pt: TPoint; var ACol,
  ARow: integer): Boolean;
var
  X,Y,i,j,lRCount: integer;
begin
  Result:=False;
  if (TopRowID+ShowRowCount)<=FRowCount then
    lRCount:=TopRowID+ShowRowCount
  else
    lRCount:=FRowCount;

  X:=0;
  for i:=0 to High(Data) do
  begin
    Inc(X,Data[i].Width);
    Y:=GridTop;
    for j:=TopRowID to lRCount-1 do
    begin
      Inc(Y,RowHeight);
      if PtInRect(Rect(1,Y-RowHeight, X-1,Y),Pt) then
      begin
        ACol:=i;
        ARow:=j;
        Result:=True;
        Break;
      end;
    end;
    if Result then
      Break;
  end;
end;

{procedure TMiniGrid.WmLbuttonDown(var Msg: TMessage);
var
  OldID,ACol,ARow: integer;
  CurrP: TPoint;
begin
  inherited;
  Windows.SetFocus(Self.Handle);
  CurrP:=Point(Msg.LParamLo,Msg.LParamHi);
  //Windows.ScreenToClient(Handle,CurrP);
  if PointToColRow(CurrP,ACol,ARow) then
    if ARow<>SelectionID then
    begin
      OldID:=SelectionID;
      SelectionID:=ARow;
      Show_Selection(SelectionID,OldID);
    end;
end;   }

procedure TMiniGrid.Clear;
var
  i: integer;
begin
  FRowCount:=0;
  TopRowID:=0;
  SelectionID:=0;
  for i:=0 to High(Data) do
    if Data[i].Text<>nil then
    begin
      FreeMem(Data[i].Text,FRowCount*ROW_BUFSIZE);
      Data[i].Text:=nil;
    end;

  //AdjustParameter;
  if FShowScrollBar then
    ScrollBar.HideCount:=0;

  DrawGrid;
  //Invalidate;
end;

procedure TMiniGrid.SetShowSelection(Value: Boolean);
begin
  if FShowSelection<>Value then
  begin
    FShowSelection:=Value;
    SelectionID:=TopRowID;
    Invalidate;
  end;
end;

procedure TMiniGrid.SetGridFont(Value: TFont);
begin
  FGridFont.Assign(Value);
end;

procedure TMiniGrid.SetTitleFont(Value: TFont);
begin
  FTitleFont.Assign(Value);
end;

procedure TMiniGrid.SetBackgroudPicture(Picture: TBitmap);
begin
  FBackBitmap.Assign(Picture);
  Invalidate;
end;

procedure TMiniGrid.FontChanged(Sender: TObject);
begin
  Invalidate;
end;

procedure TMiniGrid.ScrollChanged(Sender: TObject; CurrentTopID: integer);
begin
  TopRowID:=CurrentTopID;
  DrawGrid;
  if FShowSelection then
    if (SelectionID>=TopRowID)and(SelectionID<=(TopRowID+ShowRowCount-1)) then
      Show_Selection(SelectionID,-1);
end;

procedure TMiniGrid.SetShowScrollBar(Value: Boolean);
begin
  if FShowScrollBar<>Value then
  begin
    FShowScrollBar:=Value;
    if FShowScrollBar then
    begin
      ScrollBar:=TMiniScroll.Create(Self);
      ScrollBar.Parent:=Self;
      ScrollBar.ShowRect:=Rect(Width-SCROLLWIDTH-2,GridTop+2,Width-2,Height-2);  //GridTop+4
      ScrollBar.HideCount:=FRowCount-ShowRowCount;
      ScrollBar.OnScroll:=ScrollChanged;
      ScrollBar.Show;
    end
    else
      if ScrollBar<>nil then
      begin
        ScrollBar.Free;
        ScrollBar:=nil;
      end;
  end;
end;

procedure TMiniGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  i,OldID,ACol,ARow: integer;
  CurrP: TPoint;
  lpText:PBufText;
  lColor: TColor;
  lCanEdit: Boolean;
  lEditType: TEditType;
  lMaxInputLength: integer;
  cStyle: TComboboxStyle;
  InputList: TStringList;
  ADateTime: TDateTime;
  AText: string;
  R: TRect;
  Edit_: TEditBox;
  BoxLabel_: TMiniBoxLabel;
  Combobox_: TComboboxBox;
  DTPicker_: TDTPickerBox;
  isEdited: Boolean;
  DC: HDC;
  Size: TSize;
begin
  isEdited:=False;

  Windows.SetFocus(Self.Handle);
  CurrP:=Point(X,Y);
  if PointToColRow(CurrP,ACol,ARow) then
  begin
    OldID:=-1;
    if ARow<>SelectionID then
    begin
      OldID:=SelectionID;
      SelectionID:=ARow;
    end;
    Show_Selection(SelectionID,OldID);

    //if Button=mbLeft then

    if Assigned(FOnSetEdit) then
    begin
      lCanEdit:=False;
      lEditType:=miniSTR;
      lMaxInputLength:=0;
      FOnSetEdit(Self,ACol,ARow,lCanEdit,lEditType,lMaxInputLength);
      if lCanEdit and ColRowToRect(ACol,ARow,R) then
      begin
        BoxLabel_:=TMiniBoxLabel.Create(Self);
        BoxLabel_.Parent:=Self;
        BoxLabel_.Brush.Color:=clWhite; //Self.Color;
        BoxLabel_.is3D:=False;
        BoxLabel_.Left:=R.Left-1;
        BoxLabel_.Top:=R.Top-1;
        BoxLabel_.Width:=R.Right-R.Left+2;
        BoxLabel_.Height:=R.Bottom-R.Top+2;
        BoxLabel_.Show;
        
        Edit_:=TEditBox.Create(Self,BoxLabel_);
        Edit_.Parent:=Self;
        Edit_.Font:=Self.FGridFont;
        Edit_.Color:=clWhite;//Self.Color;
        Edit_.EditType:=lEditType;
        Edit_.MaxLength:=lMaxInputLength;
        Edit_.Text:=Cells[ACol,ARow];
        DC:=GetDC(Edit_.Handle);
        GetTextExtentPoint(DC,'MINI',Length('MINI'),Size);
        ReleaseDC(Edit_.Handle,DC);
        Edit_.ARow:=ARow;
        Edit_.ACol:=ACol;
        Edit_.Width:=R.Right-R.Left;
        Edit_.Height:=Size.cy-4;
        if Edit_.Height>(R.Bottom-R.Top) then
          Edit_.Height:=R.Bottom-R.Top;
        Edit_.Left:=R.Left;
        Edit_.Top:=R.Top+(((R.Bottom-R.Top)-Edit_.Height) div 2);
        Edit_.Show;
        Edit_.SetFocus;

        isEdited:=True;
      end;
    end;
    if (not isEdited) and Assigned(FOnSetCombobox) then
    begin
      lCanEdit:=False;
      cStyle:=csDropDown;
      InputList:=TStringList.Create;
      try
        FOnSetCombobox(Self,ACol,ARow,lCanEdit,cStyle,InputList);
        if lCanEdit and ColRowToRect(ACol,ARow,R) then
        begin
          Combobox_:=TComboboxBox.Create(Self);
          Combobox_.Parent:=Self;
          Combobox_.Style:=cStyle;
          //Combobox_.Text:=Cells[ACol,ARow];
          Combobox_.ARow:=ARow;
          Combobox_.ACol:=ACol;
          Combobox_.Width:=R.Right-R.Left+2;
          //Combobox_.Height:=R.Bottom-R.Top+2;
          Combobox_.Left:=R.Left-1;
          Combobox_.Top:=R.Top-1;
          Combobox_.Show;
          Combobox_.SetFocus;
          Combobox_.Items.Assign(InputList);
          for i:=0 to Combobox_.Items.Count-1 do
            if Combobox_.Items.Strings[i]=Cells[ACol,ARow] then
            begin
              Combobox_.ItemIndex:=i;
              Break;
            end;

          isEdited:=True;
        end;
      finally
        InputList.Free;
      end;
    end;
    if (not isEdited) and Assigned(FOnSetDTPicker) then
    begin
      lCanEdit:=False;
      ADateTime:=Now;
      FOnSetDTPicker(Self,ACol,ARow,lCanEdit,ADateTime);
      if lCanEdit and ColRowToRect(ACol,ARow,R) then
      begin
        DTPicker_:=TDTPickerBox.Create(Self);
        DTPicker_.Parent:=Self;
        if Cells[ACol,ARow]='' then
          DTPicker_.DateTime:=ADateTime
        else
          DTPicker_.DateTime:=StrToDate(Cells[ACol,ARow]);
        //Combobox_.Text:=Cells[ACol,ARow];
        DTPicker_.ARow:=ARow;
        DTPicker_.ACol:=ACol;
        DTPicker_.Width:=R.Right-R.Left+2;
        //DTPicker_.Height:=20;
        //DTPicker_.Height:=R.Bottom-R.Top;
        DTPicker_.Left:=R.Left-1;
        DTPicker_.Top:=R.Top-1;
        DTPicker_.Show;
        DTPicker_.SetFocus;

        isEdited:=True;
      end;
    end;
    if (not isEdited) and Assigned(FOnSetMouseDown) then
    begin
      lCanEdit:=False;
      AText:='';
      FOnSetMouseDown(Self,Button,ACol,ARow,lCanEdit,AText);
      if lCanEdit and ColRowToRect(ACol,ARow,R) then
      begin
        SetCells(ACol,ARow,AText);

        isEdited:=True;
      end;
    end;

    if Data[ACol].ShowCheckBox then
    begin
      lpText:=Data[ACol].Text;
      Inc(lpText,ARow);
      if not lpText^.Checked then
      begin
        lpText^.Checked:=True;
        DrawCell(ACol,ARow);
      end
      else
      begin
        lpText^.Checked:=False;
        DrawCell(ACol,ARow);
      end;
      if Assigned(FOnChecked) then
        FOnChecked(Self,ACol,ARow,lpText^.Checked);

      {if Assigned(FOnSetFontColor) then
      begin
        lColor:=FGridFont.Color;
        FOnSetFontColor(Self,ACol,ARow,lColor);
        _1BufferBtm.Canvas.Font.Color:=lColor;    //messagebeep(20);
        for i:=0 to High(Data) do
          DrawCell(i,ARow);
      end;}
    end;
  end;
  if not isEdited then  //如果前面没有编辑动作,则调用默认的OnMouseDown事件.
    inherited;
end;

function TMiniGrid.GetChecked(ACol, ARow: integer): Boolean;
var
  lpText: PBufText;
begin
  Result:=False;
  if (not (ACol in[0..High(Data)]))or(ARow<0)or(ARow>(FRowCount-1)) then
    Exit;
  if not Data[ACol].ShowCheckBox then
    Exit;

  lpText:=Data[ACol].Text;
  Inc(lpText,ARow);
  if lpText<>nil then
    Result:=lpText^.Checked;
end;

procedure TMiniGrid.SetChecked(ACol, ARow: integer; Checked: Boolean);
var
  lpText: PBufText;
  i: integer;
  lColor: TColor;
begin
  if (not (ACol in[0..High(Data)]))or(ARow<0)or(ARow>(FRowCount-1)) then
    Exit;

  if Data[ACol].ShowCheckBox then
  begin
    lpText:=Data[ACol].Text;
    Inc(lpText,ARow);
    if Checked then
    begin
      if not lpText^.Checked then
      begin
        lpText^.Checked:=True;
        if (ARow>=TopRowID)and(ARow<=(TopRowID+ShowRowCount-1)) then  //在当前显示区域。
          DrawCell(ACol,ARow);
      end;
    end
    else
      if lpText^.Checked then
      begin
        lpText^.Checked:=False;
        if (ARow>=TopRowID)and(ARow<=(TopRowID+ShowRowCount-1)) then  //在当前显示区域。
          DrawCell(ACol,ARow);
      end;
    if Assigned(FOnSetFontColor) then
    begin
      lColor:=FGridFont.Color;
      FOnSetFontColor(Self,ACol,ARow,lColor);
      _1BufferBtm.Canvas.Font.Color:=lColor;
      for i:=0 to High(Data) do
        if (ARow>=TopRowID)and(ARow<=(TopRowID+ShowRowCount-1)) then
          DrawCell(i,ARow);
    end;
    if ARow=SelectionID then
      Show_Selection(SelectionID,-1);
  end;
end;

procedure TMiniGrid.SetImage(ImageList: TImageList);
begin
  FImageList:=ImageList;
end;

procedure TMiniGrid.SetCellImage(ACol, ARow, ImageIndex: integer);
var
  lpText: PBufText;
begin
  if (not (ACol in[0..High(Data)]))or(ARow<0)or(ARow>(FRowCount-1)) then
    Exit;
  if Data[ACol].ShowCheckBox then
    Exit;
  if FImageList=nil then
    Exit;

  lpText:=Data[ACol].Text;
  Inc(lpText,ARow);
  lpText^.ImageIndex:=ImageIndex+1; //因为初始化时是0,为了区别+1,在DrawCell中判断是否画时,再-1.
  if (ARow>=TopRowID)and(ARow<=(TopRowID+ShowRowCount-1)) then  //在当前显示区域。
  begin
    DrawCell(ACol,ARow);                              //messagebeep(20);
    if FShowSelection and(ARow=SelectionID) then
      Show_Selection(SelectionID,-1);
  end;
end;

procedure TMiniGrid.SetRowColor(ARow, Color: TColor);
var
  lpText: PBufText;
  i: integer;
begin
  if (ARow<0)or(ARow>(FRowCount-1)) then
    Exit;

  for i:=0 to High(Data) do
  begin
    lpText:=Data[i].Text;
    Inc(lpText,ARow);
    lpText^.BackColor:=Color;
  end;

  if (ARow>=TopRowID)and(ARow<=(TopRowID+ShowRowCount-1)) then  //在当前显示区域。
  begin
    for i:=0 to High(Data) do
      DrawCell(i,ARow);                              //messagebeep(20);
    if FShowSelection and(ARow=SelectionID) then
      Show_Selection(SelectionID,-1);
  end;
end;

function TMiniGrid.GetRowAt(X, Y: integer): integer;
var
  ACol,ARow: integer;
  CurrP: TPoint;
begin
  CurrP:=Point(X,Y);
  if PointToColRow(CurrP,ACol,ARow) then
    Result:=ARow
  else
    Result:=-1;
end;

function TMiniGrid.GetColAt(X, Y: integer): integer;
var
  ACol,ARow: integer;
  CurrP: TPoint;
begin
  CurrP:=Point(X,Y);
  if PointToColRow(CurrP,ACol,ARow) then
    Result:=ACol
  else
    Result:=-1;
end;

function TMiniGrid.GetSelected: integer;
begin
  if FShowSelection then
    Result:=SelectionID
  else
    Result:=-1;
end;

function TMiniGrid.Delete(ARow: integer): Boolean;
var
  i: integer;
begin
  Result:=False;
  if (FRowCount<1)or(ARow<0)or(ARow>=FRowCount) then
    Exit;

  for i:=0 to High(Data) do
  begin
    if Data[i].Text<>nil then
    begin      //再次调整内存大小。
      if ARow<(FRowCount-1) then  //如果不是最后一条记录。
        MoveMemory(Pointer(DWORD(Data[i].Text)+ARow*ROW_BUFSIZE),Pointer(DWORD(Data[i].Text)+(ARow+1)*ROW_BUFSIZE),(FRowCount-1-ARow)*ROW_BUFSIZE);
      ReallocMem(Data[i].Text,(FRowCount-1)*ROW_BUFSIZE);
      if (FRowCount-1)=0 then
        Data[i].Text:=nil;
    end;
  end;
  Result:=True;                

  Dec(FRowCount,1);
  if TopRowID>0 then
    Dec(TopRowID);
  if SelectionID>=ARow then
    if (SelectionID>0)or(FRowCount=0) then
    begin
      Dec(SelectionID,1);
      //FOnSelectChanged(Self,SelectionID);
    end;
  AdjustParameter;
  DrawGrid;

  if FShowScrollBar and(ScrollBar<>nil) then
    ScrollBar.Change(TopRowID);
end;

function TMiniGrid.Add(ARow: integer): Boolean;
var
  i: integer;
begin
  Result:=False;
  if (ARow<0)or(ARow>FRowCount) then
    Exit;

  for i:=0 to High(Data) do
  begin
    if Data[i].Text=nil then //第一次分配。
    begin
      ReallocMem(Data[i].Text,ROW_BUFSIZE);
      ZeroMemory(Data[i].Text,ROW_BUFSIZE);
    end
    else      //再次调整内存大小。
    begin
      ReallocMem(Data[i].Text,(FRowCount+1)*ROW_BUFSIZE);
      if ARow<FRowCount then
        MoveMemory(Pointer(DWORD(Data[i].Text)+(ARow+1)*ROW_BUFSIZE),Pointer(DWORD(Data[i].Text)+ARow*ROW_BUFSIZE),(FRowCount-ARow)*ROW_BUFSIZE);
      ZeroMemory(Pointer(DWORD(Data[i].Text)+ARow*ROW_BUFSIZE),ROW_BUFSIZE);
    end;
  end;

  if (FRowCount>0)and(SelectionID>=ARow) then
  begin
    SelectionID:=SelectionID+1;
    //FOnSelectChanged(Self,SelectionID);
  end;
  Inc(FRowCount,1);
  //Inc(TopRowID,1);
  AdjustParameter;
  DrawGrid;

  if FShowScrollBar and(ScrollBar<>nil) then
    ScrollBar.Change(TopRowID);
end;

procedure TMiniGrid.MouseEnter(var Msg: TMessage);
begin
  if Assigned(FOnMouseEnter) then
    FOnMouseEnter(Self);
end;

procedure TMiniGrid.MouseLeave(var Msg: TMessage);
begin
  if Assigned(FOnMouseLeave) then
    FOnMouseLeave(Self);
end;

procedure TMiniGrid.Setis3D(Value: Boolean);
begin
  if Fis3D<>Value then
  begin
    Fis3D:=Value;
    Invalidate;
    if ScrollBar<>nil then
    begin
      ScrollBar.is3D:=Value;
      ScrollBar.Repaint;
    end;
  end;
end;

procedure TMiniGrid.WmInputText(var Msg: TMessage);
var
  ACol,ARow: integer;
  Text: string;
  lpEditInfo: PEditCtrlInfo;
begin
  lpEditInfo:=PEditCtrlInfo(Msg.WParam);
  ACol:=lpEditInfo^.ACol;
  ARow:=lpEditInfo^.ARow;
  Text:=lpEditInfo^.Text;
  lpEditInfo^.Ctrl.Free;
  {if lpEditInfo^.Ctrl is TEditBox then
    (lpEditInfo^.Ctrl as TEditBox).Free
  else
    if lpEditInfo^.Ctrl is TComboboxBox then
      (lpEditInfo^.Ctrl as TComboboxBox).Free
    else
      (lpEditInfo^.Ctrl as TDTPickerBox).Free; }
  Dispose(lpEditInfo);

  SetCells(ACol,ARow,Text);

  if Assigned(FOnEditTextChanged) then
    OnEditTextChanged(Self,ACol,ARow,Text);
end;

procedure TMiniGrid.SetSelectionColor(Value: TColor);
begin
  if FSelectionColor<>Value then
  begin
    FSelectionColor:=Value;
    Invalidate;
  end;
end;

{ TTitle }

constructor TTitle.Create(Collection: TCollection);
begin
  FWidth:=40;
  FAlignment:=taCenter;
  FCaption:='';
  FShowCheckBox:=False;
  inherited Create(Collection);
end;

procedure TTitle.Assign(Source: TPersistent);
begin
  if Source is TTitle then
  begin
    FCaption:=(Source as TTitle).Caption;
    FAlignment:=(Source as TTitle).Alignment;
    FWidth:=(Source as TTitle).Width;
    FShowCheckBox:=(Source as TTitle).ShowCheckBox;
  end
  else
    inherited Assign(Source);
end;

procedure TTitle.SetAlignment(Value: TAlignment);
begin
  if FAlignment<>Value then
  begin
    FAlignment:=Value;
    Self.Changed(False);
  end;
end;

procedure TTitle.SetCaption(Value: string);
begin
  if FCaption<>Value then
  begin
    FCaption:=Value;
    Self.Changed(False);
  end;
end;

procedure TTitle.SetWidth(Value: WORD);
begin
  if FWidth<>Value then
  begin
    FWidth:=Value;
    Self.Changed(False);
  end;
end;

procedure TTitle.SetShowCheckBox(Value: Boolean);
begin
  if FShowCheckBox<>Value then
  begin
    FShowCheckBox:=Value;
    Self.Changed(False);
  end;
end;

function TTitle.GetDisplayName: string;
begin
  Result:=Caption;
  if Result='' then
    Result:=inherited GetDisplayName;
end;

destructor TTitle.Destroy;
begin
  
  inherited;
end;

{ TTitles }

constructor TTitles.Create(MiniGrid: TMiniGrid);
begin
  inherited Create(TTitle);
  Self.FMiniGrid:=MiniGrid;
end;

function TTitles.Add: TTitle;
begin
  Result:=TTitle(inherited Add);
end;

procedure TTitles.Delete(Index: Integer);
begin
  inherited Delete(Index);
end;

function TTitles.GetItem(Index: integer): TTitle;
begin
  Result:=TTitle(inherited GetItem(Index));
end;

procedure TTitles.SetItem(Index: integer; Value: TTitle);
begin
  inherited SetItem(Index,Value);
end;

procedure TTitles.UpDate(Item: TCollectionItem);
begin
  if Item<>nil then
    FMiniGrid.UpDateTitle(TTitle(Item))
  else
    FMiniGrid.UpdateTitles;
end;

{ TMiniScroll }
      //BL: Single;   //移动滚条一个点代表多少ROW的数量
      //RC: integer;  //滚条可移动多少个点。
constructor TMiniScroll.Create(AOwner: TComponent);
var
  rC,gC,bC: Byte;
  i: integer;
begin
  inherited Create(AOwner);
  ScrlCount:=0;  //滚条可移动多少个点。
  FHideCount:=0;
  FShowRect:=Rect(0,0,0,0);
  Canvas.Pen.Color:=RGB(0,200,255);
  //Canvas.Brush.Style:=bsClear;
  MouseState:=zxcUp;
  is3D:=TMiniGrid(AOwner).is3D;

  bkBitmap:=TBitmap.Create;
  bkBitmap.Height:=2;
  bkBitmap.Width:=SCROLLWIDTH;
  rC:=0; gC:=0; bC:=0;
  for i:=0 to bkBitmap.Width-1 do
  begin
    bkBitmap.Canvas.Pen.Color:=RGB(255-rC,255-gC,255-bC);
    bkBitmap.Canvas.MoveTo(i,0);
    bkBitmap.Canvas.LineTo(i,1);
    Inc(rC,4);
    Inc(gC,3);
    Inc(bC,2);
  end;
end;

destructor TMiniScroll.Destroy;
begin
  bkBitmap.Free;
  inherited;
end;

procedure TMiniScroll.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  if Button = mbLeft then
    if ScrlCount>0 then
    begin
      MouseState:=zxcDown;
      OldPoint:=Point(X,Y);
      Parent.SetFocus;
    end;
end;

procedure TMiniScroll.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  if Button = mbLeft then
    MouseState:=zxcUp;
end;

procedure TMiniScroll.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  T,Temp: integer;
begin
  if MouseState=zxcDown then //如果鼠标左键按下
  begin
    T:=Top+Y-OldPoint.Y;
    if T<FShowRect.Top then
      T:=FShowRect.Top;
    if (T+Height)>FShowRect.Bottom then
      T:=FShowRect.Bottom-Height;
    if T<>Top then
    begin
      Top:=T;

      if Top=FShowRect.Top then
        Temp:=0
      else
        Temp:=Round((Top-FShowRect.Top)*BL);
      if Assigned(FOnScroll) then
        FOnScroll(Self,Temp);
    end;
  end;
end;

procedure TMiniScroll.Paint;
begin                   
  Canvas.Brush.Style:=bsClear; //clBtnface;//$00F4F4F4;
  if is3D then
    Canvas.CopyRect(Rect(0,0,Width,Height*2),bkBitmap.Canvas,Rect(0,0,bkBitmap.Width,bkBitmap.Height));
  Canvas.Rectangle(0,0,Width,Height);

end;

procedure TMiniScroll.SetHideCount(Value: integer);
begin
  if FHideCount<>Value then
  begin
    FHideCount:=Value;
    if FHideCount<=(FShowRect.Bottom-FShowRect.Top-SCROLLMINHEIGHT) then
      ScrlCount:=FHideCount
    else
      ScrlCount:=FShowRect.Bottom-FShowRect.Top-SCROLLMINHEIGHT;
    if FHideCount>0 then
      BL:=FHideCount/ScrlCount;
    if Value<=0 then
      Height:=0
    else
      Height:=FShowRect.Bottom-FShowRect.Top-ScrlCount;
  end;
end;

procedure TMiniScroll.Change(TopRowID: integer);
var
  T: integer;
begin
  if ScrlCount>0 then
  begin
    if TopRowID=0 then
      T:=FShowRect.Top
    else
      T:=FShowRect.Top+Round(TopRowID/BL);

    if (T+Height)>=FShowRect.Bottom then
      Top:=FShowRect.Bottom-Height
    else
      Top:=T;
  end;
  Paint;
end;

procedure TMiniScroll.SetShowRect(Value: TRect);
begin
  FShowRect:=Value;
  Left:=FShowRect.Left;
  Top:=FShowRect.Top;
  Width:=SCROLLWIDTH;
end;

{ TEditBox }

constructor TEditBox.Create(Aowner: TComponent; bkBoxLabel: TMiniBoxLabel);
begin
  inherited Create(Aowner);
  EditType:=miniSTR;
  Self.BorderStyle:=bsNone;
  Self.OnKeyPress:=Self.CustomKeyPress;
  bkCtrl:=bkBoxLabel;
end;

procedure TEditBox.ProcessInput;
var
  lpEditInfo: PEditCtrlInfo;
begin
  New(lpEditInfo);

  lpEditInfo^.ACol:=ACol;
  lpEditInfo^.ARow:=ARow;
  lpEditInfo^.Text:=Self.Text;
  lpEditInfo^.Ctrl:=Self;

  PostMessage(Parent.Handle,WM_INPUTTEXT,integer(lpEditInfo),0);
end;

procedure TEditBox.CustomKeyPress(Sender: TObject; var Key: Char);
begin
  if EditType=miniNUM then
  begin
    if not(Key in['0'..'9',#8,#13]) then
      Key:=#0;
  end
  else
    if EditType=miniSINGLE then
    begin
      if not(Key in['0'..'9','.',#8,#13]) then
        Key:=#0;
    end;

  if Key=#13 then
  begin
    Key:=#0;
    if (EditType=miniSINGLE)and(Text<>'') then
      if Text[1]='.' then
        Text:='0'+Text;
    //ProcessInput;
    Parent.SetFocus;
  end;
end;

procedure TEditBox.WmKillFocus(var Msg: TMessage);
begin
  inherited;
  ProcessInput;
end;

destructor TEditBox.Destroy;
begin
  if bkCtrl<>nil then
    bkCtrl.Free;
  inherited;
end;

{ TComboboxBox }

constructor TComboboxBox.Create(Aowner: TComponent);
begin
  inherited;
  Self.OnKeyPress:=Self.CustomKeyPress;
  Self.OnExit:=Self.CustomExit;
end;

procedure TComboboxBox.CustomExit(Sender: TObject); //不能用WM_KILLFOCUS,可能有子控件响应此消息,造成多次发送
begin
  ProcessInput;
end;

procedure TComboboxBox.CustomKeyPress(Sender: TObject; var Key: Char);
begin
  if Key=#13 then
  begin
    Key:=#0;
    Parent.SetFocus;
  end;
end;

procedure TComboboxBox.ProcessInput;
var
  lpEditInfo: PEditCtrlInfo;
begin
  New(lpEditInfo);

  lpEditInfo^.ACol:=ACol;
  lpEditInfo^.ARow:=ARow;
  lpEditInfo^.Text:=Self.Text;
  lpEditInfo^.Ctrl:=Self;

  PostMessage(Parent.Handle,WM_INPUTTEXT,integer(lpEditInfo),0);
end;

{procedure TComboboxBox.WmKillFocus(var Msg: TMessage);
begin
  inherited;
  //ProcessInput;
end; }

{ TDTPickerBox }

constructor TDTPickerBox.Create(Aowner: TComponent);
begin
  inherited;
  Self.OnKeyPress:=Self.CustomKeyPress;
end;

procedure TDTPickerBox.CustomKeyPress(Sender: TObject; var Key: Char);
begin
  if Key=#13 then
  begin
    Key:=#0;
    Parent.SetFocus;
  end;
end;

procedure TDTPickerBox.ProcessInput;
var
  lpEditInfo: PEditCtrlInfo;
begin
  New(lpEditInfo);

  lpEditInfo^.ACol:=ACol;
  lpEditInfo^.ARow:=ARow;
  lpEditInfo^.Text:=Self.Text;
  lpEditInfo^.Ctrl:=Self;

  PostMessage(Parent.Handle,WM_INPUTTEXT,integer(lpEditInfo),0);
end;

procedure TDTPickerBox.WmKillFocus(var Msg: TMessage);
begin
  inherited;
  ProcessInput;
end;

end.
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值