我需要对TListBox进行排序,但我意识到修改我的代码需要做很多工作,如果我要说一个TStringList,对它进行排序,然后将这些项目复制到Listbox中。很多工作的主要原因是我在代码中有许多地方修改了列表框内容,我想我必须编辑它们以在添加,删除或其他任何内容时强制排序。
我更喜欢让我只使用自定义排序逻辑对列表框进行排序的方法。
有可能吗?
答案 0 :(得分:5)
这不是问题!看看这个代码:
function CompareDates(List: TStringList; Index1, Index2: Integer): Integer;
var
d1, d2: TDateTime;
begin
d1 := StrToDate(List[Index1]);
d2 := StrToDate(List[Index2]);
if d1 < d2 then
Result := -1
else if d1 > d2 then
Result := 1
else
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
sl: TStringList;
begin
sl := TStringList.Create;
try
sl.Assign(ListBox1.Items);
sl.CustomSort(CompareDates);
ListBox1.Items.Assign(sl);
finally
sl.Free
end;
end;
答案 1 :(得分:0)
如果您使用的是Delphi XE或更高版本,我有可能为您服务。
请注意,我说的是“可能性”,而不是“解决方案”,因为它更像是一个黑客攻击,除非是最后的手段,否则我不会在生产代码中批准这个。
据我所知,您实际上想要实现的是覆盖Add函数(它是虚拟的)的行为,使其根据自定义顺序插入到正确的位置。 (如果你还需要覆盖插入,这也适用)。如果可以覆盖TLtrings后代的TListbox使用,那很简单,但我们没那么幸运。
Delphi XE引入了一个名为TVirtualMethodInterceptor(Rtti unit)的新类,它允许拦截虚拟方法以执行我们想要做的任何事情。我们可以检查和修改参数,调用其他功能,或者根本取消呼叫,什么都不做。
以下是我制作的概念证明:
//type
// TCompareFunc<T1> = reference to function (const Arg1, Arg2 : T1) : Integer;
procedure TForm4.FormCreate(Sender: TObject);
var vCompareFunc : TCompareFunc<string>;
RttiContext : TRttiContext;
vAddMethod : TRttiMethod;
vRttiType : TRttiType;
begin
RttiContext := TRttiContext.Create;
vRttiType := RttiContext.GetType(TStrings);
vAddMethod := vRttiType.GetMethod('Add');
vCompareFunc := MyCompareFunc;
Fvmi := TVirtualMethodInterceptor.Create(Listbox1.Items.ClassType);
Fvmi.OnBefore := procedure(Instance: TObject; Method: TRttiMethod;
const Args: TArray<TValue>; out DoInvoke: Boolean; out Result: TValue)
var
idx : Integer;
begin
if Method = vAddMethod then
begin //if it's the Add method, map it to Insert at the right position
DoInvoke := False;
BinarySearch(TStrings(Instance), Args[0].AsString, vCompareFunc,idx);
TStrings(Instance).Insert(idx, Args[0].AsString);
end;
end;
Fvmi.Proxify(Listbox1.Items);
end;
此概念证明拦截对TStrings.add的调用并将其映射到binarysearch / Insert,以便列表中的项始终按正确的顺序排列。这不会覆盖插入或分配功能,也不会覆盖修改列表的任何其他功能。如果您想使用这种方法,您需要覆盖所有“违规”功能。
免责声明:由于我从未真正使用过这种技术,因此不要将此示例视为TVirtualMethodInterceptor使用的黄金法则。它确实有效,但它可能具有性能影响或其他我不知道的。
需要提及的一点(来自Barry Kelly的博客,见下文)
TVirtualMethodInterceptor类没有一件事,但是, 是一种解开(取消提交)对象的方法。如果对象永远不会 没有被束缚,重要的是该物体不会比这更长久 拦截器,因为拦截器需要分配可执行文件 内存,以便创建重定向的小存根 方法调用事件。
如果你想深入挖掘,这里有一篇关于这个主题的非常好的文章: http://blog.barrkel.com/2010/09/virtual-method-interception.html