delphi 在cxgrid表中设置下拉菜单,以及多表查询时,如何更新数据(TFDUpdateSQL)

我写的博客内容,都是在实际生产中遇到的问题,针对性很强,记录下来有两个目的,一是当成笔记,二是丰富Delphi的网上资料,让遇到相同问题的朋友,少走弯路.

 

如下图,我希望所属仓库,供应商,物料用途这三个字段,我希望做成下拉菜单的形式给用户选择,

但因为这个表格是多表联合查询得出来的结果,如果直接交给cxgrid自动处理的话,会产生错误

 

 

 

首先,先来实现下拉菜单的效果.我们以物料用途字段为例进行说明.

1.选中 物料用途 字段,在属性面板中设置properties=LookupComboBox,此时properties属性的左边会多出来一个大于号,像这样

 

2.点开这个大于号,设置ListSource为一个我们事先准备好的数据集.

3.在ListColumns中设置下拉菜单的显示列,可以同时显示多列,同时要设置KeyFieldNames属性,比如你在ListColumns中设置了 用途与单位 这两列,那么对应的,你要在KeyFieldNames中设置为: 用途;单位 ,列与列之间用分号隔开,这里是可以手输的.如果KeyFieldNames与ListColumns不对应,就会出错.

 

 

但切记要设置好列宽.下面几个参数要留意一下,它们都在properties属性中设置:

 

 

DropDownAutoSize: 使下拉菜单的宽度等于屏幕的宽度.除非你要显示的列非常多,否则不勾选.效果如下

 

DropDownRows:下拉菜单中最多显示多少行,这里很好理解,就不出图了

DropDownSizeable:使下拉菜单可以通过右下角进行拉伸,改变下拉菜单的大小,同时在左下角提供一个关闭下拉菜单的按钮

 

 

 说完了下拉菜单设置,现在来说说怎么实现更新.这里先声明,我的方法可能并不是最优解,但能解决实际问题,欢迎大佬指点

这里要用到properties当中的两个事件OnInitPopup事件与OnValidate事件

 

OnInitPopup事件是在下拉菜单弹出之前,更新它的用途,因为每一行的数据可能不同,用途要通过查询才能返回对应的历史用途.

另外因为我使用的是Access数据库,SQL语句请按自己的对应的数据库语言来写

procedure T申领申购报废清单.T1用途PropertiesInitPopup(Sender: TObject);
var
  codeText: string;  
begin
  codeText := DM.FDQ报废池.FieldByName('物料代码').AsString;  //取得当前行的物料代码,然后再以此向数据库查询它的历史用途
  with DM.FDQ用途 do  //下拉菜单关联着这个查询的数据集,所以我们只要更新这个查询就可以了.
  begin
    close;
    SQL.Text := 'select distinct 用途 from(SELECT 用途 FROM 采购入仓记录 WHERE 物料代码=' + codeText.QuotedString
      + ' ORDER BY 入仓日期 DESC)';
    Open();
  end;
end;

OnValidate事件:当焦点离开当前单元格时,触发此事件.同时会触发cxgrid的更新事件,但因为数据表是联合查询得来的,cxgrid会向一个不存在的表进行更新操作,所以导致出错

procedure T申领申购报废清单.T1用途PropertiesValidate(Sender: TObject; var DisplayValue: Variant; var ErrorText:
  TCaption; var Error: Boolean);
var
  YT: string;
begin
  YT := DisplayValue; //当前值,也就是用户点选的值
//这里你完全可以再次判断YT的数据是否合法,再决定更新与否
TV报废池.DataController.Cancel; //取消更新,避免出错. //重新定义更新内容,因为是临时的,所以用了一个公共的查询来执行更新操作 with DM.FD公共查询 do begin close; SQL.Text := 'update 报废池 set 用途=' + YT.QuotedString + ' where RecordID=' + dm.FDQ报废池.FieldByName('RecordID').asstring; ExecSQL; end; dm.FDQ报废池.Refresh; //更新数据集 end;

 坑:

 

 

2025-11-19 更新.关于涉及到多表个数据表的联合查询,如何更新数据的问题.最优解是使用TFDUpdateSQL控件.使用方法如下:

1.假设联合查询为FDQuery1,TFDUpdateSQL控件为FDUpdateSQL1,首先需要把它们关联起来.请设置FDQuery1.UpdateObject属性为FDUpdateSQL1

2.设置FDUpdateSQL1的SQL语句.你可以在属性中设置(推荐),也可以在代码中设置

image

 

 在代码是设置: 

procedure TMaterialInfomation.SetupUpdateSQL;
begin
  with FData.FDUpdateSQL1 do
  begin
    // 设置修改语句
    ModifySQL.Text := 'UPDATE 物料信息 SET 物料名称 = :物料名称,规格型号 = :规格型号, 材质 = :材质,'
      + '客户料号 = :客户料号,启用状态 = :启用状态, 备注 = :备注,'
      + '助记码=:助记码,储位=:储位,单重 = :单重, 权重 = :权重 WHERE 物料ID = :物料ID';

    // 设置插入语句(如果需要)
    InsertSQL.Text := 'INSERT INTO 物料信息 (物料名称, 规格型号, 材质, 客户料号, 启用状态, 备注, '
      + '默认仓库, 助记码, 储位, 单位, 单重, 权重, 物料ID) '
      + 'VALUES (:物料名称, :规格型号, :材质, :客户料号, :启用状态, :备注, '
      + ':默认仓库, :助记码, :储位, :单位, :单重, :权重, :物料ID)';
    // 设置删除语句(如果需要)
    DeleteSQL.Text := 'DELETE FROM 物料信息 WHERE 物料ID = :物料ID';
  end;
end;

3.使用方法.如果是在代码中设置的,需要在POST前调用 SetupUpdateSQL 过程,比如:

if FDQuery1.State in [dsEdit,dsInsert] then
    begin
      SetupUpdateSQL;
      FDQuery1.Post;
    end;

 

posted @ 2023-01-16 12:53  一曲轻扬  阅读(1199)  评论(0)    收藏  举报