首页 > 其他分享 >bufDataSet排序

bufDataSet排序

时间:2024-04-13 09:11:38浏览次数:14  
标签:begin end Fields DataSet bufDataSet IndexDefs IndexName 排序

https://wiki.lazarus.freepascal.org/How_to_write_in-memory_database_applications_in_Lazarus/FPC

 

Sorting DBGrid on TitleClick event for TBufDataSet
If you wish to enable consecutive ascending and descending sorting of a DBGrid showing some data from TBufDataSet, you could use the following method:

Uses
BufDataset, typinfo;

function SortBufDataSet(DataSet: TBufDataSet;const FieldName: String): Boolean;
var
i: Integer;
IndexDefs: TIndexDefs;
IndexName: String;
IndexOptions: TIndexOptions;
Field: TField;
begin
Result := False;
Field := DataSet.Fields.FindField(FieldName);
//If invalid field name, exit.
if Field = nil then Exit;
//if invalid field type, exit.
if {(Field is TObjectField) or} (Field is TBlobField) or
{(Field is TAggregateField) or} (Field is TVariantField)
or (Field is TBinaryField) then Exit;
//Get IndexDefs and IndexName using RTTI
if IsPublishedProp(DataSet, 'IndexDefs') then
IndexDefs := GetObjectProp(DataSet, 'IndexDefs') as TIndexDefs
else
Exit;
if IsPublishedProp(DataSet, 'IndexName') then
IndexName := GetStrProp(DataSet, 'IndexName')
else
Exit;
//Ensure IndexDefs is up-to-date
IndexDefs.Updated:=false; {<<<<---This line is critical as IndexDefs.Update will do nothing on the next sort if it's already true}
IndexDefs.Update;
//If an ascending index is already in use,
//switch to a descending index
if IndexName = FieldName + '__IdxA'
then
begin
IndexName := FieldName + '__IdxD';
IndexOptions := [ixDescending];
end
else
begin
IndexName := FieldName + '__IdxA';
IndexOptions := [];
end;
//Look for existing index
for i := 0 to Pred(IndexDefs.Count) do
begin
if IndexDefs[i].Name = IndexName then
begin
Result := True;
Break
end; //if
end; // for
//If existing index not found, create one
if not Result then
begin
if IndexName=FieldName + '__IdxD' then
DataSet.AddIndex(IndexName, FieldName, IndexOptions, FieldName)
else
DataSet.AddIndex(IndexName, FieldName, IndexOptions);
Result := True;
end; // if not
//Set the index
SetStrProp(DataSet, 'IndexName', IndexName);
end;
So, you can call this function from a DBGrid in this way:

procedure TFormMain.DBGridProductsTitleClick(Column: TColumn);
begin
SortBufDataSet(Products, Column.FieldName);
end;

Sorting multiple columns in grid
I have written TDBGridHelper for sorting grid by multiple columns while holding shift key. Note MaxIndexesCount must be set quite large for TBufDataSet because there can be quite large combinations of possible sorting options. But I think people would not use more than 10 so setting it 100 should be teoretically Ok.

{ TDBGridHelper }

TDBGridHelper = class helper for TDBGrid
public const
cMaxColCOunt = 3;
private
procedure Interbal_MakeNames(Fields: TStrings; out FieldsList, DescFields: String);
procedure Internal_SetColumnsIcons(Fields: TStrings; AscIdx, DescIdx: Integer);
function Internal_IndexNameExists(IndexDefs: TIndexDefs; IndexName: String): Boolean;
public
procedure Sort(const FieldName: String; AscIdx: Integer = -1; DescIdx: Integer = -1);
procedure ClearSort;
end;

{ TDBGridHelper }

procedure TDBGridHelper.Interbal_MakeNames(Fields: TStrings; out FieldsList, DescFields: String);
var
FldList: TStringList;
DscList: TStringList;
FldDesc, FldName: String;
i: Integer;
begin
if Fields.Count = 0 then
begin
FieldsList := '';
DescFields := '';
Exit;
end;

FldList := TStringList.Create;
DscList := TStringList.Create;
try
FldList.Delimiter := ';';
DscList.Delimiter := ';';

for i := 0 to Fields.Count - 1 do
begin
Fields.GetNameValue(i, FldName, FldDesc);
FldList.Add(FldName);

if FldDesc = 'D' then
DscList.Add(FldName);
end;

FieldsList := FldList.DelimitedText;
DescFields := DscList.DelimitedText;
finally
FldList.Free;
DscList.Free;
end;
end;

procedure TDBGridHelper.Internal_SetColumnsIcons(Fields: TStrings; AscIdx, DescIdx: Integer);
var
i: Integer;
FldDesc: String;
begin
for i := 0 to Self.Columns.Count - 1 do
begin
FldDesc := Fields.Values[Self.Columns[i].Field.FieldName];

if FldDesc = 'A' then
Self.Columns[i].Title.ImageIndex := AscIdx
else
if FldDesc = 'D' then
Self.Columns[i].Title.ImageIndex := DescIdx
else
Self.Columns[i].Title.ImageIndex := -1
end;
end;

function TDBGridHelper.Internal_IndexNameExists(IndexDefs: TIndexDefs; IndexName: String): Boolean;
var
i: Integer;
begin
for i := 0 to IndexDefs.Count - 1 do
begin
if IndexDefs[i].Name = IndexName then
Exit(True)
end;

Result := False
end;

procedure TDBGridHelper.Sort(const FieldName: String; AscIdx: Integer;
DescIdx: Integer);
var
Field: TField;
DataSet: TBufDataset;
IndexDefs: TIndexDefs;
IndexName, Dir, DescFields, FieldsList: String;
Fields: TStringList;
begin
if not Assigned(DataSource.DataSet) or
not DataSource.DataSet.Active or
not (DataSource.DataSet is TBufDataset) then
Exit;
DataSet := DataSource.DataSet as TBufDataset;

Field := DataSet.FieldByName(FieldName);
if (Field is TBlobField) or (Field is TVariantField) or (Field is TBinaryField) then
Exit;

IndexDefs := DataSet.IndexDefs;
IndexName := DataSet.IndexName;

if not IndexDefs.Updated then
IndexDefs.Update;

Fields := TStringList.Create;
try
Fields.DelimitedText := IndexName;
Dir := Fields.Values[FieldName];

if Dir = 'A' then
Dir := 'D'
else
if Dir = 'D' then
Dir := 'A'
else
Dir := 'A';

//If shift is presed then add field to field list
if ssShift in GetKeyShiftState then
begin
Fields.Values[FieldName] := Dir;
//We do not add to sor any more field if total field count exids cMaxColCOunt
if Fields.Count > cMaxColCOunt then
Exit;
end
else
begin
Fields.Clear;
Fields.Values[FieldName] := Dir;
end;

IndexName := Fields.DelimitedText;
if not Internal_IndexNameExists(IndexDefs, IndexName) then
begin
Interbal_MakeNames(Fields, FieldsList, DescFields);
TBufDataset(DataSet).AddIndex(IndexName, FieldsList, [], DescFields, '');
end;

DataSet.IndexName := IndexName;
Internal_SetColumnsIcons(Fields, AscIdx, DescIdx)
finally
Fields.Free;
end;
end;

procedure TDBGridHelper.ClearSort;
var
DataSet: TBufDataset;
Fields: TStringList;
begin
if not Assigned(DataSource.DataSet) or
not DataSource.DataSet.Active or
not (DataSource.DataSet is TBufDataset) then
Exit;
DataSet := DataSource.DataSet as TBufDataset;

DataSet.IndexName := '';

Fields := TStringList.Create;
try
Internal_SetColumnsIcons(Fields, -1, -1)
finally
Fields.Free
end
end;
To use sorting you need to call helper methods in OnCellClick and onTitleClick. OnTitleClick - If you hold shift ads new column to sot list ore changes direction to selected column or just sorts one column OnCellClick - If you double click on cell[0, 0] grid clears its sorting

procedure TForm1.grdCountriesCellClick(Column: TColumn);
begin
if not Assigned(Column) then
grdCountries.ClearSort
end;

procedure TForm1.grdCountriesTitleClick(Column: TColumn);
begin
grdCountries.Sort(Column.Field.FieldName, 0, 1);
end;
If you have assigned TitleImageList then you can specify which image use for ascending and which for descending operations.

标签:begin,end,Fields,DataSet,bufDataSet,IndexDefs,IndexName,排序
From: https://www.cnblogs.com/0n355/p/18132496

相关文章

  • 常见的排序算法——冒泡排序(二)
    本文记述了冒泡排序微小改动的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想更少的比较可以节省一定的时间,此改动可以减少更小范围的比较。(把水平陈列的数组逆时针旋转90°后,有助于理解后续的内容。)将包含顶层以下的所有元素作为待排序范围......
  • 常见的排序算法——冒泡排序
    本文记述了冒泡排序的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想(把水平陈列的数组逆时针旋转90°后,有助于理解后续的内容。)将包含顶层以下的所有元素作为待排序范围,将该范围以上的所有元素作为已排序范围。通过一一比较相邻的两个元素,自......
  • Java stream sorted使用 Comparator 进行多字段排序
    摘要:介绍使用JavaStream流排序器Comparator对List集合进行多字段排序的方法,包括复杂实体对象多字段升降序混合排序方法。综述​ Java8的Stream使用了函数式编程模式,人如其名,它可以被用来对集合或数组进行链状流式的排序、过滤和统计等操作,从而让我们更方便的对集合或数组......
  • JZ25合并两个排序链表
    /***structListNode{* intval;* structListNode*next;* ListNode(intx):val(x),next(nullptr){}*};*/#include<cstddef>classSolution{public:/***代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*......
  • Java中Array.sort()的几种用法简明教程 (需要初始化要排序的对象)对 一个数组的所有元素
    Java中Array.sort()的几种用法简明教程(需要初始化要排序的对象)对一个数组的所有元素进行排序,并且是按从小到大的顺序Java中Array.sort()的几种用法简明教程(需要初始化要排序的对象)======================================================1、Arrays.sort(int[]a)......
  • 记录真实项目中遇到的bug--007:排序展示bug
    T07:排序展示bug:1.优先级:T22.前提条件:用户A打开日历3.预期结果:日历行程展示按照业务提供的sort顺序进行排序。4.实际结果:日历行程展示的时间段在9点之前的顺序不符合预期。5.缺陷跟踪:后端按照sort字段排序,更改为9点之前的时间段前面加0,例如原先的9:45,改为09:45,后达到预期......
  • 排序规则冲突问题解决
    --英文操作系统数据库恢复到中文版本操作系统的时候容易出现一下问题--无法解决equalto运算中"SQL_Latin1_General_CP1_CI_AS"和"Chinese_PRC_CI_AS"之间的排序规则冲突。--简单解决办法如下:指定排序规则COLLATESQL_Latin1_General_CP1_CI_AS或者Chinese_PRC_CI_AS......
  • el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能,利用@sort-cha
        写这篇博客的原因是前段时间做了一个数据列可变的表格,同时需要实现在网页中更新了数据列之后,能够对表格进行排序的需求。如果想要直接了解实现el-table的动态数据动态排序(列数据是通过计算获得,并且可以在页面中修改,在此基础上实现数据变化后实时更新)。请直接跳到......
  • 排序算法(c语言版)
    排序算法(c语言版)1、插入排序#include<stdio.h>//插入排序,升序voidinsertion_sort(intarr[],intlen){inti,j,key;for(i=1;i<len;i++){key=arr[i];//arr[i]为待插入的元素,保存在key中j=i-1;wh......
  • 记录一个springcloud-task-core.jar导致CommandLineRunner @order排序失效的问题
    项目中编写了几个CommandLineRunner,并且加上了spring的@order注解,期望在启动时会按顺序执行(从order的value小到大执行),但是实际使用发现排序不生效于是进行debug,CommandLineRunner类的排序是在SpringApplication.class的callRunners方法privatevoidcallRunners(ApplicationCon......