最近在学习使用cxGrid,安装的版本是ExpressQuantumGrid Suite v5.10
我发现这个控件功能虽然强大,但是非常难用。现在我手头就有几个问题还没解决:
1)主从模式下导出Excel中文会产生乱码,而且从表内容没有导出。
我不知道是不是因为我的字段名包括单引号的原因。
导出代码:ExportGrid4ToExcel(FileName, cxGrid);2)主从模式下通过按钮对从表添加/删除行,代码怎么写。
附:单表添加/删除行的代码
procedure TFormAccount.cxButtonNewClick(Sender: TObject);
begin
  Self.tvAccount.DataController.Append;
  Self.tvAccount.Columns[0].Focused := True;
  cxGrid.SetFocus;
end;procedure TFormAccount.cxButtonDeleteClick(Sender: TObject);
begin
  if Self.tvAccount.DataController.RowCount = 0 then
    Exit;
  if Application.MessageBox('确认删除当前记录?', '确认删除',
    MB_YesNo + MB_IconQuestion) = IDNO then
    Exit;
  Self.tvAccount.DataController.DeleteFocused;
end;3)动态创建主从结构出错(Compiler没错,运行时出现系统错误0000000018),
我使用了二个ADOStoreProcedure作主从表
代码如下:
var
  Level: TcxGridLevel;
  GridView: TcxGridDBTableView;
begin
  Level := cxGrid1.Levels[0].Add;
  GridView := TcxGridDBTableView(cxGrid1.CreateView(TcxGridDBTableView));
  GridView.DataController.DataSource := Self.dsDetail;  GridView.DataController.KeyFieldNames := 'PurchOrderID;POLineNbr;PromiseDate;ReceiverDate';
  GridView.DataController.MasterKeyFieldNames := 'VendorID';
  GridView.DataController.DetailKeyFieldNames := 'VendorID';
  GridView.DataController.DataModeController.SmartRefresh := True;  GridView.OptionsCustomize.ColumnHiding := True;
  GridView.OptionsCustomize.ColumnsQuickCustomization := True;
  GridView.OptionsData.Deleting := False;
  GridView.OptionsData.Inserting := False;
  GridView.OptionsView.Indicator := True;
  Level.GridView := GridView;  GridView := TcxGridDBTableView(cxGrid1.Levels[0].GridView);
  GridView.DataController.KeyFieldNames := 'VendorID';
  GridView.OptionsView.GroupByBox := False;  //显示主表内容
  tvResult.BeginUpdate;
  tvResult.ClearItems;
  tvResult.DataController.CreateAllItems;
  tvResult.EndUpdate;  //显示明细表内容
  GridView := TcxGridDBTableView(cxGrid1.Levels[0].Items[0].GridView);
  GridView.BeginUpdate;
  GridView.ClearItems;
  GridView.DataController.CreateAllItems;
  GridView.DataController.Refresh;
  GridView.EndUpdate;
end;

解决方案 »

  1.   

    小技巧:用代码展开/收缩主从结构
    Self.tvDepartment.ViewData.Expand(True);
    Self.tvDepartment.ViewData.Collaspe(True);
    注:tvDepartment为主表对应的TableView
      

  2.   

    你说的这几个问题我也遇到过。
    第一个问题是编码的问题,修改了其中关于编码的函数,OK.
    第二个问题在cxGrid的社区可以找到解答,但从表必须满足某种条件,例如关键字排序。
    第三个问题的解决办法,你可以尝试在动态创建的代码前后加上:
    grid.beginupdate;
    ...
    grid.endupdate
    来解决。
      

  3.   

    to tttk(网络芝麻):
    第一个问题:如何修改啊,贴出代码
    第二个问题:没搜到啊
    第三个问题:试一下再说
      

  4.   

    不要经常使用三方控件
    ======================
    我感觉不用cxGrid的话,没必要用Delphi了,呵呵
      

  5.   

    樓上這話是不是有點問題?DELPHI能做得事情很多很多,難道非要用CXGRID?CXGRID不是用DELPHI做出來得?
      

  6.   

    回复人: zxkid(没有人会像我这样...) ( ) 信誉:101  2006-01-06 16:58:00  得分: 0  
     
     
       不要经常使用三方控件
    ======================
    我感觉不用cxGrid的话,没必要用Delphi了,呵呵
      
     
    **********
    楼主乃天人也!!
      

  7.   

    cxGrid比较不错,我也使用过导出到Excel,没有遇到你说的乱码主从表也没有问题的,其实跟单表操作还不是一回事
      

  8.   

    楼主乃天人也!!
    =============================
    Delphi下有cxGrid, .NET下有XtraGrid, 它们都是同一公司出的。
    迟早都会转到.NET,所以
      

  9.   

    发一个邮件给我,我把解决乱码后的源代码发一分给你,放到你的项目文件夹下即可。
    [email protected]
      

  10.   

    第二个问题:https://www.devexpress.com/Support/Center/default.aspx?view=ViewIssue&issueid=B2691
      

  11.   

    谢谢tttk(网络芝麻) 第二个问题:我现在直接让用户用导航条的删除/添加按钮了。根据你给的网址上的内容我知道大概该怎么写了,有空再试试。第一个问题:不光是乱码问题,还有从表内容没导出的问题。
    只有一个表的话是不会出现乱码的。第三个问题:还没来得及试。
      

  12.   

    第一个问题:看了一下帮助,原来cxGrid不支持主从表的导出,只能导出主表(顶层表)的内容。晕
      

  13.   

    贴一些小技巧,希望与各位使用cxGrid的朋友共同交流
    各位有什么好个技巧也可以贴出来:技巧二:在内置右键菜单的后面增加菜单项首先应在Form上加一个cxGridPopupMenu控件 以启用右键菜单
    UseBuildInPopupMenus设为Trueprocedure TFormItemList.FormCreate(Sender: TObject);
    var
      AMenu: TComponent;
      FMenuItem, FSubMenuItem: TMenuItem;
    begin
      AMenu := nil;
      if cxGridPopupMenu.BuiltInPopupMenus.Count = 0 then
        Exit;
      AMenu := cxGridPopupMenu.BuiltInPopupMenus[0].PopupMenu; //第一个内置右键菜单(表头菜单)
      if Assigned(AMenu) and AMenu.InheritsFrom(TPopupMenu) then
      begin
        TPopupMenu(AMenu).AutoHotkeys := maManual;    //手动热键    //-------------------------
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Caption := '-';
        FMenuItem.Name := 'miLineForGroup';
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //展开所有组
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Name := 'miExpandAllGroup';
        FMenuItem.Caption := '展开所有组(&X)';
        FMenuItem.OnClick := miExpandAllGroupClick;
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //收缩所有组
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Name := 'miCollapseAllGroup';
        FMenuItem.Caption := '收缩所有组(&O)';
        FMenuItem.OnClick := miCollapseAllGroupClick;
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //-------------------------
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Caption := '-';
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //过滤面板
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Name := 'miFilterPanel';
        FMenuItem.Caption := '过滤面板(&P)';
        //自动显示
        FSubMenuItem := TMenuItem.Create(Self);
        FSubMenuItem.Name := 'miFilterPanelAuto';
        FSubMenuItem.Caption := '自动(&A)';
        FSubMenuItem.RadioItem := True;
        FSubMenuItem.GroupIndex := 5; //指定同一组
        FSubMenuItem.Checked := True;
        FSubMenuItem.OnClick := miFilterPanelClick;
        FMenuItem.Add(FSubMenuItem); //加入二级子菜单
        //总是显示
        FSubMenuItem := TMenuItem.Create(Self);
        FSubMenuItem.Name := 'miFilterPanelAlways';
        FSubMenuItem.Caption := '总是显示(&W)';
        FSubMenuItem.RadioItem := True;
        FSubMenuItem.GroupIndex := 5;
        FSubMenuItem.OnClick := miFilterPanelClick;
        FMenuItem.Add(FSubMenuItem);
        //从不显示
        FSubMenuItem := TMenuItem.Create(Self);
        FSubMenuItem.Name := 'miFilterPanelNerver';
        FSubMenuItem.Caption := '从不显示(&N)';
        FSubMenuItem.RadioItem := True;
        FSubMenuItem.GroupIndex := 5;
        FSubMenuItem.OnClick := miFilterPanelClick;
        FMenuItem.Add(FSubMenuItem);
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //自定义过滤
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Name := 'miCustomFilter';
        FMenuItem.Caption := '自定义过滤(&M)';
        FMenuItem.OnClick := miCustomFilterClick;
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //过滤管理器
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Name := 'miFilterBuilder';
        TPopupMenu(AMenu).Images.AddImage(FormMain.ImageListExtend, 44); //添加图标图像
        FMenuItem.ImageIndex := TPopupMenu(AMenu).Images.Count - 1; //指定图标序号
        FMenuItem.Caption := '过滤管理器';
        FMenuItem.OnClick := Self.miFilterBuilderClick;
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //---------------------
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Caption := '-';
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //导出
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Name := 'miExport';
        TPopupMenu(AMenu).Images.AddImage(FormMain.ImageListExtend, 37);
        FMenuItem.ImageIndex := TPopupMenu(AMenu).Images.Count - 1;
        FMenuItem.Caption := '导出(&E)';
        FMenuItem.OnClick := Self.miExportClick;
        TPopupMenu(AMenu).Items.Add(FMenuItem);    //打印
        FMenuItem := TMenuItem.Create(Self);
        FMenuItem.Name := 'miPrint';
        FMenuItem.Caption := '打印(&P)';
        TPopupMenu(AMenu).Images.AddImage(FormMain.ImageListExtend, 14);
        FMenuItem.ImageIndex := TPopupMenu(AMenu).Images.Count - 1;
        FMenuItem.OnClick := Self.miPrintClick;
        TPopupMenu(AMenu).Items.Add(FMenuItem);
      end;
    end;procedure TFormItemList.miExportClick(Sender: TObject);
    var
      FileName, FileExt, msg: String;
    begin
      if Self.aqyQuery.IsEmpty then
      begin
        msg := '没有导出数据...';
        Application.MessageBox(PChar(msg), PChar(Application.Title),
          MB_OK or MB_IconWarning);
        Exit;
      end;  Self.SaveDialogExport.Filter := 'Excel文件 (*.xls)|*.xls|XML文件 (*.xml)|*.xml'
        + '|文本文件 (*.txt)|*.txt|网页文件 (*.html)|*.html';
      Self.SaveDialogExport.Title := '导出为';  if not Self.SaveDialogExport.Execute then
        Exit;  FileName := Self.SaveDialogExport.FileName;
      FileExt := LowerCase(ExtractFileExt(FileName));
      if FileExt = '.xls' then
        ExportGrid4ToExcel(FileName, Self.cxGrid1)
      else if FileExt = '.xml' then
        ExportGrid4ToXML(FileName, Self.cxGrid1)
      else if FileExt = '.txt' then
        ExportGrid4ToText(FileName, Self.cxGrid1)
      else if FileExt = '.html' then
        ExportGrid4ToHTML(FileName, Self.cxGrid1)
      else
      begin
        msg := '不支持的导出文件类型...';
        Application.MessageBox(PChar(msg), PChar(Application.Title),
          MB_OK or MB_IconError);
        Exit;
      end;  msg := '导出完成...';
      Application.MessageBox(PChar(msg), PChar(Application.Title),
        MB_OK or MB_IconInformation);
    end;procedure TFormItemList.miPrintClick(Sender: TObject);
    begin
      //打印
      Self.dxComponentPrinter.Preview(True, Self.dxComponentPrinterLink1);
    end;procedure TFormItemList.cxGridPopupMenuPopup(ASenderMenu: TComponent;
      AHitTest: TcxCustomGridHitTest; X, Y: Integer; var AllowPopup: Boolean);
    begin
      if GetHitTypeByHitCode(AHitTest.HitTestCode) = gvhtColumnHeader then //右击列标题时
      begin
        //if tvResult.DataController.Groups.GroupingItemCount > 0 then
        if tvResult.GroupedColumnCount > 0 then //有分组时显示
        begin
         TMenuItem(Self.FindComponent('miLineForGroup')).Visible := True;
         TMenuItem(Self.FindComponent('miExpandAllGroup')).Visible := True;
         TMenuItem(Self.FindComponent('miCollapseAllGroup')).Visible := True;
        end
        else
        begin
         TMenuItem(Self.FindComponent('miLineForGroup')).Visible := False;
         TMenuItem(Self.FindComponent('miExpandAllGroup')).Visible := False;
         TMenuItem(Self.FindComponent('miCollapseAllGroup')).Visible := False;
        end;
      end;
    end;procedure TFormItemList.miFilterBuilderClick(Sender: TObject);
    begin
      //过滤管理器
      //弹出Filter Builder Dialog对话框
      tvResult.Filtering.RunCustomizeDialog;
    end;procedure TFormItemList.miCustomFilterClick(Sender: TObject);
    var
      AHitTest: TcxCustomGridHitTest;
    begin
      //自定义过滤
      //弹出Custom Filter Dialog对话框
      AHitTest := cxGridPopupMenu.HitTest;
      if GetHitTypeByHitCode(AHitTest.HitTestCode) = gvhtColumnHeader then //获得右击的列
        tvResult.Filtering.RunCustomizeDialog(TcxGridColumnHeaderHitTest(AHitTest).Column);
    end;procedure TFormItemList.miFilterPanelClick(Sender: TObject);
    var
      mi: TMenuItem;
    begin
      //隐藏/显示过滤面板
      mi := TMenuItem(Sender);
      mi.Checked := True;
      if mi.Name = 'miFilterPanelAlways' then
        tvResult.Filtering.Visible := fvAlways
      else if mi.Name = 'miFilterPanelNerver' then
        tvResult.Filtering.Visible := fvNever
      else
        tvResult.Filtering.Visible := fvNonEmpty;
    end;procedure TFormItemList.miExpandAllGroupClick(Sender: TObject);
    begin
      //展开所有组
      tvResult.DataController.Groups.FullExpand;
    end;procedure TFormItemList.miCollapseAllGroupClick(Sender: TObject);
    begin
      //收缩所有组
      tvResult.DataController.Groups.FullCollapse;
    end;
      

  14.   

    技巧三 按条件计算合计值在Footer的第一列显示[合计:]
    加一个Summary项,Column设为Grid的第一列,Kind设为skNone
    在该Summary项的OnGetText事件中,输入:
    procedure TFormExpense.tvExpenseTcxGridDBDataControllerTcxDataSummaryFooterSummaryItems2GetText(
      Sender: TcxDataSummaryItem; const AValue: Variant; AIsFooter: Boolean;
      var AText: String);
    begin
      AText := '合计:';
    end;按条件汇总:
    在TableView的DataController->Summary->FooterSummary->OnSummary事件中,输入:
    procedure TFormExpense.tvExpenseDataControllerSummaryFooterSummaryItemsSummary(
      ASender: TcxDataSummaryItems; Arguments: TcxSummaryEventArguments;
      var OutArguments: TcxSummaryEventOutArguments);
    begin
      //得到字段名 TcxDBDataSummaryItem(Arguments.SummaryItem).FieldName;
      if (ASender.DataController.Values[Arguments.RecordIndex, tvExpenseLevel.Index] > 1)   //只统计Level列=1的值
        and (TcxDBDataSummaryItem(Arguments.SummaryItem).Kind = skSum) then
        OutArguments.Value := 0; //Level > 1的统计值设为0
    end;
      

  15.   

    借贵地一用,问个CXGrid问题,在cxgrid中如何使一些行不能编辑,如:字段isenable = false的行
      

  16.   

    楼上的问题
    请参考下面的技巧技巧四:根据某列的值设定其它列的可编辑性procedure TFormUser.tvUserEditing(Sender: TcxCustomGridTableView;
      AItem: TcxCustomGridTableItem; var AAllow: Boolean);
    begin
      //如果第三列值为True,则第4列不能修改
      if (tvUser.Controller.FocusedRecord.Values[2] = True) and (AItem.Index = 4) then
        AAllow := False
      else
        AAllow := True;
    end;
      

  17.   

    技巧五:保存/恢复Grid布局//恢复布局
    IniFileName := ExtractFilePath(Application.ExeName) + 'Layout\' + Self.Name + '.ini';
    if FileExists(IniFileName) then
      Self.tvResult.RestoreFromIniFile(IniFileName) //从布局文件中恢复
    else
    begin
      Self.tvResult.BeginUpdate;
      for i := 0 to Self.tvResult.ItemCount - 1 do
        Self.tvResult.Items[i].ApplyBestFit; //调整为最佳宽度
      Self.tvResult.EndUpdate;
    end;//保存布局
    IniFileName := ExtractFilePath(Application.ExeName) + 'Layout\' + Self.Name + '.ini';
    if not DirectoryExists(ExtractFileDir(IniFileName)) then
      CreateDir(ExtractFileDir(IniFileName));
    Self.tvResult.StoreToIniFile(IniFileName); //保存为布局文件
      

  18.   

    借用地问一下:在 cxgrid中,如果我同时选中主表与子表中的记录,怎么样能同时进行对其所选记录进行处理呢。
    我现在只能判断 焦点是在主表还是从表中,然后只能对主表或子表中的数据进行处理。
      

  19.   

    看来用cxGrid人不多啊再多贴一些技巧,需要的朋友顶一下==========================================================================在主从TableView中根据主TableView得到对应的从TableView
    var
      ADetailDC: TcxGridDataController;
      AView: TcxCustomGridTableView;
    begin
      with cxGrid1DBTableView1.DataController do
        ADetailDC := TcxGridDataController(GetDetailDataController(FocusedRecordIndex, 0));
      AView := ADetailDC.GridView;
    end;==============================================================================定位在第一行并显示内置编辑器cxDBVerticalGrid1.FocusedRow := cxDBVerticalGrid1.Rows[0];
    cxDBVerticalGrid1.ShowEdit;==============================================================================隐藏 "<No data to display>" 字符串该文本存储在scxGridNoDataInfoText资源字符串,可以将该资源字符串的内容设为空
    来隐藏该文本。uses cxClasses, cxGridStrs; 
      ...
      cxSetResourceString(@scxGridNoDataInfoText, '');  //如果"<No data to display>" 字符串已经显示,需要调用:
      <View>.LayoutChanged;============================================================删除应用过滤后的行var
      I: Integer;
    begin
      with <GridView> do
        for I := 0 to ViewData.RecordCount - 1 do
        begin
          ViewData.Records[0].Focused := True;
          DataController.DataSet.Delete;
        end;=============================================================根据单元的值设置样式procedure <aForm>.<aColumn>StylesGetContentStyle(
      Sender: TcxCustomGridTableView; ARecord: TcxCustomGridRecord;
      AItem: TcxCustomGridTableItem; out AStyle: TcxStyle);
    begin
      if ARecord.Values[AItem.Index] = aSomeValue then
        AStyle := <aSomeStyle>;
    end;procedure <aForm>.<aView>StylesGetContentStyle(
      Sender: TcxCustomGridTableView; ARecord: TcxCustomGridRecord;
      AItem: TcxCustomGridTableItem; out AStyle: TcxStyle);
    var
      AColumn: TcxCustomGridTableItem;
    begin
      AColumn := (Sender as TcxGridDBTableView).GetColumnByFieldName('Email');
      if VarToStr(ARecord.Values[AColumn.Index]) = '' then
        AStyle := cxStyleNullEmail;
    end;==============================================================================TcxCustomGridTableView.FindItemByName, TcxGridDBTableView.GetColumnByFieldName or
    TcxGridDBDataController.GetItemByFieldName  with cxGrid1DBBandedTableView1.DataController do
        AValue := Values[FocusedRecordIndex, GetItemByFieldName('SomeFieldName').Index];===================================================================动态生成BandedViewvar
      AView: TcxCustomGridView;
    begin
      AView := <cxGrid>.CreateView(TcxGridDBBandedTableView);
      TcxGridDBBandedTableView(AView).DataController.DataSource := <DataSource>;
      TcxGridDBBandedTableView(AView).Bands.Add;
      with TcxGridDBBandedTableView(AView).Bands.Add do
      begin
        Visible := False;
        FixedKind := fkLeft;
      end;
      TcxGridDBBandedTableView(AView).DataController.CreateAllItems;
      <cxGridLevel>.GridView := AView;
      

  20.   

    ======================================================================当底层数据集为空时显示一条空记录procedure <Form>.<cxGrid>Enter(Sender: TObject);
    var
      View: TcxGridDBTableView;
    begin
      View := TcxGridDBTableView((Sender as TcxGrid).FocusedView);
      if View.DataController.DataSet.IsEmpty then
      begin
        View.DataController.DataSet.Append;
        View.Controller.EditingController.ShowEdit;
      end;
    end;=======================================================================在当前View插入记录使用FocusedView属性得到当前焦点View,用View.DataController得到对应的Data Controller,
    之后使用Data Controller的方法来操作数据:
    - Append
    - Insert
    - Post
    - Cancel
    - DeleteFocused
    - DeleteSelection示例:
    var
      ARecIndex: Integer;

      View.DataController.Append;
      ARecIndex := View.DataController.FocusedRecordIndex;
      View.DataController.Values[ARecIndex, SomeItemIndex] := SomeValue;
      View.DataController.Post;另外一种方法是使用View.DataController.DataSource.DataSet得到底层数据集后,再用数据集的
    方法来操作数据。========================================================================激活内置编辑控件 1) <aView>.Controller.EditingController.ShowEdit(<aColumn>);
     2) <aView>.Controller.EditingController.StartEditShowingTimer(<aColumn>);
     3) <aView>.Controller.EditingItem := <aColumn>;
     4) <aColumn>.Editing := True;隐藏内置编辑控件
      <aView>.Controller.EditingController.HideEdit(True);===========================================================================移除一个分组列  <aColumn>.GroupIndex := -1;
      <aColumn>.Visible := True;===========================================================================保存修改到数据库procedure <aForm>.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      if (<aGrid>.FocusedView <> nil) and (<aGrid>.FocusedView.DataController.EditState <> []) then
        <aGrid>.FocusedView.DataController.Post;
    end;============================================================================设置内置右键菜单内置右键菜单包括二个菜单:cxGridStdHeaderMenu, TcxGridStdFooterMenuuses cxGridStdPopupMenu;procedure TForm1.cxGridPopupMenu1Popup(ASenderMenu: TComponent;
      AHitTest: TcxCustomGridHitTest; X, Y: Integer; var AllowPopup: Boolean);
    begin
      if ASenderMenu is TcxGridStdHeaderMenu then
        TcxGridStdHeaderMenu(ASenderMenu).OnPopup := StdHeaderMenuPopup;
    end;procedure TForm1.StdHeaderMenuPopup(Sender: TObject);
    var
      I: Integer;
    begin
      with TcxGridStdHeaderMenu(Sender).Items do
        for I := 0 to Count - 1 do
          if Items[I].Caption = 'Group By Box' then
          begin
            Items[I].Enabled := False;
            System.Break;
          end
    end;===========================================================================得到选中记录的值1) View.DataController.DataModeController.GridMode = False时  RecIdx := View.Controller.SelectedRecords[i].RecordIndex;
      ColIdx := View.DataController.GetItemByFieldName(AFieldName).Index;
      OutputVal := View.DataController.Values[RecIdx, ColIdx];  //RecID := View.DataController.GetRecordId(RecIdx);
      //OutputVal := ADataSet.Lookup(View.DataController.KeyFieldNames, RecID, AFieldName);2) View.DataController.DataModeController.GridMode = True时
      Bkm := View.DataController.GetSelectedBook(ASelectedRecordIndex);
      if ADataSet.BookValid(TBook(Bkm)) then
      begin
        ADataSet.Book := TBook(Bkm);
        OutputVal := ADataSet.FieldByName(AFieldName).Value;
      end;  View.BeginUpdate;
      View.DataController.BeginLocate;
      try
        // make changes here…
      finally
        View.DataController.EndLocate;
        View.EndUpdate;
      end;=============================================================在GridMode禁用内置的右键Footer菜单uses cxGridStdPopupMenu;procedure cxGridPopupMenuOnPopup(...)
    begin
      if (ASenderMenu is TcxGridStdFooterMenu) and
          <GridView>.DataController.DataModeController.GridMode then
        AllowPopup := False;
    end;==============================================================主从表任何时候只能展开一个组procedure TForm1.ADetailDataControllerCollapsing(
      ADataController: TcxCustomDataController; ARecordIndex: Integer;
      var AAllow: Boolean);
    var
      I: Integer;
      C: Integer;
    begin
      AAllow := False;
      C := 0;
      for I := 0 to ADataController.RecordCount - 1 do
      begin
        if ADataController.GetDetailExpanding(I) then
          Inc(C);
        if C > 1 then
          AAllow := True;
       end;
    end;procedure TForm1.ADetailDataControllerExpanding(
      ADataController: TcxCustomDataController; ARecordIndex: Integer;
      var AAllow: Boolean);
    begin
      ADataController.CollapseDetails;
    end;procedure TForm1.FormCreate(Sender: TObject);
    begin
      cxGrid1DBTableView1.DataController.OnDetailExpanding := ADetailDataControllerExpanding;
      cxGrid1DBTableView1.DataController.OnDetailCollapsing := ADetailDataControllerCollapsing;
    end;=================================================================动态创建层次(Level)和视图(View)var  
      Grid: TcxGrid;  
      Level: TcxGridLevel;  
      View: TcxGridDBTableView;  
    begin
      // Creates a Grid instance
      Grid := TcxGrid.Create(SomeOwner);  
      Grid.Parent := SomeParent;  
      // Creates a Level
      Level := Grid.Levels.Add;  
      Level.Name := 'SomeLevelName';
      // Creates a View
      View := Grid.CreateView(TcxGridDBTableView) as TcxGridDBTableView;  
      View.Name := 'SomeViewName';
      // … and binds it to the Level
      Level.GridView := View;  
      // Hooks up the View to the data
      View.DataController.DataSource := SomeDataSource;  
      // … and creates all columns
      View.DataController.CreateAllItems;  
    end; 
      

  21.   

    ======================================================================获得Group Footer合计行对应的记录procedure TForm1.cxGrid1DBTableView1CustomDrawFooterCell(
      Sender: TcxGridTableView; ACanvas: TcxCanvas;
      AViewInfo: TcxGridColumnHeaderViewInfo; var ADone: Boolean);
    var
      ALevel, ADataGroupIndex: Integer;
      AGridRecord, AGroupRecord: TcxCustomGridRecord;
    begin
      if AViewInfo is TcxGridRowFooterCellViewInfo and   // Row footer
         (TcxGridDBColumn(AViewInfo.Column).DataBinding.FieldName = 'Area') then  // Area column
        begin
          AGridRecord := TcxGridRowFooterCellViewInfo(AViewInfo).GridRecord;
          ALevel := TcxGridRowFooterCellViewInfo(AViewInfo).Container.GroupLevel;
          ADataGroupIndex := Sender.DataController.Groups.DataGroupIndexByRowIndex[AGridRecord.Index];
          if ADataGroupIndex <> -1 then
          begin
            AGroupRecord := AGridRecord;
            while AGroupRecord.Level <> ALevel do
              AGroupRecord := AGroupRecord.ParentRecord;
            AViewInfo.Text := AGroupRecord.DisplayTexts[0];
          end;
        end;
    end;===========================================================================访问过滤之后的记录var
      I: Integer;
    begin
      Memo1.Lines.Clear;
      with cxGrid1DBTableView1.DataController do
        for I := 0 to FilteredRecordCount - 1 do
          Memo1.Lines.Add(DisplayTexts[FilteredRecordIndex[I], 0]);
    end;============================================================================获得单元的FontcxGrid1DBTableView1.ViewInfo.RecordsViewInfo.Items[1].GetCellViewInfoByItem(
      cxGrid1DBTableView1Company).EditViewInfo.Font;============================================================================根据Level名称找到Level对象function GetLevelByName(AGrid: TcxGrid; ALevelName: string): TcxGridLevel;  function LoopThroughLevels(ALevel: TcxGridLevel; ALevelName: string): TcxGridLevel;
      var
        I: Integer;
      begin
        Result := nil;
        for I := 0 to ALevel.Count - 1 do
        begin
          if ALevel[I].Name = ALevelName then
          begin
            Result := ALevel[I];
            Exit;
          end;
          if ALevel[I].Count > 0 then
          begin
            Result := LoopThroughLevels(ALevel[I], ALevelName);
            if Result <> nil then
              Exit;
          end;
        end;
      end;var
      I: Integer;
    begin
      Result := nil;
      for I := 0 to AGrid.Levels.Count - 1 do
      begin
        if AGrid.Levels[I].Name = ALevelName then
        begin
          Result := AGrid.Levels[I];
          Exit;
        end;
        if AGrid.Levels[I].Count > 0 then
        begin
          Result := LoopThroughLevels(AGrid.Levels[I], ALevelName);
          if Result <> nil then
            Exit;
        end;
      end;
    end;============================================================================指定Filter Builder打开/保存过滤文件的默认路径uses
      ..., cxFilterControlDialog;procedure TForm.GridView1FilterControlDialogShow(
      Sender: TObject);
    begin
      TfmFilterControlDialog(Sender).OpenDialog.InitialDir := 'D:\'
    end; ============================================================================保存/恢复带汇总行的布局<TableView>.StoreToIniFile('c:\Grid.ini', True, [gsoUseSummary]); 
    <GridView>.RestoreFromIniFile(<inifilename>,True,False {or True, optional},[gsoUseSummary]);============================================================================取消过滤时移到第一行uses
      cxCustomData;procedure TYour_Form.AViewDataControllerFilterChanged(Sender: TObject);
    var
      Filter: TcxDataFilterCriteria;
    begin
      with Sender as TcxDataFilterCriteria do
        if IsEmpty then
          DataController.FocusedRowIndex := 0;
    end;=============================================================================排序后移到第一行可以设置DataController.Options.FocusTopRowAfterSorting := True,也可以使用如下的代码:uses
      cxCustomData;procedure TYour_Form.Your_ViewDataControllerSortingChanged(Sender: TObject);
    begin
      TcxCustomDataController(Sender).FocusedRowIndex := 0;
    end;==============================================================================判断当前行是否第一行或最后一行可以使用DataController的IsBOF, IsEOF方法,或者:
    <AView>.Controller.Controller.FocusedRow.IsFirst
    <AView>.Controller.Controller.FocusedRow.IsLast==============================================================================根据指定值查找记录DataController提供了好几个方法来得到指定值对应的RecordIndex
    对于Bound View可以使用FindRecordIndexByKeyValue方法===============================================================================编辑和显示Blob字段该字段的Properties设置为BlobEdit,并将BlobPaintStyle 属性设为 bpsText===============================================================================得到可见行数<View>.ViewInfo.VisibleRecordCount===============================================================================保存后的行设置为当前行const
      CM_SETFOCUSEDRECORD = WM_USER + 1002;type
      TForm1 = class(TForm)
        cxGrid1DBTableView1: TcxGridDBTableView;
        cxGrid1Level1: TcxGridLevel;
        cxGrid1: TcxGrid;
        dxMemData1: TdxMemData;
        dxMemData1Field1: TStringField;
        dxMemData1Field2: TIntegerField;
        DataSource1: TDataSource;
        cxGrid1DBTableView1RecId: TcxGridDBColumn;
        cxGrid1DBTableView1Field1: TcxGridDBColumn;
        cxGrid1DBTableView1Field2: TcxGridDBColumn;
        Timer1: TTimer;
        CheckBox1: TCheckBox;
        procedure Timer1Timer(Sender: TObject);
        procedure dxMemData1AfterPost(DataSet: TDataSet);
        procedure CheckBox1Click(Sender: TObject);
      private
        procedure CMSetFocusedRecord(var Msg: TMessage); message CM_SETFOCUSEDRECORD;
      public
        { Public declarations }
      end;var
      Form1: TForm1;
      FocusedIdx: Integer;
    implementation{$R *.dfm}procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      dxMemData1.AppendRecord(['', IntToStr(Random(1000)), Random(1000)]);
    end;procedure TForm1.dxMemData1AfterPost(DataSet: TDataSet);
    begin
      PostMessage(Handle, CM_SETFOCUSEDRECORD, Integer(cxGrid1DBTableView1), MakeLParam(cxGrid1DBTableView1.Controller.FocusedRowIndex, cxGrid1DBTableView1.Controller.TopRowIndex));
    end;procedure TForm1.CMSetFocusedRecord(var Msg: TMessage);
    begin
      TcxGridDBTableView(msg.WParam).Controller.FocusedRowIndex := Msg.LParamLo;
      TcxGridDBTableView(msg.WParam).Controller.TopRowIndex := Msg.LParamHi;
    end;procedure TForm1.CheckBox1Click(Sender: TObject);
    begin
      Timer1.Enabled := TCheckBox(Sender).Checked;
    end;end.=================================================================================删除记录并获得焦点procedure TForm1.BtnDeleteClick(Sender: TObject);
    var
      FocusedRow, TopRow: Integer;
      View: TcxGridTableView;
      DataController: TcxGridDataController;
    begin
      View := cxGrid1.FocusedView as TcxGridTableView;
      DataController := View.DataController;  // Remember the top row (the vertical scrollbar position)
      TopRow := View.Controller.TopRowIndex;
      // Remember the focused row(!) index
      FocusedRow := DataController.FocusedRowIndex;  DataController.DeleteFocused;  // After deletion the same row must be focused,
      // although it will correspond to a different data record
      DataController.FocusedRowIndex := FocusedRow;
      // Restore the top row
      View.Controller.TopRowIndex := TopRow;
    end;