注册 登录
编程论坛 Delphi论坛

FireDac下DBGrid标题栏点击排序功能

cz012273 发布于 2022-06-03 08:48, 1231 次点击
参考网上给出的两种方法,一种是通用的(方法一),用点击column找到对应的query对象,然后替换SQL语句,经试验运行成功,唯一缺点是点击后字段标题不发生变化(看不出升降序);另一种(方法二)是根据column.index替换字段标题(加上下箭头)后再加入排序子句(但试验后发现column.index值始终为-1,运行时出现下标越界错误,原因待查)。(运行环境为:Win10 DelphiXE10.4.2)
注:程序内注释均按个人理解添加,可能有误!

附代码:

程序代码:

procedure TForm1.DBGrid1TitleClick(Column: TColumn); //方法一
var
  SqlStr,myFieldName,TempStr: string;
  OrderPos: integer;
  SavedParams: TParams;
begin
  if not (Column.Field.FieldKind in [fkData,fkLookup]) then exit;
  //如果字段类型不属于物理字段或查询字段则退出
  if Column.Field.FieldKind =fkData then
    myFieldName := UpperCase(Column.Field.FieldName)  //如为物理字段,取大写字段名
  else
    myFieldName := UpperCase(Column.Field.KeyFields);   //如为查询字段,取大写主键名

  while Pos(myFieldName,';')<>0 do   //如果名称中包含分号
    myFieldName := copy(myFieldName,1,Pos(myFieldName,';')-1)
                  + ',' + copy(myFieldName,Pos(myFieldName,';')+1,100);  //把分号变逗号
  with TFDQuery(TDBGrid(Column.Grid).DataSource.DataSet) do  //根据column获取FDQuery对象
  begin
    SqlStr := UpperCase(Sql.Text);   //SQL语句字符串大写
//  if pos(myFieldName,SqlStr)=0 then exit;   //如果SQL语句中不存在所选字段名,则退出
    if ParamCount>0 then   //如果运行过程时包含参数
    begin
      SavedParams := TParams.Create;   //创建保存参数变量
      SavedParams.Assign(Params);   //连接参数
    end;
    OrderPos := pos('ORDER',SqlStr);   //获取'ORDER'串在SQL语句中的起始位置
    if (OrderPos=0) or
      (pos(myFieldName,copy(SqlStr,OrderPos,100))=0) then   //如不存在ORDER或ORDER子句中不包含所选字段
      TempStr := ' Order By ' + myFieldName + ' Asc'   //生成按照所选字段升序排列的ORDER子句
    else if pos('ASC',SqlStr)=0 then   //如果ORDER子句中有所选字段但不包含升序标志
      TempStr := ' Order By ' + myFieldName + ' Asc'   //生成按所选字段升序排列的ORDER子句
    else   //如果ORDER子句中有所选字段且包含升序标志
      TempStr := ' Order By ' + myFieldName + ' Desc';   //生成按所选字段降序排列的ORDER子句
    if OrderPos<>0 then SqlStr := Copy(SqlStr,1,OrderPos-1);   //如果存在ORDER子句,提取ORDER子句之前的SQL语句内容
    SqlStr := SqlStr + TempStr;   //将其与新生成的ORDER子句连接
    Active := False;   //锁定QUERY状态
    Sql.Clear;   //清除SQL内容
    Sql.Text := SqlStr;   //更新SQL内容
    if ParamCount>0 then   //如果运行过程时包含参数
    begin
      Params.Assign(SavedParams);   //提取保存的参数变量
      SavedParams.Free;   //释放参数变量
    end;
    Prepare;   //将带参数的SQL语句传给数据库引擎
    Open;   //打开查询
  end;
end;

procedure TForm1.DBGrid1TitleClick(Column: TColumn);  //方法二
var

 temp, title: string;

 lastcolumn,icount:integer;   //应设为单元内全局变量,记录已点击状态和添加SQL排序子句的位置?
begin

 temp := Column.FieldName;

 lastcolumn:=DBGrid1.DataSource.DataSet.FieldCount-1;

 icount:=1;

 FDQuery1.Close;   //关闭查询

 if Column.Index <> lastcolumn then    // 如果不是已点击列

 begin
   if (Pos('', DBGrid1.Columns[LastColumn].Title.Caption) > 0)
   or (Pos('', DBGrid1.Columns[LastColumn].Title.Caption) > 0) then
     DBGrid1.Columns[LastColumn].Title.Caption :=
     Copy(DBGrid1.Columns[LastColumn].Title.Caption, 3,
     Length(DBGrid1.Columns[LastColumn].Title.Caption) - 2);  //如果字段名中包含上下箭头,去掉字段名前两个字符
   FDQuery1.Sql[icount] := 'order by ' + temp + ' asc';  //查询SQL中添加按当前字段排序
   DBGrid1.Columns[Column.Index].Title.Caption :=
    '' + DBGrid1.Columns[Column.Index].Title.Caption;  //字段名前添加上箭头
   lastcolumn := column.Index;  //当前列加入已点击

 end

 else

 begin
   LastColumn := Column.Index;   //当前列加入已点击
   title := DBGrid1.Columns[LastColumn].Title.Caption;  //标题等于字段名
   if Pos('', title) > 0 then  //如果标题中包含上箭头
   begin
     FDQuery1.Sql[icount] := 'order by ' + temp + ' desc';
     Delete(title, 1, 2); //删除标题中前两个字符
     DBGrid1.Columns[LastColumn].Title.Caption := '' + title;   //字段名前添加下箭头
   end
   else if Pos('', title) > 0 then  //如果标题中包含下箭头
   begin
     FDQuery1.Sql[icount] := 'order by ' + temp + ' asc';
     Delete(title, 1, 2);    //删除标题中前两个字符
     DBGrid1.Columns[LastColumn].Title.Caption := '' + title;   //字段名前添加上箭头
   end
   else    //如果标题中不包含箭头
   begin
     FDQuery1.Sql[icount] := 'order by ' + temp + ' asc';    //查询SQL中添加按当前字段排序?
     DBGrid1.Columns[LastColumn].Title.Caption := '' + title;   //字段名前添加上箭头
   end;

 end;

 FDQuery1.Open;   //打开查询
end;


综合以上两种方法的优点,经过思考修改后,最终采用的方案(方法三):

程序代码:

procedure TDM1.DBGridSort(DBGrid:TDBGrid; Column: TColumn);  //DBgrid点击标题栏排序(方法三)
var
  SqlStr,myFieldName,TempStr,TitleStr: string;
  i,OrderPos,colnum: integer;
  SavedParams: TParams;
begin

  if not (Column.Field.FieldKind in [fkData,fkLookup]) then exit;
  //如果字段类型不属于物理字段或查询字段则退出
  if Column.Field.FieldKind =fkData then
    myFieldName := UpperCase(Column.Field.FieldName)  //如为物理字段,取字段名大写
  else
    myFieldName := UpperCase(Column.Field.KeyFields);   //如为查询字段,取主键名大写

  while Pos(myFieldName,';')<>0 do   //如果名称中包含分号
    myFieldName := copy(myFieldName,1,Pos(myFieldName,';')-1)
                  + ',' + copy(myFieldName,Pos(myFieldName,';')+1,100);  //把分号变逗号
  with TFDQuery(DBGrid.DataSource.DataSet) do
  begin
    colnum:=column.index;
    if (Pos('', column.Title.Caption) > 0)
   or (Pos('', column.Title.Caption) > 0) then
     column.Title.Caption :=
     Copy(column.Title.Caption, 3,
     Length(column.Title.Caption) - 2);  //如果字段名中包含上下箭头,去掉字段名前两个字符
    TitleStr := Column.Title.Caption;   //取字段标题
    SqlStr := UpperCase(Sql.Text);   //SQL语句字符串大写

    if ParamCount>0 then   //如果运行过程时包含参数
      begin
        SavedParams := TParams.Create;   //创建保存参数变量
        SavedParams.Assign(Params);   //连接参数
      end
    else
      savedparams := nil;

    OrderPos := pos('ORDER',SqlStr);   //获取'ORDER'串在SQL语句中的起始位置
    if (OrderPos=0) or
      (pos(myFieldName,copy(SqlStr,OrderPos,100))=0) then   //如不存在ORDER或ORDER子句中不包含所选字段
      begin
        TempStr := ' Order By ' + myFieldName + ' Asc';   //生成按照所选字段升序排列的ORDER子句
        TitleStr := '' + TitleStr;
      end
    else if pos('ASC',SqlStr)=0 then   //如果ORDER子句中有所选字段但不包含升序标志
      begin
        TempStr := ' Order By ' + myFieldName + ' Asc';   //生成按照所选字段升序排列的ORDER子句
        TitleStr := '' + TitleStr;
      end
    else   //如果ORDER子句中有所选字段且包含升序标志
      begin
        TempStr := ' Order By ' + myFieldName + ' Desc';   //生成按所选字段降序排列的ORDER子句
        TitleStr := '' + TitleStr;
      end;
    if OrderPos<>0 then SqlStr := Copy(SqlStr,1,OrderPos-1);   //如果存在ORDER子句,提取ORDER子句之前的SQL语句内容
    SqlStr := SqlStr + TempStr;   //将其与新生成的ORDER子句连接
    Active := False;   //锁定QUERY状态
    Sql.Clear;   //清除SQL内容
    Sql.Text := SqlStr;   //更新SQL内容

    if ParamCount>0 then   //如果运行过程时包含参数
    begin
      Params.Assign(SavedParams);   //提取保存的参数变量
      SavedParams.Free;   //释放参数变量
    end;
    Prepare;   //将带参数的SQL语句传给数据库引擎

    if Not Active then Open ;   //打开查询,按点击字段排序

    DBGrid.Columns[colnum].Title.Caption := TitleStr;   //显示排序修改后的字段标题

  end;
end;

//以上过程放入数据模块DM1中作为公用过程,其它单元引用后即可使用,调用方法如下:

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
  DM1.DBGridSort(DBGrid1,Column);
end;



[此贴子已经被作者于2022-6-4 13:28编辑过]

1 回复
#2
sssooosss2022-06-13 19:34
共同学习
1