最近闲来无事,就装了一个 Ehlib 来玩。呵呵,没想到,这么个小东西一下子就把我迷住了,细细品来,的确是一个非常好的控件作品。作者厉害厉害啊~~



2003-12-5 15:17:00   
发表评语»»»     

2003-12-5 15:22:29    使用 TDBSumList 组件   还记得以前有朋友问过这样一个问题:在 DBGrid 下如何像 Excel 一样能够做统计计算,实话说,使用 DBGrid 来做的话着实不易,不过现在有了这个咚咚,相信会简单些。以下是摘录的一些使用上的说明:

【TDBSumList说明】
    你可以使用TDBSumList在可视动态变化数据集中进行记录统计。在你想查看的数据集中设置相关的数据字段,然后写 SumListChanged 事件来指定在TDBSumList发生改变后所要做的操作。TDBSumList 的 SumCollection 属性上一个 TDBSum 对象容器。每个 TDBSum 对象是一个可以指定集合值的元件。 FieldName 和 GroupOperation 决定了集合值的类型,SumValue 控制当前的集合值。

    TDBSumList 被埋藏于 DBGridEh 组件中,因此所的下面有关TDBGridEh.SumList 的说明与TDBGirdEh的TDBGridEh.SumList 属性的说明是一样的。

【如何工作以及为什么有时SumList的集合值计算不正确?】
    你知道 data-aware 控件与数据集是通过 TDataLink 对象相连接的。 TDataLink 不允许快速重新计算集合值。例如,当从数据集中删除记录时,数据集发送deDataSetChange事件给所有的TDataLink对象,在当前局部过滤发生改变时,同样的事件也被发送了。因此当 TDataLink 接收到该事件时,它不得不在所有的数据集中重新计算集合值,甚至于仅从数据集中删除一条记录。在激活后, TDBSumList 重载了数据集的下列事件: OnAfterEdit, OnAfterInsert, OnAfterOpen, OnAfterPost, OnAfterScroll, OnBeforeDelete, OnAfterClose。这种方法避免了在所有的数据集中它。在不需要它时,又会出现其它的问题,比如: T 运行时指定这些事件。在指定上述事件之一以前,关闭 SumList。
    在下面的情形下,SumList 发出存取错误信息。 SumList 试着向数据集返回事件,但数据集数据并未被删除。在SumList(或网格)以及数据集放置在不同的窗体(数据模块)这种情况下,可以显示数据。在这种情况下,试着在从数据集或数据模块中数据集数据被删除时关闭SumList。
    如果你使用SetRange或ApplyRange事件,SumList 将不能跟踪数据集中发生的变化。但可以调用 SumList.RecalAll 方法。
    在非BDE数据集的主/明细表中,SumList 不能跟踪数据变化。在主数据集激活状态数据集发生变化后,调用 SumList.RecalAll 方法。
    在任何其它情况下,如果你发现了其它SumList的计算值不正确,你都可以调用 RecalAll 方法。  


2003-12-5 15:24:54    如何使用 Ehlib 实现自动排序   在 Ehlib 的 DataService 文件夹下提供了一些可以使数据集实现自动排序的文件。TDBGridEh 使用这些文件中的相关对象可以实现当排序标记发生变化时实现自动排序。

    如果你改变了数据网格及标题的排序标记而没有书写 OnSortMarkingChanged 事件,数据网格将尝试自动进行数据排序。DBGridEhDataService 尝试通过 GetDatasetFeaturesForDataSet 查找 TDataSet 中可以排序的特定的对象。正如你所知道的,TDataSet 不支持数据排序,但它的派生对象 TQuery 或 TClientDataSet 却允许实现数据排序。使用过程 RegisterDatasetFeaturesEh ,你可以注册 TDatasetFeaturesEhClass 类,该类可以实现对 TQuery, TADOQuery 以及 TClientDataSet 对象进行排序。简单地通过 uses 子句添加 Ehlib...(EhlibBDE,EhlibADO,EhlibCDS)的单元之一到你的工程的任意单元中,与它们相连的数据网格将自动对该数据集进行排序。 EhLibBDE, EhLibADO, EhLibCDS 通过在单元数据集中调用 RegisterDatasetFeaturesEh 过程来实现初始化。对于其它数据集类型,你必须编写、并注册可以实现该数据集排序的新对象。书写过程 T[你的数据集]DatasetFeaturesEh.ApplySorting ,你可以存取那些使用了 SortMarkedColumns 属性的列以实现直接排序。你可以查看 DbUtilsEh 单元中的示例以明白如何编写T[你的数据集]DatasetFeaturesEh 类及查看 EhLibBDE 单元以明白如何注册 T[你的数据集]DatasetFeaturesEh 类。

引擎           数据集           单元文件

BDE            TQuery           EhLibBDE
ADO            TADOQuery        EhLibADO
ClientDataSet  TClientDataSet   EhLibCDS
DBExpress      TSQLQuery        EhLibDBX
InterBase      Express TIBQuery EhLibIBX

【译【者注】:
    实际上,实现该功能非常简单(以下我以BDE为例说明如何实现自动排序):
    1.在窗体上放置一个 DBGridEh 组件,并将其连接到相应的 BDE 数据集;
    2.将该组件的[OptionsEn]中的 dgAutoSortMarking 属性设置为 True;
    3.双击该组件,在其弹出的属性编辑器中添加相关字段;
    4.将要排序的字段的属性列表的 [Title]的 TitleButton 属性设置为 True;
    5.最后,千万不要忘了在 uses 子句中加上 EhlibBDE单元。

好了,使用上面的方法,你会发现原来通过 Ehlib 实现数据的自动排序居然如些简单!


2003-12-5 15:39:37    以下这段文字摘自《Delphi 园地》【定制网格标题 】--
-【复杂标题】
    TDBGridEh 允许在多列上创建标题,设置 DBGridEh.UseMultiTitle 属性为 True 并且填充字段的标签或列标题的标题,可以使用下面的规则:字段标签中的文本部分或列标题必须由几部分组成,并且用 "|" 分割,几个列的每一个通用部分都设置为相同。其它字段或标题必须在相应的部分包含同样的文本。

例如:
Field1.DisplayLabel := 'Title1|SubTitle1';
Field2.DisplayLabel := 'Title1|SubTitle2';

DBGridEh.Columns[0].Title.Caption := 'Title1|SubTitle1';
DBGridEh.Columns[1].Title.Caption := 'Title1|SubTitle2';

-【按钮式标题】
    设置Column.Title.TitleButton 为 True可以强制标题单元为按钮式。写 OnTitleBtnClick事件来控制用户单击标题单元时的操作。

-【在标题中显示位图】
    To show bitmap in titles instead of caption use TitleImages property of TDBGridEh and ImageIndex property of TColumnTitleEh.

-【自动用位置标识排序标题】.
    TDBGridEh allows to show special sortmarking bitmaps (small triangles) in the right part of title cell. In order to automatically marking title by sortmarking bitmaps add dghAutoSortMarking to OptionsEh property. Add dghMultiSortMarking too in order to allow sortmarking several columns simultaneously. Set Column.Title.TitleButton to true for titles which will have possibility to change sortmarkers at run time. At runtime clicking on title will change sortmarking. Holding Ctrl key allows to mark several columns simultaneously. After user change sormarking grid call OnSortMarkingChanged event. You can write this event to change sorting and reopen in dataset. Use SortMarkedColumns property to access to sortmarked columns.

-【标题属性的默认值】
    使用TDBGridEh.ColumnDefValues.Title来设置标题属性的默认值。

【定制网格页脚】--
-【页脚以及统计值】
    TDBGridEh allows to show special row (footer) or rows at bottom part. Use FooterRowCount property to specify the number of footer rows in the grid. Use Footer or Footers property of TColumnEh object to specify information which need to show in footer cells. Footers property useful then you have more then one footer rows. Footers is a collection of TColumnFooterEh objects where information from i-th aliment of collection will be show in i-th cell of footer column. In footer cell, it is possible to show: Sum value for specified field, record count, value of a specified field or static text. Use property Footer.ValueType or Footers .ValueType to specify which type of value will be show in footer cell. If ValueType = fvtStaticText, then set the property Value to specify text which need to show. If ValueType = fvtFieldValue, then you need to set property FieldName to specify field, value of which need to show. To force grid to calculate total values need to activate SumList (DBGridEh.SumList.Active := True). Set ValueType to fvtSum and grid must to show sum value of the column field in the footer cell, you can also specify Column.Footer.FieldName to calculate total value of the other field. Set ValueType to fvtCount to force grid to show count of records in the footer cell.

-【定制网格数据单元】
    在数据单元中显示字段值为图形。
    TDBGridEh allows to show bitmaps from TImageList component depending on field values. To show bitmaps depending on field values need: Fill list of field values to Column.KeyList property (every value in separate line) and set Column.ImageList property to ImageList control that has the bitmap in according index. Set Column.NotInKeyListIndex to index of bitmap that will be shown if field's value does not correspond to any value in KeyList (for instance you can set index of p_w_picpath for Null field value). At run time you are not allowed to edit bitmap in column cell. Use blank key and mouse click to set next value from Column.KeyList to the field; Shift-blank key and Shift-Mouse click to set previous value from Column.KeyList. Set Column.DblClickNextval to True have allows to change value on mouse double click.

【检查框式的逻辑及非逻辑值】
    Grid automatically shows checkboxes for boolean field. To show checkboxes for non boolean fields fill first line of Column.KeyList property that corresponds to the checked state of the checkbox, second line - non checked state, and set Column.Checkboxes ptoperty to True. Line of KeyList can represent more than one value in a semicolon-delimited list of items.

【数据行高度】
    使用 RowHeight 和 RowLines 属性来指定数据行高。完整的数据行高 = 行线高度+行高。设置 RowSizingAllowed 为 True 以允许可以在运行是使用鼠标来改变行高。
    设置Column.WordWrap为True可以使数据行中文本多行显示。如果行高>文本行,它就换行。

【显示备注字段】
    设置 DrawMemoText to True来显示文本式的备注字段。.

【定制单元格字体及颜色】
    TDBGridEh 中的 Font 和 Color 属性描述了数据网格中绘制单元格的字体和颜色。
    TColumnEh 中的 Font 和 Color 属性描述了指定列中绘制单元格的字体和颜色。

【事件定制单元格字体及颜色】
    有几个事件可以让你能够在绘制单元格前定制单元格字体和颜色。你可以写TDBGridEh的OnDrawColumnCellEvent事件句柄来在控制在网格单元中绘制数据。你可以使用Canvas属性的方法来绘制单元格。但是如果你只想改变字体或颜色的属性,我建议你使用下面的事件。你可以写TDBGridEh的OnGetCellParams事件来控制在绘制数据单元以前所指定的操作。你可以改变绘制字体及背景色。这个事件适合你在想改变整行的字体或颜色时使用。如果你想改变指定列中单元格的属性,你可以使用TColumnEh.OnGetCellParams。写这个事件用来控制在一列数据单元被重绘或编辑时的操作。在一列数据单元被重绘以前,你可以改变绘制字体,背景色,对齐方式,图像索引,文本或检查框。在编辑一列数据单元以前,你可以改变编辑字体,背景色,文本或只读状态。

【列属性的默认值】
    使用ColumnDefValues属性来设置列属性的默认值。新创建的列将从ColumnDefValues属性中获得属性值,并且直到第一次为其指定值为止。

【在网格的适当位置放置编辑器】--
-【在下拉列表中显示几个字段】
    在下拉列表中显示几个下拉字段,需要设置列的LookupDisplayFields属性到字段的Semicolons属性来分割多个字段名。命名为Column.Field.LookupResultField的属性必须位于LookupDisplayFields列表中。多字段的下拉列表只能应用于下拉字段。

-【显示下拉方式的列】
    你可以通过KeyList 和 PickList 属性在相关的的字段中显示其它文本。KeyList显示包含在字段的值而非PickList索引所包含的值。 Column.NotInKeyListIndex to index of text from PickList that will be shown if field value do not contain in KeyList (for instance you can set index of text for Null field value). Set Column.DblClickNextval to True to change value on mouse double click.

-【下拉式计算器】
    对于 TDateField 和 TDateTimeField 字段,inplace 编辑器将显示下拉按钮以显示显示下拉计算器。设置 Column.ButtonStyle 为 cbsNone 以禁止显示下拉按钮。

【设置编辑器颜色和字体】
    Inplace编辑器可以设置数据单元的颜色和字体。数据单元使用OnGetCellParams 事件来控制列的颜色和字体。 Inplace 编辑器在行高>一行的高度时自动设置为多行模式并且将列的属性 WordWrap 设置为True.

【自动填充网格列宽到网格客户区】
    设置AutoFitColWidths为True以自动重置列宽来设置网格的宽度等于客户区宽度。 MinAutoFitWidth 属性决定网格的最小宽度,列宽将会被重新计算。

【3D或平面外观】
    使用 OptionsEh 属性来显示/隐藏固定的3D框架,冷区,页脚以及数据行。
    使用 Flat 属性来设置用平面方式显示数据网格。

【从多种格式导入/导出数据到TDBGridEh】
    EhLib 的函数集可以从DBGridEh导出数据到Text, Csv, HTML, RTF, XLS以及其内部格式。它可以保存数据到流(TStream对象)或文件。

例子
Pascal: SaveDBGridEhToExportFile(TDBGridEhExportAsText,DBGridEh1,'c:\temp\file1.txt',False);
C++: SaveDBGridEhToExportFile(__classid(TDBGridEhExportAsText),DBGridEh1,"c:\\temp\\file1.txt",false);

    EhLib 的函数集可以从 Text以及其内部格式的数据导入到DBGridEh的数据集中。它可以从文件中读取数据或读取数据到流(TStream对象)。

【其它特性】--
    用lookup 编辑器,你可以在运行时清空(设置为Null) LookupKeyField 值。比如选择整个文本然后按Delete键。

-【冷区】
    冷区是数据网格列集左边显示的不可滚动的区域。与固定列不同的是,冷区的列可以获得编辑焦点。可以通过设置FrozenCols属性来设置右边不可滚动的列集。

-【增量搜索】
    TDBGridEh 允许用户在网格列中实现特定的“增量”搜索。当用户进入增量搜索时他可以显示字符以及网格,并且在当前的列中查找文本。使用 dghIncSearch 和 dghPreferIncSearch的值(在OptionsEh 选项中) 在数据网格中操作增量搜索。 dghIncSearch 值允许在数据网格中进行增量搜索。运行时你能够使用下面的键进行增量搜索:

         Ctrl+F - 开始增量搜索。
         Ctrl+Enter - 查找下一个匹配记录。
         Ctrl+Shift+Enter - 查找前一个匹配记录。

    如果OptionsEh选项中的 dghIncSearch 是只读的,那么网络将自动设置增量模式在第一次按键以及1.5秒后返回普通模式。 dghPreferIncSearch 值决定网格设置自动增量搜索模式在第一次按键时替代单元编辑。

【水平或垂直滚动条】
    使用 VertSctollbar, HorzSctollbar 属性来显示/隐藏以及跟踪水平或垂直滚动条。

【多选】
    TDBGridEh 允许在选定的区域上进行选择记录,列以及矩形区域等操作:

×允许多选会影响下面这些属性:
  Options 选项中的 dgMultiSelect 属性 - 设置是否允许多选。
  Options 选项中的 dghClearSelection 属性- 设置在用户移到下一个单元时是否清除已选记录。
  Options 选项中的 EditActions 属性 -设置用户可以在已选记录上执行哪些操作(比如,拷贝,剪切,删除,粘贴,全选等)。
  Options 选项中的 AllowedSelections 属性-设置允许选定记录的类型(比如,行,列,矩形区域等)。
  Options 选项中的 Selection 属性-设置一个当前的多选状态,已选记录,列或矩形区域以及存取它们的属性和函数。

【从注册表或ini文件中保存或恢复网格和列的层次】
    TDBGridEh 有一个常规设置来从注册表或ini文件中保存和恢复网络以及列的层次:
      RestoreColumnsLayout - 从注册表中恢复列的次序,宽度,排序标志。
      RestoreColumnsLayoutIni - 从ini文件中恢复列的次序,宽度,排序标志。
      RestoreGridLayout - 从注册表中恢复列的次序,宽度,可视,排序标志,排序索引或行高。
      RestoreGridLayoutIni - 从ini文件中恢复列的次序,宽度,可视,排序标志,排序索引或行高。
      SaveColumnsLayout - 保存列的次序,宽度,排序标志到注册表中。
      SaveColumnsLayoutIni - 保存列的次序,宽度,排序标志到ini文件中。
      SaveGridLayout - 保存列的次序,宽度,可视,排序标志,排序索引或行高到注册表中。
      SaveGridLayoutIni - 保存列的次序,宽度,可视,排序标志,排序索引或行高到ini文件中。

『以下内容仅供参考了,因为不知道它那个版本是多少,目前最新的版本是3.2吧,俺正在用,感觉很不错啊~~』
  当前版本的TDBGridEh不支持的特性:
  TDBGridEh 不能设置每一个数据窗口中单独行的行高。
  TDBGridEh 不能象TreeView那样工作。它不能拥有节点和枝叶。
  TDBGridEh 不能横向或纵向合并数据单元。

【将已存在的TDBGrid组件转换为TDBGridEh组件】:
    尽管TDBGridEh并不是从TCustomDBGrid组件继承而来的,但是在TDBGridEh和TDBGrid中还是有一些相似的属性。
    它允许仅用一点点代价来转换已存在的TDBGrid组件到TDBGridEh。

【注意】:可以按照下面的提示来转转换已存在的TDBGrid组件到TDBGridEh:
    在Delphi的IDE中打开包含有TDBGrid组件的应用程序。
    设置视图方式为文本方式(Alt-F12)。
    if key=VK_RETURN then //Key:回车
    begin
      if (grdDetailData.SelectedIndex=grdDetailData.Columns.Count-1) and not (dgRowSelect in grdDetailData.Options) then
      BEGIN
        if (dgEditing in grdDetailData.Options) and (grdDetailData.Row=grdDetailData.RowCount-1) then //从表GRID能进行编辑和当前光标焦点在最后一行时
          acAddDetailExecute(self)
        else
        begin
          grdDetailData.Row:=grdDetailData.Row+1; //改变光标焦点行到下一行(当为新增加时,这句不用运行
          grdDetailData.SelectedIndex:=0 //改变光标焦点列到第一列
        end;
      END ELSE
      BEGIN
        grdDetailData.SelectedIndex:=grdDetailData.SelectedIndex+1;
        while grdDetailData.Columns[grdDetailData.SelectedIndex].ReadOnly do
          grdDetailData.SelectedIndex:=grdDetailData.SelectedIndex+1;
      END;
      key:=0;
    end;
    if key=VK_INSERT then //Insert键:新增一条记录
    begin
      acAddDetailExecute(self);
      key:=0;
    end;
    if key=VK_DELETE then //Delte: 删除一条记录
    begin
      acDeleteDetailExecute(self);
      key:=0;
    end;

【页脚合计】
   1、设置DBGRIDEH属性的FooterRowCount值为1;
   2、设置DBGRIDEH属性的SumList的Active值为true;
   3、设置你要求和的该列的Footer的ValueType类型为fvtSum;
   4、运行OK!
    在DataSet打开时写:
      DBGridEh1.Columns[0].Footer.Value := IntToStr DBGridEh1.DataSource.DataSet.RecordCount);


2003-12-5 16:56:13    Ehlib 的 DBGridEh 控件怎样才能像 dxDBGrid 控件那样输出文件到 EXCEL以下是EHLIB的导出代码:(其实EHLIB的DEMO1中已有)

procedure TInvoiceManager.ppmSaveSelectionClick(Sender: TObject);
var ExpClass:TDBGridEhExportClass;
    Ext:String;
begin
  SaveDialog1.FileName := 'file1';
  if (ActiveControl is TDBGridEh) then
    if SaveDialog1.Execute then
    begin
      case SaveDialog1.FilterIndex of
        1: begin ExpClass := TDBGridEhExportAsText; Ext := 'txt'; end;
        2: begin ExpClass := TDBGridEhExportAsCSV; Ext := 'csv'; end;
        3: begin ExpClass := TDBGridEhExportAsHTML; Ext := 'htm'; end;
        4: begin ExpClass := TDBGridEhExportAsRTF; Ext := 'rtf'; end;
        5: begin ExpClass := TDBGridEhExportAsXLS; Ext := 'xls'; end;
      else
        ExpClass := nil; Ext := '';
      end;
      if ExpClass <> nil then
      begin
        if UpperCase(Copy(SaveDialog1.FileName,Length(SaveDialog1.FileName)-2,3)) <>
           UpperCase(Ext) then
          SaveDialog1.FileName := SaveDialog1.FileName + '.' + Ext;
        SaveDBGridEhToExportFile(ExpClass,TDBGridEh(ActiveControl),
             SaveDialog1.FileName,False);
      end;
    end;
end;


2003-12-5 17:05:48    Ehlib 在 Delphi 7 中的安装(我可是花了半天的力气才搞定的哦)Delphi 7中的安装方法

   1. 把 EhLib 中的 common 和 DataService 文件拷贝到 Delphi7 目录中.
   2.在 TOOLS->Environment Options->Library->Library Path 中添入EHLIB路径。
   3.打开新建文件夹中的 EHLIB70.DPK ,编译一下,但不要安装。
   4.打开Ehlib中的DclEhLib70.DPK,编译,安装
   5. 在Delphi 7中打开DclEhLib70.dpk,编译并安装。
   6. 组件面板中出现一个EhLib的组件页。
   7. 打开附带的DEMOS,编译并运行,测试安装成功。
  


2003-12-8 16:41:54    DBGridEh控件的页脚属性怎么设?0、将dBGridEh.FooterRowCount := 1
1、将DBGridEh.SumList.Active := True;
2、将Columns[要求和的字段].Footer.ValueType := vtSum;
就行了

最后要注意,在FormCloseQuery事件中,一定要将SumList.Active := False,因为在数据集中的数据多了以后,FormClose会让DBGridEh释放所有EhLib资源,会使得退出很慢,所以将SumList.Active := False不会引起退出很慢


2003-12-10 11:22:37    如何实现在DbgridEh中不同的行显示不同的颜色?或某一些条件的行显示特定的颜色?【实现 DBGridEh 隔行分色显示】
procedure TForm1.DBGridEh1GetCellParams(Sender: TObject; Column: TColumnEh;
AFont: TFont; var Background: TColor; State: TGridDrawState);
begin
   if DBGridEh1.SumList.RecNo mod 2 = 1 then
     Background := $00FFC4C4
   else
     Background := $00FFDDDD;
end;


【DBGridEh 在某些条件下某行显示特定颜色】
procedure TForm1.DBGridEh1GetCellParams(Sender: TObject; Column: TColumnEh; AFont: TFont; var Background: TColor; State: TGridDrawState);
begin

  //在 name 字段值为 aaa 的行设置行背景色(ado 设置情况下)
  if ADOQuery1.FieldByName('name').AsString = 'aaa' then
      Background := $00FFC4C4

  //在 xm 字段值为 Li ming 的行设置行背景色(bde 设置情况下)
  else if DBGridEh1.DataSource.DataSet.FieldByName('xm').AsString = 'Li ming'  then
     Background := $00FFC4C4
  else
     Background := $00FFDDDD;

end;   


2003-12-10 14:19:28    DBGridEh 控件导出文件到 EXCEL 的补充说明(关于多表头导出的设计思路)   如果表头是着样的:
      |Mergetitle|
      ------------
      Col1|Col2
    分析表头几层,然后根据其表头的'|' 将,其还原成
      |Mergetitle|Mergetitle
      ----------------------
      Col1       |Col2
    再导入到Excel里合并单元格即可!


2003-12-10 14:55:16    在dbgrideh中允许选择多行,如何知道哪些行被选中?是个BOOKMARK类型的属性。
SelectedRows: TBookmarkList
procedure TForm1.Button1Click(Sender: TObject);
var
i, j: Integer;
s: string;
begin
if DBGrid1.SelectedRows.Count>0 then
   with DBGrid1.DataSource.DataSet do
     for i:=0 to DBGrid1.SelectedRows.Count-1 do
     begin
       GotoBookmark(pointer(DBGrid1.SelectedRows.Items));
       for j := 0 to FieldCount-1 do
       begin
         if (j>0) then s:=s+', ';
         s:=s+Fields[j].AsString;
       end;
       Listbox1.Items.Add(s);
       s:= '';
     end;
end;   


2003-12-10 15:06:19    dbgrideh 上选择多行之后,要求把所选择的记录全部添加入SQL数据库的一个固定表中。dbgrideh.selectedrows记载了所有被选择行的bookmark;利用SelectedRows和GotoBookmark完成。代码如下:

procedure TForm1.Button1Click(Sender: TObject);
var
i, j: Integer;
s: string;
begin
if DBGrid1.SelectedRows.Count>0 then
   with DBGrid1.DataSource.DataSet do
     for i:=0 to DBGrid1.SelectedRows.Count-1 do
     begin
       GotoBookmark(pointer(DBGrid1.SelectedRows.Items));
       for j := 0 to FieldCount-1 do
       begin

         if (j>0) then s:=s+', ';
         s:=s+Fields[j].AsString;
       end;
       Listbox1.Items.Add(s);
       s:= '';
     end;
end;


2004-2-11 12:45:10    在dbgrideh中直接点击title就可按点击的那个字段排序的方法第一种方法(未测试)
procedure TForm1.DBGridEh1TitleClick(Column: TColumnEh);
begin
//点击GridEh标题排序
if (Column.Title.SortMarker = smNoneEh) or (Column.Title.SortMarker = smDownEh) then
   begin
     ADOQuery1.SORT := COLUMN.FIELDNAME;
     Column.Title.SortMarker := smUpEh
   end
else
   begin
     ADOQuery1.SORT := COLUMN.FIELDNAME + ' DESC';
     Column.Title.SortMarker := smDownEh
   end;
end;

第二种方法(未测试)
procedure TPrintMai_frm.DBGridEh1TitleClick(Column: TColumnEh);
var
sortstring: string;
begin //进行排序
with Column do
begin
   if FieldName = '' then
     Exit;
   case Title.SortMarker of
     smNoneEh:
       begin
         Title.SortMarker := smDownEh;
         sortstring := Column.FieldName + ' ASC';
       end;
     smDownEh: sortstring := Column.FieldName + ' ASC';
     smUpEh: sortstring := Column.FieldName + ' DESC';
   end; //数据集排序。
   try
     DM.DataModule1.qry2.Sort := sortstring //dataset为实际数据集变量名
   except
   end;
end;
end;  


2004-3-24 17:34:05    ehlib的颜色控制及打印From:
    http://www.delphibbs.com/keylife/iblog_show.asp?xid=191

      很多说根据条件在数据网格中显示不同颜色的说法都是在DrawColumnCell事件里,这样显示没有问题,但在ehlib中如果想打印出来可就不行了。
ehlib提供了GetCellParams事件,可以显示和打印
//只能显示,不能打印
procedure TfrmQueryContractInfo.DBGrid1DrawColumnCell(Sender: TObject;
const Rect: TRect; DataCol: Integer; Column: TColumnEh;
State: TGridDrawState);
var
OldColor,OldColumnColor:TColor;
v:TColCellParamsEh;
begin
{  OldColor:=DBGrid1.Canvas.Font.Color ;
if (Column.Field.FieldName = '填制调单时间') then
if (DBGrid1.DataSource.DataSet.FieldByName('填制调单时间').AsDateTime >DBGrid1.DataSource.DataSet.FieldByName('应发货时间').AsDateTime) then
begin
   //v:=TColCellParamsEh.Create ;
   //Column.GetColCellParams(true,v);
   //v.Font.Color :=clRed;
   //Column.FillColCellParams(v);
   //v.Free;
   DBGrid1.Canvas.font.Color := clRed;
end;

//Column.GetColCellParams  .FillColCellParams()

if (Column.Field.FieldName = '移交时间') then
if (DBGrid1.DataSource.DataSet.FieldByName('移交时间').AsDateTime >DBGrid1.DataSource.DataSet.FieldByName('应移交时间').AsDateTime) then
   DBGrid1.Canvas.Font.Color := clRed;

if (Column.Field.FieldName = '填制运输单时间') then
if (DBGrid1.DataSource.DataSet.FieldByName('填制运输单时间').AsDateTime >DBGrid1.DataSource.DataSet.FieldByName('填制调单时间').AsDateTime) then
   DBGrid1.Canvas.Font.Color := clRed;

DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
DBGrid1.Canvas.Font.Color:=OldColor;
}
end;
//可以显示,可以打印
procedure TfrmQueryContractInfo.DBGrid1GetCellParams(Sender: TObject;
Column: TColumnEh; AFont: TFont; var Background: TColor;
State: TGridDrawState);
var
OldColor,OldColumnColor:TColor;
v:TColCellParamsEh;
begin
//OldColor:=DBGrid1.Canvas.Font.Color ;
if (Column.Field.FieldName = '填制调单时间') then
if (DBGrid1.DataSource.DataSet.FieldByName('填制调单时间').AsDateTime >DBGrid1.DataSource.DataSet.FieldByName('应发货时间').AsDateTime) then
   AFont.Color := clRed;

if (Column.Field.FieldName = '移交时间') then
if (DBGrid1.DataSource.DataSet.FieldByName('移交时间').AsDateTime >DBGrid1.DataSource.DataSet.FieldByName('应移交时间').AsDateTime) then
   AFont.Color := clRed;

if (Column.Field.FieldName = '填制运输单时间') then
if (DBGrid1.DataSource.DataSet.FieldByName('填制运输单时间').AsDateTime >DBGrid1.DataSource.DataSet.FieldByName('填制调单时间').AsDateTime) then
   AFont.Color := clRed;

if (Column.Field.FieldName = '实际到货时间') then
if (DBGrid1.DataSource.DataSet.FieldByName('实际到货时间').AsDateTime >DBGrid1.DataSource.DataSet.FieldByName('要求到货时间').AsDateTime) then
   AFont.Color := clRed;
//DBGrid1.DefaultDrawColumnCell(Rect, DataCol, Column, State);
//DBGrid1.Canvas.Font.Color:=OldColor;
end;  


2004-3-29 20:12:46    DBGridEH 所有欄位自動寬度的實現interface
THackDBGridEH = class(TCustomdbgrideh)
end;

procedure OptimizeGrid(AGrid: TCustomDbGridEh);

implementation
procedure OptimizeGrid(AGrid: TCustomDbGridEh);
var
i: integer;
begin
// 優化GRID的寬度
for i := 0 to TDBGridEh(AGrid).Columns.count - 1 do
THackDBGridEH(AGrid).OptimizeSelectedColsWidth(TDBGridEh(AGrid).Columns);
end;


從ehlib 3.0開始,DBGridEH的OptionEh中就多了一個dbgDblClickOptimizeColWidth選項,設為true,就可以雙擊一個標題的右邊線,自動此列的寬度.
但是我想一次性實現整個grid的自動寬度,卻沒有找到相就的方法(真的有可能是我沒有找到,如果本身就有的話請一定要用郵件通知我喔),所以就自已寫了一個,用起來還可以,數據量大的時候就會有些慢呢!

作者email :[email protected]
  



2005-5-23 10:17:38   
发表评语»»»     

2005-5-26 18:02:12    点击DBGridEh标题实现排序KeyLife富翁笔记  
作者 : tempmen
标题 : 点击GridEh标题排序
关键字:
分类 : 个人专区
密级 : 公开
(评分: , 回复: 0, 阅读: 145) »»
1。
if (Column.Title.SortMarker = smNoneEh) or (Column.Title.SortMarker = smDownEh) then
    begin
      ADOQuery1.SORT := COLUMN.FIELDNAME;
      Column.Title.SortMarker := smUpEh
    end
  else
    begin
      ADOQuery1.SORT := COLUMN.FIELDNAME + ' DESC';
      Column.Title.SortMarker := smDownEh
    end;   
2。
以下方法用来实现 点击DBGrid列 按该列正序排序,再次点击 逆序
procedure TFormMain.MyDBGridTitleClick(Column: TColumn);
var i:integer;
begin
  if AdoQCX.Sort = Column.FieldName then    //AdoQCX为MyDBGrid绑定的Tadoquery
    begin
      For i:=0 to MyDBGrid.Columns.Count-1 do
        MyDBGrid.Columns.Title.RestoreDefaults;

      AdoQCX.Sort := Column.FieldName + ' DESC';
      Column.Title.Font.Color:=clPurple;    //用紫色表示 逆序 字段
    end
  else begin
    For i:=0 to MyDBGrid.Columns.Count-1 do
      MyDBGrid.Columns.Title.RestoreDefaults;

    AdoQCX.Sort := Column.FieldName;
    Column.Title.Font.Color:=clBlue;    //用蓝色表示正序字段
    end;
end;

顺便求教,有没有好方法实现 用上下箭头 代替颜色表示正序、逆序
前提是使用DBGrid控件,不是其他第三方控件  

3。
procedure TForm_main.DBGrid_topTitleClick(Column: TColumn);
var
lInteger_count,lInteger_Length:integer;
lString_All,lString_Last:string;
begin
for lInteger_count := 0 to dbgrid_top.FieldCount - 1 do
  begin
   lInteger_Length := length(dbgrid_top.columns[lInteger_count].Title.Caption);
   lString_Last := copy(dbgrid_top.columns[lInteger_count].Title.Caption,lInteger_Length-2,3);
   lString_All := copy(dbgrid_top.columns[lInteger_count].Title.Caption,1,lInteger_Length-3);
   if dbgrid_top.columns[lInteger_count].FieldName = column.FieldName then
    begin
     if (lString_Last = ' ▼') then
      begin
       adoquery_main.Sort := column.FieldName + ' ASC';
       dbgrid_top.columns[lInteger_count].Title.Caption := lString_All + ' ▲';
      end
     else if (lString_Last = ' ▲') then
      begin
       adoquery_main.Sort := column.FieldName + ' DESC';
       dbgrid_top.columns[lInteger_count].Title.Caption := lString_All + ' ▼';
      end
     else
      begin
       adoquery_main.Sort := column.FieldName + ' ASC';
       dbgrid_top.columns[lInteger_count].Title.Caption := lString_All + lString_Last + ' ▲';
      end;
    end
   else
    begin
     if ((lString_Last = ' ▼') or (lString_Last = ' ▲')) then
      dbgrid_top.columns[lInteger_count].Title.Caption := lString_All;
    end;
  end;
end;
  


2005-6-10 11:33:26    DBGRIDEH 组件在Borland开发工具中应用全攻略 【陈文彬】http://www.delphibbs.com/keylife/iblog_show.asp?xid=5161


2005-6-18 11:43:26    DevExpress cxGrid 使用方法汇总http://www.delphibbs.com/keylife/iblog_show.asp?xid=3893


2005-7-1 20:33:17    DBGridEh 应用实例 KeyLife富翁笔记  
作者 : delsoft
标题 : DBGridEH应用实例
关键字:
分类 : 个人专区
密级 : 公开
(评分: , 回复: 0, 阅读: 44) »»
DBGridEH应用实例
--------------------------------------------------------------------------------
作者:金软在线   来源:softsky.com.cn   发布日期:2005-4-1   点击次数: 94
应用实例
    Enlib3.0组件包安装成功后,在系统的组件面板中会显示“enlib”组件包标签(如图1),添加DBGridEh到窗体的方法与其它组件一样。在窗体中添加该组件后,请跟我一起来实现图2的一些特殊效果,具体属性设置请参考属性表的说明。

A、定制标题行
1、制作复杂标题行
    标题行可设为2行以上高度,并可以为多列创建一个共同的父标题行。为实现这个效果,需在各个列标题属性中以“|”分隔父标题和子标题,如办公用品包括代码和名称两部分,具体属性设置如下:

usemultititile=true;
titlelines=2
DBGridEh.Columns[0].Title.Caption := '办公用品|代码';
DBGridEh.Columns[1].Title.Caption := '办公用品|名称';

2、标题行显示图片
    实现图2中的购买人标题行显示效果。首先添加一个p_w_picpathlist组件img1并在其中添加一组bmp,ico格式的图片。然后将DBGridEh的TitleImages设置为img1.最后在需要显示图片的列标题的p_w_picpathindex中设置需要显示的img1中图片的序号。按F9执行一下程序,是不是很酷!

3、自动显示标题行的升降排序标志符(▽降序△升序)并做相应排序
    DBGridEh组件可以在标题行单元格中显示小三角形升、降排序标志符图片,在运行时可点击标题行,图片自动切换并做相应排序。具体属性设置如下:

OptionsEh=dghAutoSortMarking
Column.Title.TitleButton=true

SortMarkedColumns 为当前排序列可在运行时使用.
然后在该列的ontitleclick事件中添加代码:
procedure TForm_Query.DBGridEh1TitleBtnClick(Sender: TObject; ACol: Integer; Column: TColumnEh);
var
  sortstring:string; //排序列
begin
  //进行排序
  with Column do
  begin
    if FieldName = '' then
      Exit;
    case Title.SortMarker of
      smNoneEh:
      begin
        Title.SortMarker := smDownEh;
        sortstring := Column.FieldName + ' ASC';
      end;
      smDownEh: sortstring := Column.FieldName + ' ASC';
      smUpEh: sortstring := Column.FieldName + ' DESC';
    end;
  //进行排序
    try
      dataset.Sort := sortstring //dataset为实际数据集变量名
    except
    end;
  end;
end;

切记lookup型字段不可做上述设置,否则系统会提示错误。

    另外,组件说明书中提到不需要编写代码即可自动排序,但是不编写代码自动排序方法我还没找到,有知道的朋友烦请告诉我一声啊!让我也对程序代码进行“减肥”。



B、定制表格底部(footer)区域的汇总统计行
    DBGridEh 组件可以在表格底部显示汇总行,如记录数合计、列字段累加和等信息。在FooterRowCount中设置底部显示的行数;然后在Footers 编辑器中添加一个或多个显示列,显示列可以是字段值累加和、记录数合计、字段值或静态文件等集合类型,可以在设计时在ValueType属性中设置,也可在运行时通过设置Footers.ValueType指定其类型。其含义见下表:

    切记设置DBGridEh.SumList.Active 为 True,才会进行汇总统计运算。需注意的是,如显示类型为不是当前列的累加和,则需在fieldname属性中指定汇总列,其它类型则无此要求。



C、定制表格数据单元外观
1、根据不同字段值显示相应的小图片
    如根据库存材料的不同状态在数据单元格中显示相应图片,具体设置如下:
    添加一个p_w_picpathlist组件img1并在其中添加一组bmp,ico格式的图片。然后将需要显示图片的列的p_w_picpathlist属性设置为img1;在keylist属性中添加实际数据存储值,一行为一个值,切记一定要与p_w_picpathlist中图片顺序一一对应,否则会张冠李戴,面目全非。还可在picklist中添加提示信息,也要求是一行为一个值,并设tooltip为true,那么,运行时当鼠标移动到该数据单元格时在显示图片的同时还显示提示信息,怎么样,功能够强大吧!可使用空格键或鼠标切换下一张图片,图片切换的同时也改变了实际存储数据值。也可通过shift+空格或鼠标切换为上一张图片。这样就实现了上下两个方向图片切换。

2、显示检查框(checkbox)外观
    对于Boolean型字段值在dbgrideh组件中自动显示为检查框。通常情况下我们需将非Boolean型字段值也此外观显示,如性别字段为字符型,字段值为“男性”时为选中,“女性”时为未选中。需要在keylist编辑器中设置实际存储数据值,第一行为选中时的值“1”,第二行为未选中的值“0”,第三行为其它值“2”,支持三态显示。

3、显示单、多列下拉列表
    根据单元格字段值显示与其相关的其它表字段内容,如部门代码字段显示为部门名称。首先需在当前表中新建立一个lookup型字段,设置好关联表的字段和返回字段。多列下拉列表需在单列基础上做进一步设置,在LookupDisplayFields中以“;”号将关联表中多个字段分隔开,而且返回字段必须作为其中的第一项。具体设置如下:

dropdownshowtitles=true
dropdownsizing=true
dropdownwidth=-1

    例:当前表中只有部门代码无部门名称列,
式显示。

4、显示日历下拉列表
    Date 和 DateTime类型字段值均可以此形式显示。外观与编辑框无异,当点击该单元格时,右侧会出现“▽”符号,点击之即可出现日历下拉列表。有时不希望出现日历下拉列表,只需设置Column.ButtonStyle属性为 cbsNone即可,此方法同样适用于其它组件不以特殊外观显示的情况。

5、3D或平面外观效果
    设置OptionsEh属性 中fixed, frozen, footer 和 data rows等属性表格外观为3D效果,设置flat为true则为平面外观效果.

6、锁定多列不滚动
    当表格水平方向信息在一屏幕显示不下时,此项功能非常有用。例如,工资表格中包含姓名、基本工资、绩效工资等信息一屏幕显示不下,需要通过移动水平滚动条显示下一屏信息。如果不锁定关键字段列如姓名,则移动到下一屏时就不知道此条记录对应的姓名。因此,在实际应用中经常需锁定多列不滚动。

    例:姓名字段为表格第二列,则设置FrozenCols=2.这样当一屏幕显示不下,通过移动水平滚动条显示下一屏信息时,表格前两列不滚动,作为参照列。

D、导入/导出数据
    导入/导出数据在实际处理过程中是比较烦琐的。但是Enlib3.0提供了一系列函数让你轻松实现此功能,而且支持的文件格式很多:Text, Csv, HTML, RTF, XLS 和内部数据格式。除此之外,还可对任意选择的数据区域进行操作。函数如下:

Pascal: SaveDBGridEhToExportFile(TDBGridEhExportAsText,DBGridEh1,'c:\temp\file1.txt',False);

C++: SaveDBGridEhToExportFile(__classid(TDBGridEhExportAsText),DBGridEh1,"c:\\temp\\file1.txt",false);

说明:其中false参数表示导出的是选中的局部数据区域数据,true则为整个表格数据。

   例:将当前表格中数据导出为EXCEL等格式文件。
    在窗体中添加一个SaveDialog组件和“导出”按钮B_exp,在“导出”按钮的click事件中添加如下代码:

procedure TForm1.B_expClick(Sender: TObject);
var
  ExpClass:TDBGridEhExportClass;
  Ext:String;
begin
  SaveDialog1.FileName := 'file1';
  if (ActiveControl is TDBGridEh) then
    if SaveDialog1.Execute then
    begin
      case SaveDialog1.FilterIndex of
        1: begin ExpClass := TDBGridEhExportAsText; Ext := 'txt'; end;
        2: begin ExpClass := TDBGridEhExportAsCSV; Ext := 'csv'; end;
        3: begin ExpClass := TDBGridEhExportAsHTML; Ext := 'htm'; end;
        4: begin ExpClass := TDBGridEhExportAsRTF; Ext := 'rtf'; end;
        5: begin ExpClass := TDBGridEhExportAsXLS; Ext := 'xls'; end;
      else
        ExpClass := nil; Ext := '';
    end;
    if ExpClass <> nil then
    begin
      if UpperCase(Copy(SaveDialog1.FileName,Length(SaveDialog1.FileName)-2,3)) <> UpperCase(Ext) then
        SaveDialog1.FileName := SaveDialog1.FileName + '.' + Ext;
      SaveDBGridEhToExportFile(ExpClass,DBGridEh1,SaveDialog1.FileName,False);
      //其中false为局部数据
    end;
  end;
end;

E、将存在的DBGrid组件转换为DBGridEh组件.
    通过笔者上述介绍,想必你已经对Enlib组件包产生好感而且越越欲试了,那就赶快下载使用吧。但是,使用一段时间并且喜欢上它后,你又有新的问题产生了,那就是为了保持界面风格一致,能否将已经开发完成的应用程序中的DBGrid组件能否转换为DBGridEh组件,进行一次彻底革命?答案是肯定的。尽管DBGridEh并不是继承于CustomDBGrid组件, 但是DBGridEh和DBGrid它们之间有许多相同之处.因此可以相互转换。

具体步骤如下:
1、在Delphi IDE下打开TDBGrid组件.
2、通过组合键Alt-F12将form 以文本方式显示;
3、将所有TDBGrid 对象名改变为 TDBGridEh对象名,如:DBGrid1: TDBGrid改为 DBGrid1: TDBGridEh;
4、再次通过组合键Alt-F12将文本方式恢复为form 显示;
5、将form各相关事件中定义的所有TDBGrid改为TDBGrideh,如DBGrid1: TDBGrid改为DBGrid1: TDBGridEh;
6、重新编译应用程序。

    以上只是本人在实际程序开发过程中使用dbgrideh组件的一些体会,当然其功能还远不止这些。欢迎朋友与我做进一步交流。

【原作者联系方式】
     Email:[email protected]
  


2007-1-15 23:27:40    KeyLife富翁笔记  
作者 : Delphizhou
标题 : DBGrid的实用技巧
关键字: Delphi DBGrid
分类 : 开发技巧
密级 : 公开
(评分: , 回复: 0, 阅读: 137) »»
DBGrid的实用技巧

1.隔行不同颜色显示
with TDBGrid(Sender) do
begin
if (gdSelected in State) or (gdFocused in State) then
Canvas.Brush.Color := clAqua
else if DataSource.DataSet.RecNo mod 2 = 0 then
Canvas.Brush.Color := $00F0F0F5
else
Canvas.Brush.Color := clWindow;
DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;

2.Flat风格
属性设置:
Ctrl3D = False
Options.dgColLines = False
Options.dgRowLines = False

type
TGridAccess = class(TCustomGrid);

Form.OnCreate:
with TGridAccess(DBGrid1) do
Options := Options + [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine];

3.去掉滚动条
private
{ Private declarations }
FGridWndProc: TWndMethod;
procedure GridWndProc(var Message: TMessage);

Form.OnCreate:
TGridAccess(DBGrid1).ScrollBars := ssNone;
FGridWndProc := DBGrid1.WindowProc;
DBGrid1.WindowProc := GridWndProc;

Form.OnDestroy:
DBGrid1.WindowProc := FGridWndProc;

procedure TForm1.GridWndProc(var Message: TMessage);
begin
case Message.Msg of
WM_PAINT, WM_NCPAINT:
begin
SetScrollRange(DBGrid1.Handle, SB_HORZ, 0, 0, False);
SetScrollRange(DBGrid1.Handle, SB_VERT, 0, 0, False);
end;
end;
FGridWndProc(Message);
end;

4.鼠标移到某个单元格,指针形状改变
procedure TForm1.DBGrid1MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
var
Coord: TGridCoord;
begin
Coord := TDBGrid(Sender).MouseCoord(X, Y);
if (Coord.Y > 0) and (Coord.X = 1) and not TDBGrid(Sender).DataSource.DataSet.IsEmpty then
begin // Coord.X=1,dgIndicator=True时说明在第一列,False时说明在第二列
TDBGrid(Sender).Cursor := crHandPoint;
StatusBar1.SimpleText := 'Click to open curve form';
end
else
begin
TDBGrid(Sender).Cursor := crDefault;
StatusBar1.SimpleText := '';
end;
end;

5.Options.dgRowSelect=True时,点击不同单元格列,执行不同的动作
DBGrid的OnMouseDown/OnMouseUp事件在点击记录单元格时不会触发(点击固定行列区会触发),而Options.dgRowSelect=True时,OnCellClick事件的Column总是传递第一个列对象,即Column.Index=0,即使你点击的是其他列,因此需要在OnCellClick中再判断点击的是哪个列,再根据不同列执行不同的动作。
procedure TForm1.DBGrid1CellClick(Column: TColumn);
var
Coord: TGridCoord;
P: TPoint;
begin
GetCursorPos(P);
Windows.ScreenToClient(TDBGrid(Sender).Handle, P);
Coord := TDBGrid(Sender).MouseCoord(P.X, P.Y);
if (Coord.Y > 0) and (Coord.X = 1) and not TDBGrid(Sender).DataSource.DataSet.IsEmpty then
// Coord.X=1,dgIndicator=True时说明在第一列,False时说明在第二列
ShowMessage(GridRate.Columns[0].Field.AsString);
end;



2006-1-5 15:50:45
查看评语»»»

2006-1-5 16:57:15 6.支持鼠标滚轮方法一:
private
{ Private declarations }
procedure GridMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);

Form.OnCreate:
TControlAccess(DBGrid1).OnMouseWheel := GridMouseWheel;

procedure TForm1.GridMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
TDBGrid(Sender).DataSource.DataSet.MoveBy(-WheelDelta div WHEEL_DELTA);
Handled := True;
end;

方法二:
private
{ Private declarations }
FGridWndProc: TWndMethod;
procedure GridWndProc(var Message: TMessage);

Form.OnCreate:
FGridWndProc := DBGrid1.WindowProc;
DBGrid1.WindowProc := GridWndProc;

Form.OnDestroy:
DBGrid1.WindowProc := FGridWndProc;

procedure TForm1.GridWndProc(var Message: TMessage);
begin
case Message.Msg of
WM_MOUSEWHEEL:
begin
DBGrid1.DataSource.DataSet.MoveBy(-Smallint(Message.WParamHi) div WHEEL_DELTA);
end;
else FGridWndProc(Message);
end;
end;


2006-1-5 16:59:05 6.支持鼠标滚轮(补充)type
TControlAccess = class(TControl);


2006-1-17 10:39:50 隔行不同颜色显示(2)鉴于DataSource.DataSet.RecNo可能无效,改用DataLink.ActiveRecord。

type
TDBGridAccess = class(TCustomDBGrid);

procedure TForm1.GridListDrawColumnCell(Sender: TObject;
const Rect: TRect; DataCol: Integer; Column: TColumn;
State: TGridDrawState);
begin
with TDBGrid(Sender) do
begin
Canvas.Font.Color := clBlack;
if (gdSelected in State) or (gdFocused in State) then
Canvas.Brush.Color := clAqua
else if Odd(TDBGridAccess(Sender).DataLink.ActiveRecord) then
Canvas.Brush.Color := $00F0F0F5
else
Canvas.Brush.Color := clWindow;

DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;
end;


2006-1-17 14:48:45 7.显示行号unit HackGrid;

interface

uses Windows, SysUtils, Grids, DBGrids;

type
THackGrid = class
protected
class procedure NewSetColumnAttributes;
public
class procedure Hook(AIndicatorWidth: Integer);
class procedure Unhook;
class procedure DrawOrds(Sender: TObject; AState: TGridDrawState);
end;

implementation

var
GOldSetColumnAttributes: Pointer;
GIndicatorWidth: Integer;

type
TDBGridAccess = class(TCustomDBGrid);

{ THackGrid }

class procedure THackGrid.Hook(AIndicatorWidth: Integer);
var
obj: TObject;
vmt, vmtIndex: Integer;
method, newMethod: Pointer;
dwOldProtect: DWORD;
begin
GIndicatorWidth := AIndicatorWidth;
if GOldSetColumnAttributes <> nil then Exit;

obj := TDBGrid.Create(nil);
try
vmt := PInteger(obj)^;
asm
MOV vmtIndex,VMTOFFSET TDBGridAccess.SetColumnAttributes;
end;
method := Pointer(vmt + vmtIndex);
GOldSetColumnAttributes := PPointer(method)^;

VirtualProtect(method, 4, PAGE_READWRITE, dwOldProtect);
newMethod := @THackGrid.NewSetColumnAttributes;
PPointer(method)^ := newMethod;
VirtualProtect(method, 4, dwOldProtect, dwOldProtect);
finally
obj.Free;
end;
end;

class procedure THackGrid.Unhook;
var
obj: TObject;
vmt, vmtIndex: Integer;
method: Pointer;
dwOldProtect: DWORD;
begin
if GOldSetColumnAttributes = nil then Exit;

obj := TDBGrid.Create(nil);
try
vmt := PInteger(obj)^;
asm
MOV vmtIndex,VMTOFFSET TDBGridAccess.SetColumnAttributes;
end;
method := Pointer(vmt + vmtIndex);

VirtualProtect(method, 4, PAGE_READWRITE, dwOldProtect);
PPointer(method)^ := GOldSetColumnAttributes;
VirtualProtect(method, 4, dwOldProtect, dwOldProtect);
finally
obj.Free;
GOldSetColumnAttributes := nil;
end;
end;

class procedure THackGrid.NewSetColumnAttributes;
var
Grid: Pointer;
begin
asm
MOV Grid,EAX
CALL GOldSetColumnAttributes
end;
with TDBGridAccess(Grid) do
if (dgIndicator in Options) and (GIndicatorWidth > DBGrids.IndicatorWidth) then
ColWidths[0] := GIndicatorWidth;
end;

class procedure THackGrid.DrawOrds(Sender: TObject; AState: TGridDrawState);
var
FrameOffs: Integer;
R: TRect;
begin
with TDBGridAccess(Sender) do
begin
R := CellRect(0, DataLink.ActiveRecord+1);
if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options =
[dgRowLines, dgColLines]) then
FrameOffs := 1 else
FrameOffs := 2;
R.Right := R.Right - 6{FIndicator.Width} - FrameOffs - 2;
DrawText(Canvas.Handle, PChar(IntToStr(DataLink.ActiveRecord+1)), -1, R,
DT_RIGHT or DT_VCENTER or DT_SINGLELINE);
end;
end;

end.

使用:
procedure TForm1.FormCreate(Sender: TObject);
begin
THackGrid.Hook(28);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
THackGrid.Unhook;
end;

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject;
const Rect: TRect; DataCol: Integer; Column: TColumn;
State: TGridDrawState);
begin
with TDBGrid(Sender) do
begin
Canvas.Font.Color := clBlack;
if DataCol = 0 then // 一行只画一次
begin
Canvas.Brush.Color := clBtnFace;
THackGrid.DrawOrds(Sender, State);
end;
DefaultDrawColumnCell(Rect, DataCol, Column, State);
end;
end;


2006-1-23 16:24:07 7.显示行号(2)上面的代码在数据记录数下面的代码经测试基本可行,不过在数据集执行Last,当前记录已经在最后一条并且Eof=True时,再Insert插入,显示的行号比实际的大1,主要在判断是Insert插入还是Append添加的操作是通过判断Eof进行的,这就会导致误判,其他情况目前还没有发现显示不正确的。

unit MyGrid;

interface

uses Windows, Messages, Classes, SysUtils, DB, Grids, DBGrids;

type
TMyDBGrid = class(TDBGrid)
private
FIndicatorWidth: Integer;
FFirstRecNo: Integer;
FOldBeforeInsert: TDataSetNotifyEvent;
procedure DataSetBeforeInsert(DataSet: TDataSet);
function GetDataSource: TDataSource;
procedure SetDataSource(const Value: TDataSource);
procedure SetIndicatorWidth(const Value: Integer);
protected
procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override;
procedure SetColumnAttributes; override;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
public
constructor Create(AOwner: TComponent); override;
published
property IndicatorWidth: Integer read FIndicatorWidth write SetIndicatorWidth default 28;
property DataSource: TDataSource read GetDataSource write SetDataSource;
end;

implementation


{ TMyDBGrid }

constructor TMyDBGrid.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FIndicatorWidth := 28;
end;

procedure TMyDBGrid.DataSetBeforeInsert(DataSet: TDataSet);
var
iRow: Integer;
begin
iRow := Row;
if dgTitles in Options then Dec(iRow);
FFirstRecNo := DataSet.RecNo - iRow;
if Assigned(FOldBeforeInsert) then FOldBeforeInsert(DataSet);
end;

procedure TMyDBGrid.DrawCell(ACol, ARow: Integer; ARect: TRect;
AState: TGridDrawState);
var
OldActive, iRow, RowNo: Integer;
begin
inherited DrawCell(ACol, ARow, ARect, AState);

if (dgIndicator in Options) then
begin
Dec(ACol);
if dgTitles in Options then Dec(ARow);

if Assigned(DataLink) and DataLink.Active and (ACol < 0) and (ARow >= 0) then
begin
if DataLink.DataSet.State = dsInsert then
begin
if DataLink.DataSet.Eof then // Append
begin
iRow := Row;
if dgTitles in Options then Dec(iRow);
RowNo := DataLink.DataSet.RecordCount - iRow + ARow + 1
end else // Insert
RowNo := FFirstRecNo + ARow;
end
else
begin
OldActive := DataLink.ActiveRecord;
try
DataLink.ActiveRecord := ARow;
RowNo := DataSource.DataSet.RecNo;
finally
DataLink.ActiveRecord := OldActive;
end;
end;

ARect.Right := ARect.Right - 6{FIndicator.Width} - 2{FrameOffs} - 2{Space};
DrawText(Canvas.Handle, PChar(IntToStr(RowNo)), -1, ARect,
DT_RIGHT or DT_VCENTER or DT_SINGLELINE);
end;
end;
end;

function TMyDBGrid.GetDataSource: TDataSource;
begin
Result := inherited DataSource;
end;

procedure TMyDBGrid.SetColumnAttributes;
begin
inherited;
if (dgIndicator in Options) then
ColWidths[0] := FIndicatorWidth;
end;

procedure TMyDBGrid.SetDataSource(const Value: TDataSource);
begin
if Assigned(DataSource) and Assigned(DataSource.DataSet) then
DataSource.DataSet.BeforeInsert := FOldBeforeInsert;

if Assigned(Value) and Assigned(Value.DataSet) then
begin
FOldBeforeInsert := Value.DataSet.BeforeInsert;
Value.DataSet.BeforeInsert := DataSetBeforeInsert;
end else
FOldBeforeInsert := nil;

inherited DataSource := Value;
end;

procedure TMyDBGrid.SetIndicatorWidth(const Value: Integer);
begin
if FIndicatorWidth <> Value then
begin
FIndicatorWidth := Value;
if (dgIndicator in Options) then
ColWidths[0] := FIndicatorWidth;
end;
end;

procedure TMyDBGrid.WMSize(var Message: TWMSize);
var
OldRow: Integer;
begin
OldRow := Row;
inherited;
FFirstRecNo := FFirstRecNo - (Row - OldRow);
end;

end.

测试代码:
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, ADODB, ExtCtrls, DBCtrls, Grids, DBGrids, StdCtrls;

type
TForm1 = class(TForm)
DBNavigator1: TDBNavigator;
ADOConnection1: TADOConnection;
ADOTable1: TADOTable;
DataSource1: TDataSource;
Button1: TButton;
Label1: TLabel;
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses MyGrid;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
with TMyDBGrid.Create(Self) do
begin
Parent := Panel1;
Align := alClient;
IndicatorWidth := 40;
Options := Options - [dgTitles];
DataSource := DataSource1;
end;
ADOTable1.Open;
Label1.Caption := IntToStr(ADOTable1.RecordCount);
end;

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

end.  
  


2007-3-23 0:04:30    KeyLife富翁笔记  
作者 : archonwang
标题 : DBGRIDEH 组件在Borland开发工具中应用全攻略 【陈文彬】
关键字:
分类 : 个人专区
密级 : 公开
(评分:★★★★★ , 回复: 16, 阅读: 14877) »»

    DBGRIDEH 是Enlib 3.0组件包中的组件之一。Enlib 3.0组件包是一位俄国人为增强Borland系列开发工具功能而开发的第三方组件,它具有界面友好、功能强大、开发效率高、、快速制作预览/打印简单中国式报表等特点。因此,一推出即受到广大Borland程序员的青睐。目前这个版本支持Borland Delphi versions 4,5,6&7 和 Borland C++ Builder versions 4 & 5 ,可极大地提高数据库应用系统客户端的性能。许多商品软件如《速达2000》等都使用了该组件。下面本人将使用该组件在实际系统开发过程中的经验总结如下。

    Enlib3.0组件包中最重要而且功能最强大的莫过于dbgrideh组件,本文介绍的所有实例均在Delphi 7开发环境下调试通过。

一、DBGridEh(增强型表格组件)功能详解
    DBGridEh组件无论在外观上还是功能上都非常类似Borland开发工具中现有的dbgrid组件,它除了提供dbgrid组件的全部功能外,还增加了下列新功能:

● 任意选择多行、列或矩形区域的数据.
● 为多列标题设定共同的父标题行.
● 表格底部(Footer) 区显示求和、计数和其它统计信息.
● 自动调整组件宽度与客户区域等宽.
● 设置标题行、数据行的高度.
● 超长的标题行、数据行文本自动折行处理.
● 标题行可作为按钮使用,并可选择是否显示排序标志符(▽降序△升序).
● 点击列标题可对当前列自动排序而无需编写代码.
● 能够自动设置删除超长文本显示不下的多余部分,并以省略号(…)代替.
● 自动搜索字段(Lookup)数据单元格以单、多列字段下拉列表形式显示.
● 自动搜索字段(Lookup)数据单元格可进行增量搜索.
● 可锁定任意列数在屏幕水平方向不滚动.
● 日期时间控件DateTime picker 可支持TDateField and TDateTimeField两种日期格式.
● 根据字段不同值显示关联的ImageList 对象图片组中的图片.
● 隐藏任意列.
● 显示3D风格的数据区、表尾区和锁定滚动列,制作3D外观表格.
● 显示Memo类型字段值.
● 除BOOLEAN型数据外,其它数据类型也可以检查框( checkbox )形式显示数据.
● 使用专门的函数和过程来存取以reg或ini文件格式保存的表格布局(包含各数据列表、数据列访问顺序、列宽、索引标识、行高等信息)文件。
● 通过设置数据单元格的hint和ToolTips属性,当移动鼠标到该单元格时,可以显示单元格容纳不下的文本内容.
● 将组件中数据导入/导出到Text, Csv, HTML, RTF, XLS 和内部数据等多种格式的文件中.

    DBGridEh组件主要属性见下表(其它属性参见dbgrid):

    DBGridEh组件事件基本与DBGrid相同,在此不再赘述。
  



2004-1-2 11:32:00   
发表评语»»»     

2004-1-2 11:33:10   


2004-1-2 11:33:33   


2004-1-2 11:37:47    二、应用实例
    Enlib3.0组件包安装成功后,在系统的组件面板中会显示“enlib”组件包标签(如图1),添加DBGridEh到窗体的方法与其它组件一样。在窗体中添加该组件后,请跟我一起来实现图2的一些特殊效果,具体属性设置请参考属性表的说明。

A、定制标题行
1、制作复杂标题行
    标题行可设为2行以上高度,并可以为多列创建一个共同的父标题行。为实现这个效果,需在各个列标题属性中以“|”分隔父标题和子标题,如办公用品包括代码和名称两部分,具体属性设置如下:

usemultititile=true;
titlelines=2
DBGridEh.Columns[0].Title.Caption := '办公用品|代码';
DBGridEh.Columns[1].Title.Caption := '办公用品|名称';

2、标题行显示图片
    实现图2中的购买人标题行显示效果。首先添加一个p_w_picpathlist组件img1并在其中添加一组bmp,ico格式的图片。然后将DBGridEh的TitleImages设置为img1.最后在需要显示图片的列标题的p_w_picpathindex中设置需要显示的img1中图片的序号。按F9执行一下程序,是不是很酷!

3、自动显示标题行的升降排序标志符(▽降序△升序)并做相应排序
    DBGridEh组件可以在标题行单元格中显示小三角形升、降排序标志符图片,在运行时可点击标题行,图片自动切换并做相应排序。具体属性设置如下:

OptionsEh=dghAutoSortMarking
Column.Title.TitleButton=true

SortMarkedColumns 为当前排序列可在运行时使用.
然后在该列的ontitleclick事件中添加代码:
procedure TForm_Query.DBGridEh1TitleBtnClick(Sender: TObject; ACol: Integer; Column: TColumnEh);
var
  sortstring:string; //排序列
begin
  //进行排序
  with Column do
  begin
    if FieldName = '' then
      Exit;
    case Title.SortMarker of
      smNoneEh:
      begin
        Title.SortMarker := smDownEh;
        sortstring := Column.FieldName + ' ASC';
      end;
      smDownEh: sortstring := Column.FieldName + ' ASC';
      smUpEh: sortstring := Column.FieldName + ' DESC';
    end;
  //进行排序
    try
      dataset.Sort := sortstring //dataset为实际数据集变量名
    except
    end;
  end;
end;

切记lookup型字段不可做上述设置,否则系统会提示错误。

    另外,组件说明书中提到不需要编写代码即可自动排序,但是不编写代码自动排序方法我还没找到,有知道的朋友烦请告诉我一声啊!让我也对程序代码进行“减肥”。


2004-1-2 11:38:16   


2004-1-2 11:39:41    B、定制表格底部(footer)区域的汇总统计行
    DBGridEh 组件可以在表格底部显示汇总行,如记录数合计、列字段累加和等信息。在FooterRowCount中设置底部显示的行数;然后在Footers 编辑器中添加一个或多个显示列,显示列可以是字段值累加和、记录数合计、字段值或静态文件等集合类型,可以在设计时在ValueType属性中设置,也可在运行时通过设置Footers.ValueType指定其类型。其含义见下表:

    切记设置DBGridEh.SumList.Active 为 True,才会进行汇总统计运算。需注意的是,如显示类型为不是当前列的累加和,则需在fieldname属性中指定汇总列,其它类型则无此要求。


2004-1-2 11:43:13   


2004-1-2 11:47:50    C、定制表格数据单元外观
1、根据不同字段值显示相应的小图片
    如根据库存材料的不同状态在数据单元格中显示相应图片,具体设置如下:
    添加一个p_w_picpathlist组件img1并在其中添加一组bmp,ico格式的图片。然后将需要显示图片的列的p_w_picpathlist属性设置为img1;在keylist属性中添加实际数据存储值,一行为一个值,切记一定要与p_w_picpathlist中图片顺序一一对应,否则会张冠李戴,面目全非。还可在picklist中添加提示信息,也要求是一行为一个值,并设tooltip为true,那么,运行时当鼠标移动到该数据单元格时在显示图片的同时还显示提示信息,怎么样,功能够强大吧!可使用空格键或鼠标切换下一张图片,图片切换的同时也改变了实际存储数据值。也可通过shift+空格或鼠标切换为上一张图片。这样就实现了上下两个方向图片切换。

2、显示检查框(checkbox)外观
    对于Boolean型字段值在dbgrideh组件中自动显示为检查框。通常情况下我们需将非Boolean型字段值也此外观显示,如性别字段为字符型,字段值为“男性”时为选中,“女性”时为未选中。需要在keylist编辑器中设置实际存储数据值,第一行为选中时的值“1”,第二行为未选中的值“0”,第三行为其它值“2”,支持三态显示。

3、显示单、多列下拉列表
    根据单元格字段值显示与其相关的其它表字段内容,如部门代码字段显示为部门名称。首先需在当前表中新建立一个lookup型字段,设置好关联表的字段和返回字段。多列下拉列表需在单列基础上做进一步设置,在LookupDisplayFields中以“;”号将关联表中多个字段分隔开,而且返回字段必须作为其中的第一项。具体设置如下:

dropdownshowtitles=true
dropdownsizing=true
dropdownwidth=-1

    例:当前表中只有部门代码无部门名称列,需与部门表建立关联,当点击单元格时以部门代码、部门名称两列下拉列表形式显示。

4、显示日历下拉列表
    Date 和 DateTime类型字段值均可以此形式显示。外观与编辑框无异,当点击该单元格时,右侧会出现“▽”符号,点击之即可出现日历下拉列表。有时不希望出现日历下拉列表,只需设置Column.ButtonStyle属性为 cbsNone即可,此方法同样适用于其它组件不以特殊外观显示的情况。

5、3D或平面外观效果
    设置OptionsEh属性 中fixed, frozen, footer 和 data rows等属性表格外观为3D效果,设置flat为true则为平面外观效果.

6、锁定多列不滚动
    当表格水平方向信息在一屏幕显示不下时,此项功能非常有用。例如,工资表格中包含姓名、基本工资、绩效工资等信息一屏幕显示不下,需要通过移动水平滚动条显示下一屏信息。如果不锁定关键字段列如姓名,则移动到下一屏时就不知道此条记录对应的姓名。因此,在实际应用中经常需锁定多列不滚动。

    例:姓名字段为表格第二列,则设置FrozenCols=2.这样当一屏幕显示不下,通过移动水平滚动条显示下一屏信息时,表格前两列不滚动,作为参照列。

D、导入/导出数据
    导入/导出数据在实际处理过程中是比较烦琐的。但是Enlib3.0提供了一系列函数让你轻松实现此功能,而且支持的文件格式很多:Text, Csv, HTML, RTF, XLS 和内部数据格式。除此之外,还可对任意选择的数据区域进行操作。函数如下:

Pascal: SaveDBGridEhToExportFile(TDBGridEhExportAsText,DBGridEh1,'c:\temp\file1.txt',False);

C++: SaveDBGridEhToExportFile(__classid(TDBGridEhExportAsText),DBGridEh1,"c:\\temp\\file1.txt",false);

说明:其中false参数表示导出的是选中的局部数据区域数据,true则为整个表格数据。

   例:将当前表格中数据导出为EXCEL等格式文件。
    在窗体中添加一个SaveDialog组件和“导出”按钮B_exp,在“导出”按钮的click事件中添加如下代码:

procedure TForm1.B_expClick(Sender: TObject);
var
  ExpClass:TDBGridEhExportClass;
  Ext:String;
begin
  SaveDialog1.FileName := 'file1';
  if (ActiveControl is TDBGridEh) then
    if SaveDialog1.Execute then
    begin
      case SaveDialog1.FilterIndex of
        1: begin ExpClass := TDBGridEhExportAsText; Ext := 'txt'; end;
        2: begin ExpClass := TDBGridEhExportAsCSV; Ext := 'csv'; end;
        3: begin ExpClass := TDBGridEhExportAsHTML; Ext := 'htm'; end;
        4: begin ExpClass := TDBGridEhExportAsRTF; Ext := 'rtf'; end;
        5: begin ExpClass := TDBGridEhExportAsXLS; Ext := 'xls'; end;
      else
        ExpClass := nil; Ext := '';
    end;
    if ExpClass <> nil then
    begin
      if UpperCase(Copy(SaveDialog1.FileName,Length(SaveDialog1.FileName)-2,3)) <> UpperCase(Ext) then
        SaveDialog1.FileName := SaveDialog1.FileName + '.' + Ext;
      SaveDBGridEhToExportFile(ExpClass,DBGridEh1,SaveDialog1.FileName,False);
      //其中false为局部数据
    end;
  end;
end;

E、将存在的DBGrid组件转换为DBGridEh组件.
    通过笔者上述介绍,想必你已经对Enlib组件包产生好感而且越越欲试了,那就赶快下载使用吧。但是,使用一段时间并且喜欢上它后,你又有新的问题产生了,那就是为了保持界面风格一致,能否将已经开发完成的应用程序中的DBGrid组件能否转换为DBGridEh组件,进行一次彻底革命?答案是肯定的。尽管DBGridEh并不是继承于CustomDBGrid组件, 但是DBGridEh和DBGrid它们之间有许多相同之处.因此可以相互转换。

具体步骤如下:
1、在Delphi IDE下打开TDBGrid组件.
2、通过组合键Alt-F12将form 以文本方式显示;
3、将所有TDBGrid 对象名改变为 TDBGridEh对象名,如:DBGrid1: TDBGrid改为 DBGrid1: TDBGridEh;
4、再次通过组合键Alt-F12将文本方式恢复为form 显示;
5、将form各相关事件中定义的所有TDBGrid改为TDBGrideh,如DBGrid1: TDBGrid改为DBGrid1: TDBGridEh;
6、重新编译应用程序。

    以上只是本人在实际程序开发过程中使用dbgrideh组件的一些体会,当然其功能还远不止这些。欢迎朋友与我做进一步交流。