Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 是否可以使用自定义排序比较器对TListBox进行排序?_Delphi - Fatal编程技术网

Delphi 是否可以使用自定义排序比较器对TListBox进行排序?

Delphi 是否可以使用自定义排序比较器对TListBox进行排序?,delphi,Delphi,我需要对我的TListBox进行排序,但我意识到如果我说制作一个TStringList,对它进行排序,然后将这些项目复制到Listbox中,那么修改我的代码需要做很多工作。这需要大量工作的主要原因是,我在代码中有许多地方修改了列表框的内容,我想我必须对它们进行编辑,以便在添加、删除或其他内容时强制进行排序 我更倾向于使用自定义排序逻辑将方法附加到列表框中进行排序 这有可能吗?如果您使用的是Delphi XE或更高版本,我有一个可能性 请注意,我说的是“可能性”,而不是“解决方案”,因为它比其他任

我需要对我的TListBox进行排序,但我意识到如果我说制作一个TStringList,对它进行排序,然后将这些项目复制到Listbox中,那么修改我的代码需要做很多工作。这需要大量工作的主要原因是,我在代码中有许多地方修改了列表框的内容,我想我必须对它们进行编辑,以便在添加、删除或其他内容时强制进行排序

我更倾向于使用自定义排序逻辑将方法附加到列表框中进行排序


这有可能吗?

如果您使用的是Delphi XE或更高版本,我有一个可能性

请注意,我说的是“可能性”,而不是“解决方案”,因为它比其他任何东西都更像是一种黑客行为,我不会在生产代码中真正批准它,除非它是最后的手段

据我所知,您实际上试图实现的是重写Add函数的行为(这是虚拟的),使其基于自定义顺序插入到正确的位置。(如果还需要替代插入,也可以使用此选项)。如果有可能覆盖TStrings后代TListbox的使用,那将很简单,但我们没有那么幸运

DelphiXE引入了一个名为TVirtualMethodInterceptor(Rtti单元)的新类,该类允许拦截虚拟方法来执行我们想用它执行的任何操作。我们可以检查和修改参数,调用其他函数,或者随意取消调用而什么也不做

下面是我制作的概念验证的样子:

//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;
//类型
//TCompareFunc=对函数的引用(常量Arg1,Arg2:T1):整数;
程序TForm4.FormCreate(发送方:TObject);
var vCompareFunc:TCompareFunc;
RttiContext:TRttiContext;
vadd法:trtti法;
vRttiType:TRttiType;
开始
RttiContext:=TRttiContext.Create;
vRttiType:=RttiContext.GetType(TStrings);
vAddMethod:=vRttiType.GetMethod('Add');
vCompareFunc:=MyCompareFunc;
Fvmi:=TVirtualMethodInterceptor.Create(Listbox1.Items.ClassType);
Fvmi.OnBefore:=过程(实例:TObject;方法:TRttiMethod;
常量参数:TArray;out-DoInvoke:Boolean;out-Result:TValue)
变量
idx:整数;
开始
如果Method=vAddMethod,则
开始//如果是Add方法,请将其映射到正确位置的Insert
DoInvoke:=假;
BinarySearch(TStrings(实例),Args[0]。AsString,vCompareFunc,idx);
TStrings(Instance).Insert(idx,Args[0].AsString);
结束;
结束;
Fvmi.Proxify(列表框1.项目);
结束;
此概念验证拦截对TStrings.add的调用,并将其映射到binarysearch/Insert,以便列表中的项始终按正确的顺序排列。这不会覆盖Insert或Assign函数,也不会覆盖修改列表的任何其他函数。如果您想使用这种方法,您需要覆盖所有“违规”函数

免责声明:由于我从未真正使用过这一技巧,所以不要把这个例子当作TVirtualMethodInterceptor用法的黄金法则。它确实有效,但可能会对性能产生影响,或者其他我不知道的影响

需要提及的一个要点(来自巴里·凯利的博客,见下文)

但是,TVirtualMethodInterceptor类没有一件事, 是一种解开(解除锁定)对象的方法。如果对象永远不存在 解除挂钩,重要的是物体不会比目标寿命长 拦截器,因为拦截器需要分配可执行文件 内存,以创建它重定向的小存根 方法调用事件

如果你想深入挖掘,这里有一篇关于这个主题的不错的文章:

如果您使用的是Delphi XE或更高版本,我有一个可能性

请注意,我说的是“可能性”,而不是“解决方案”,因为它比其他任何东西都更像是一种黑客行为,我不会在生产代码中真正批准它,除非它是最后的手段

据我所知,您实际上试图实现的是重写Add函数的行为(这是虚拟的),使其基于自定义顺序插入到正确的位置。(如果还需要替代插入,也可以使用此选项)。如果有可能覆盖TStrings后代TListbox的使用,那将很简单,但我们没有那么幸运

DelphiXE引入了一个名为TVirtualMethodInterceptor(Rtti单元)的新类,该类允许拦截虚拟方法来执行我们想用它执行的任何操作。我们可以检查和修改参数,调用其他函数,或者随意取消调用而什么也不做

下面是我制作的概念验证的样子:

//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;
//类型
//TCompareFunc=对函数的引用(常量Arg1,Arg2:T1):整数;
程序TForm4.FormCreate(发送方:TObject);
var vCompareFunc:TCompareFunc;
RttiContext:TRttiContext;
vadd法:trtti法;
vRttiType:TRttiType;
开始
RttiContext:=TRttiContext.Create;
vRttiType:=RttiContext.GetType(TStrings);
vAddMethod:=vRttiType.GetMethod('Add');
vCompareFunc:=MyCompareFunc;
Fvmi:=TVirtualMethodInterceptor.Create(Listbox1.Items.ClassType);
Fvmi.OnBefore:=过程(实例:TObject;方法:TRttiMethod;
常量参数:TArray;out-DoInvoke:Boolean;out-Result:TValue)
变量
idx:整数;
开始
如果Method=vAddMethod,则
开始//如果是Add方法,请将其映射到正确位置的Insert
DoInvoke:=假;
BinarySearch(TStrings(实例),Args[0]。AsString,vCompareFunc,idx);
TStrings(实例).Insert(idx,参数[0].AsStrin