delphi cxgrid记录一些网上都不一定能找到的资料
主从表的问题.
效果图大概如下图所示,它能体现出主表里每一条记录的入仓记录,左边的加减号可以展示与隐藏从表.
结构设计如上图右下角所示,做两个level,和两个DB table,从结构上可以很晰的看到,TV报废池是主表,TV查询是从表.
我们需要做两组数据集,SQL内容按业务自己看着写.
然后是主从表的关联设置,这方面网上资料有很多,但都没有配图,所以我打算细讲这部分内容.
主表设置: 选中TV报废池,在左边属性面板里按如下设置.这里只要设置keyFieldNames这个属性就可以了.需要注意的是,这里要设置成主表里具有唯一性的字段,否则IDE可能会崩溃,比如我的10.3.3
然后是从表设置.选中TV查询,按下图设置:,这里有一点要注意,主表与从表的关联字段要一致,意思是从表会以主表关联的这个字段值,作为筛选条件返回数据.从表如果没有具有唯一特性的字段,keyFieldNames可以留空.
最后一步,也很关键,很多人按上面的内容设置好后,结果发现只返回了一条数据,或者根本没有数据展现出来.
先说后面一种吧,建议先看一下数据库里有没有符合条件的数据吧,我TMD当时就做了一回SB..
如果数据库里明明有好多条记录,结果只返回了一条,说明你SQL写得不对.解决的方案是在从表的SQL语句后面加个order by 关联字段.我们上面设置的关联字段是"物料代码",所以下图就是按这个字段排序的.
这样就算是设置好一个主从表了.
然后我们来看看怎么取从表里的数据,还有从表的RecordCount
看看下面这一句:
DetailRecCount:=cxGrid1DBTableView1.ViewData.Rows[i].AsMasterDataRow.ActiveDetailGridView.DataController.RecordCount;
没错,这TMD就是用来获取从表记录数的,谁能想到它隐藏得这么深!我当时在网上找了半天资料没找到,在群里问也没人回,总算是知道原因了--实在是老司机也不一定知道啊!
然后是取从表的数据:
V:= TcxGridDBTableView(cxGrid1DBTableView1.ViewData.Rows[i].AsMasterDataRow.ActiveDetailGridView).ViewData.Rows[j].Values[k];
吖吖个呸!
下面是效果图和完整代码
procedure TForm1.Button1Click(Sender: TObject); var i,j,k,DetailRecCount:integer; s:string; v:Variant; begin memo1.Clear; for i:=0 to cxGrid1DBTableView1.DataController.RowCount-1 do begin DetailRecCount:=cxGrid1DBTableView1.ViewData.Rows[i].AsMasterDataRow.ActiveDetailGridView.DataController.RecordCount; memo1.Lines.Append(''); s:=''; for k:=0 to 2 do begin v:=cxGrid1DBTableView1.ViewData.Rows[i].Values[k]; if VarIsNull(v) then s:=s+'; ' else s:=s+string(v)+'; '; end; memo1.Lines.Append(s); for j:=0 to DetailRecCount-1 do begin s:=' '; for k:=0 to 3 do begin if k=1 then continue; with TcxGridDBTableView(cxGrid1DBTableView1.ViewData.Rows[i].AsMasterDataRow.ActiveDetailGridView) do v:=ViewData.Rows[j].Values[k]; if VarIsNull(v) then s:=s+'; ' else s:=s+string(v)+'; '; end; memo1.Lines.Append(s); end; memo1.Lines.Append(' 从表共 '+inttostr(DetailRecCount)+' 笔记录.'); end; end; end.
然后,我又在想,能不能实现只有从表里面有数据时,才显示从表,否则忽略用户对 + 号的点击呢?
需要用到 DataController 下的 OnDetailExpanding事件
//ARecordIndex: 主表当前操作的行,AAllow 是否显示从表
procedure T申领申购报废清单.TV报废池DataControllerDetailExpanding(ADataController: TcxCustomDataController; ARecordIndex: Integer; var AAllow: Boolean); var n: integer; //从表记录数 begin n := TV报废池.ViewData.Rows[ARecordIndex].AsMasterDataRow.ActiveDetailGridView.DataController.RecordCount; AAllow := n > 0; //如果从表记录数大于0,则展开从表,否则不展开 end;
接下来,我又想通过从表的单元格双击事件,来实现更新主表内容,并收起从表
//更新供应商和用途到报废池 procedure T申领申购报废清单.TV查询CellDblClick(Sender: TcxCustomGridTableView; ACellViewInfo: TcxGridTableDataCellViewInfo; AButton: TMouseButton; AShift: TShiftState; var AHandled: Boolean); var recordid, 供应商ID, 用途: string; i, iRow, iCol1, iCol2: integer; begin iRow := ACellViewInfo.RecordViewInfo.Index; iCol1 := Col用途.Index; iCol2 := Col供应商ID.Index; recordid := DM.fdq报废池.FieldByName('recordid').AsString; i := TV报废池.Controller.FocusedRowIndex; 用途 := TcxGridDBTableView(TV报废池.ViewData.Rows[i].AsMasterDataRow.ActiveDetailGridView).ViewData.Rows [iRow].Values[iCol1]; 供应商ID := TcxGridDBTableView(TV报废池.ViewData.Rows[i].AsMasterDataRow.ActiveDetailGridView).ViewData.Rows [iRow].Values[iCol2]; with DM.FD公共查询 do begin close; SQL.Text := 'update 报废池 set 供应商=' + 供应商ID + ',用途=' + 用途.QuotedString + ' where recordid=' + recordid; ExecSQL; end; //更新后,更新数据集 DM.FDQ报废池.Refresh; //收起从表 TV报废池.ViewData.Collapse(True); //收起当前从表 // TV报废池.ViewData.Rows[TV报废池.DataController.FocusedRowIndex].Collapse(True); end;
其他收起与展开的代码如下,使用时 tvQuery 对应的是主表,这一点必须要理解.
1:展开所有行 tvQuery.ViewData.Expand(True); 2:收起所有行 tvQuery.ViewData.Collapse(True); 3:展开当前行 tvQuery.ViewData.Rows[tvQuery.DataController.FocusedRowIndex].Expand(True); 4:收起当前行 tvQuery.ViewData.Rows[tvQuery.DataController.FocusedRowIndex].Collapse(True);
2023-01-20追加
如何设置与访问 cxgrid 中列的 Properties 属性.
从表Column1.PropertiesClass :=TCXCurrencyEditProperties ; //动态设置属性
TCXCurrencyEditProperties(从表Column1.Properties).displayFormat := '0.##'; //设置显示样式
TcxSpinEditProperties: 是指你给这一列设置的 Properties 类型,其他类型有:
TcxTextEditProperties;
TcxDateEditProperties;
TcxCalcEditProperties;
TcxCheckboxProperties;
...其他的你们自己照着画就行了,一般都能点出来
访问(取属性值),和上面的差不多
ShowMessage(TCXCurrencyEditProperties(从表Column1.Properties).displayFormat);
2023-02-07追加
cxGrid删除与创建所有字段
IcxCustomGridDataController(cxGrid1DBTableView1.DataController).DeleteAllItems; //CXGRID删除所有字段 IcxCustomGridDataController(cxGrid1DBTableView1.DataController).CreateAllItems(False); //CXGRID创建所有字段
2024-04-03追加
cxgrid取得指定字段排在第几列.感谢 [狼行卫野] 大佬的指点
AText := cxGrid1DBTableView1.GetColumnByFieldName('物料名称').Index.ToString //物理位置,不管是否有隐藏字段 AText := cxGrid1DBTableView1.GetColumnByFieldName('物料名称').visibleIndex.ToString //视觉位置,隐藏的列将会被忽略不计