FireDac下DBGrid标题栏点击排序功能
参考网上给出的两种方法,一种是通用的(方法一),用点击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编辑过]