Delphi 10.4-按2个值对记录的动态数组进行排序

but5z9lq  于 2022-09-21  发布在  其他
关注(0)|答案(1)|浏览(160)

我正在用Delphi10.4编写一个程序,该程序将多个表从数据库读取到一个动态记录数组中。在初始数据加载期间,SQL查询已经按名称对值进行了排序。

然后,这些记录将显示在ListView的不同列下。我想让用户选择单击列,以便根据该列对值进行排序。到目前为止,一切都运行得很好。我有下面的当前代码,欢迎您指出我犯下的任何错误。

首先,我声明记录类型:

type
   TDDNS = record
     ID : Integer;      --the ID in the database
     Name  : String;    --the client name
     Alias : string;    --an alias for the client
     Domain : string;   --the DDNS address
     Login : String;    --DDNS login username
     Password: string;  --DDNS login password
     Renewed: TDate;    --Date DDNS account was renewed
     IsActive: Boolean; --Boolean if account is still active
   end;

其次,我创建了动态数组:

DDNSDetails : array of TDDNS;

然后将数据读入阵列。

由于显而易见的原因,登录和密码数据不会显示在ListView中。

对于排序,我使用以下代码:

procedure lvDDNSColumnClick(Sender: TObject;
  Column: TListColumn);
begin
  SortList(Column.Index);
  ReloadLV();
end;

procedure SortList(Col : Integer);
var
 i, j : Integer;
begin
  if Length(DDNSDetails) > 0 then
  begin
    for i :=  0 to Length(DDNSDetails)-1 do
    begin
      for j := i+1 to Length(DDNSDetails)-1 do
      begin
        if Col = 0 then //Name
        begin
          if UpperCase(DDNSDetails[i].Name) > UpperCase(DDNSDetails[j].Name) then
            Resort(i, j);
        end else
        if Col = 1 then //Alias
        begin
          if UpperCase(DDNSDetails[i].Alias) > UpperCase(DDNSDetails[j].Alias) then
            Resort(i, j);
        end else
        if Col = 2 then //Domain
        begin
          if UpperCase(DDNSDetails[i].Domain) > UpperCase(DDNSDetails[j].Domain) then
            Resort(i, j);
        end else
        if (Col = 3) or (Col = 4) then //Renewal date
        begin
          if DDNSDetails[i].Renewed > DDNSDetails[j].Renewed then
            Resort(i, j);
        end;
      end;
    end;
    lvDDNS.Columns[0].Caption := 'Client Name';
    lvDDNS.Columns[1].Caption := 'Trading As';
    lvDDNS.Columns[2].Caption := 'Domain Address';
    lvDDNS.Columns[3].Caption := 'Renewed';
    lvDDNS.Columns[4].Caption := 'Active';
    lvDDNS.Columns[Col].Caption := '|| '+lvDDNS.Columns[Col].Caption+' ||';
  end;
end;

procedure Resort(var i, j : Integer);
var
 tempInt : Integer;
 temp : string;
 tempDate : TDate;
 tempBool : Boolean;
begin
  tempInt := DDNSDetails[i].ID;
  DDNSDetails[i].ID := DDNSDetails[j].ID;
  DDNSDetails[j].ID := tempInt;

  temp := DDNSDetails[i].Name;
  DDNSDetails[i].Name := DDNSDetails[j].Name;
  DDNSDetails[j].Name := temp;

  temp := DDNSDetails[i].Alias;
  DDNSDetails[i].Alias := DDNSDetails[j].Alias;
  DDNSDetails[j].Alias := temp;

  temp := DDNSDetails[i].Domain;
  DDNSDetails[i].Domain := DDNSDetails[j].Domain;
  DDNSDetails[j].Domain := temp;

  tempDate := DDNSDetails[i].Renewed;
  DDNSDetails[i].Renewed := DDNSDetails[j].Renewed;
  DDNSDetails[j].Renewed := tempDate;

  tempBool := DDNSDetails[i].IsActive;
  DDNSDetails[i].IsActive := DDNSDetails[j].IsActive;
  DDNSDetails[j].IsActive := tempBool;

  temp := DDNSDetails[i].Login;
  DDNSDetails[i].Login := DDNSDetails[j].Login;
  DDNSDetails[j].Login := temp;

  temp := DDNSDetails[i].Password;
  DDNSDetails[i].Password := DDNSDetails[j].Password;
  DDNSDetails[j].Password := temp;
end;

此程序的目的是显示不同DDNS帐户的DDNS记录和登录凭据,并且某些客户端具有多个帐户。

例如,如果您按DDNS续订日期进行排序,则2022年7月23日可能有50个条目,而客户端“f”在该日期下有5个条目,但这5个条目不在一起。在名称列中,您可能会看到

z
w
g
x
f
z
a
f
.....

结果应该是

a
f
f
f
f
f
g
w
x
z
z
.....

对于所选的每一列,排序都能完美地工作。如果用户对任何其他列进行排序,我现在需要将名称列作为辅助列进行排序。

编辑:根据Dummzeuch的评论,我将Procedure Resort更改为以下内容:

procedure SwapRecord(var i, j : Integer);
var
 temp : TDDNS;
begin
  temp := DDNSDetails[i];
  DDNSDetails[i] := DDNSDetails[j];
  DDNSDetails[j] := temp;
end;
0tdrvxhp

0tdrvxhp1#

如果你使用的是Delphi 10.4--试着使用泛型类型。以下是我的建议:

type
   //declare new type to store sort rule
   TSortRule = record
     ColumnID : byte; //number of column
     Desc : boolean;  //reverse sort direction
   end;

//change array to list for storing items, it's much esier to work with it
var
  xList : TList<TDDNS>;

//we need somehow passed few sort rules, i prefer TList, something like that:
var
  xSortOrder : TList<TSortRule>;

以下是对所有这些员工进行分类的程序:

procedure TForm.SortRecords(AList : TList<TDDNS>; ASortOrder : TList<TSortRule>);
begin
  AList.Sort(TComparer<TDDNS>.Construct(
             function(const Left, Right: TDDNS): Integer
             var
               LeftValue, RightValue: TDDNS;
             begin
               //we go for all sorting rules
               for var xSortItem in ASortOrder do begin
                 //check if current rule is reverse
                 if not xSortItem.Desc then begin
                   LeftValue := Left;
                   RightValue := Right;
                 end else begin
                   //it's reverse - switch sides
                   LeftValue := Right;
                   RightValue := Left;
                 end{if..else};

                 //let's do comparation by correct property
                 case xSortItem.ColumnID of
                   0:  Result := CompareStr(Left.Name, Right.Name);
                   1:  Result := CompareStr(Left.Alias, Right.Alias);
                   2:  Result := CompareStr(Left.Domain, Right.Domain);
                   3, 4:  Result := TComparer<TDate>.Default.Compare(Left.Renewed, Right.Renewed);
                 end{case};

                 //if items not equval by this rule, we skip next rules
                 if Result <> 0 then
                   break;
               end{for};
              end
            ));
end;

有关TList排序的更多信息<>您可以在正式文档或Here example中阅读

相关问题