【发布时间】:2022-10-08 20:42:25
【问题描述】:
我正在 Delphi 10.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 的评论,我将程序 Resort 更改为以下内容:
procedure SwapRecord(var i, j : Integer);
var
temp : TDDNS;
begin
temp := DDNSDetails[i];
DDNSDetails[i] := DDNSDetails[j];
DDNSDetails[j] := temp;
end;
【问题讨论】:
-
使用 RTL 的内置分拣工具(如
TList<>.Sort或TArray.Sort<>);那么你只需要提供你自己的比较器。在您的情况下,如果主要列存在平局,则需要考虑次要列。 -
你不是说你使用的是哪个 Delphi 版本。根据这一点,有几种选择。 Andreas Rejbrand 提到了一个基于泛型的解决方案,该解决方案已经使用了好几年了。但是,如果您使用古老的 Delphi 版本,这些将不适合您。
-
通过直接分配记录而不是它们的字段,您的度假村程序可以简单得多。
-
@ dummzeuch 我看到有人编辑了我的问题“从标题中删除了多余的标签信息”,这是该信息,我将其添加回来,因为它也会帮助其他人。我不是专业的程序员。除了在学校外,一切基本上都是自学的。
-
@WackyWabbit:被删除的“冗余标签信息”是“Delphi”——这确实是多余的!您稍后添加的文本是“Delphi 10.4”,其中“10.4”是新的(并且非常重要的)信息!
标签: arrays sorting listview delphi record