Delphi tListBox使用其他ListBox的自动完成导航

Delphi tListBox使用其他ListBox的自动完成导航,delphi,autocomplete,listbox,delphi-7,Delphi,Autocomplete,Listbox,Delphi 7,是否有一种方法可以使用本机tListBox自动完成导航系统,但要基于其他ListBox的项目?因此,当我键入一些字符时,应根据ListBox2中的数据选择ListBox1的焦点。它们都有相同数量的物品 是否有一种方法可以使用本机tListBox自动完成导航系统,但要基于其他ListBox的项目 是,但仅当TListBox.Style属性设置为lbVirtual或lbVirtualOwnerDraw时。在这种情况下,必须使用TListBox.Count属性和TListBox.OnData事件向列表

是否有一种方法可以使用本机tListBox自动完成导航系统,但要基于其他ListBox的项目?因此,当我键入一些字符时,应根据ListBox2中的数据选择ListBox1的焦点。它们都有相同数量的物品

是否有一种方法可以使用本机tListBox自动完成导航系统,但要基于其他ListBox的项目


是,但仅当
TListBox.Style
属性设置为
lbVirtual
lbVirtualOwnerDraw
时。在这种情况下,必须使用
TListBox.Count
属性和
TListBox.OnData
事件向列表框提供字符串。然后,自动完成功能将触发
TListBox.OnDataFind
事件,要求您在获取字符串的任何来源中查找键入的字符。在该事件处理程序中,您可以根据需要搜索另一个
TListBox
。只需知道,
OnDataFind
事件处理程序返回的
Integer
必须是相对于用户正在键入的
TListBox
的索引,而不是相对于您正在搜索的
TListBox
。当OnDataFind事件处理程序退出时,无论您返回哪个索引,都将被选中,除非您返回-1以指示未找到字符。

我尝试将其设为本机,但就我所知,无法将不同的项高度功能(Style=lbOwnerDrawVariable)与DataFind事件处理结合起来。当然可以在“VCL\StdCtrls”中编辑
TCustomListBox.KeyPress
过程,但我不喜欢深入研究VCL源代码。所以我决定自己从头开始实现自动完成功能。 首先,我决定为项目字符串编制索引,以加快搜索速度,但无需制作完整的图形(八达通树…无论什么…),因为在我的情况下(我有大约1k个项目),搜索几乎立即执行-因此,因为我的列表是按字典排序的,我只为第一个字母编制索引

//...
const
    acceptCharz=[' '..'z'];
//...
type
    twoWords=packed record a,b:word; end;
//...
var
    alphs:array[' '..'z']of twoWords;// indexes of first letters
    fs:tStringList;// list for searching in
    fnd:string;// charbuffer for search string
    tk:cardinal;// tickCounter for timing
//...
procedure Tform1.button1Click(Sender: TObject);// procedure where list filled with items
var
    k,l:integer;
    h,q:char;
begin
    //... here list-content formed ...
    if(fs<>nil)then fs.Free;
    fs:=tStringList.Create;
    // fltr is tListBox which data should be source of AutoCompletion (ListBox2)
    fs.AddStrings(fltr.Items);
    for h:=low(alphs)to high(alphs)do alphs[h].a:=$FFFF;// resetting index
    h:=#0;
    l:=fs.Count-1;
    if(l<0)then exit;
    for k:=0 to l do begin
        s:=AnsiLowerCase(fs.Strings[k]);// for case-insensetivity
        fs.Strings[k]:=s;
        if(length(s)<0)then continue;
        q:=s[1];
        if(h<>q)and(q in acceptCharz)then begin
            if(k>0)then alphs[h].b:=k-1;
            h:=q;
            alphs[h].a:=k;// this will work only with sorted data!
        end;
    end;
    if(h<>#0)then alphs[h].b:=l;
end;
//...
// fl is tListBox with custom drawing and OwnerDrawVariable style (ListBox1)
// also fl has same amount of items as fltr
procedure Tform1.flKeyPress(Sender: TObject; var Key: Char);
var
    n,i,k,e,l,u,m,a:integer;
    s:string;
    h:char;
    function CharLowerr(h:char):char;// make char LowerCase
    begin
        Result:=char(LoWord(CharLower(Pointer(h))));
    end;
begin
    if(getTickCount-tk>=800)then fnd:='';// AutoComplete timeout
    tk:=getTickCount;
    h:=CharLowerr(key);// for case-insensetivity
    if(h in ['a'..'z','0'..'9',' ','-','.'])then fnd:=fnd+h;// u can add all needed chars
    if(fnd='')then exit;// if no string to find
    h:=fnd[1];// obtain first letter of search-string
    a:=alphs[h].a;// get index of first item starting with letter
    l:=alphs[h].b;// get index of last item starting with letter
    if(a=$FFFF)then exit;// if no such items
    e:=length(fnd);// get length of search-string
    u:=1;// current length of overlap
    m:=1;// max overlap
    i:=a;// index to select
    if(e>1)then for k:=a to l do begin
        s:=fs.Strings[k];
        if(length(s)<e)then continue;
        for n:=2 to e do begin// compare strings char-by-char
            if(s[n]<>fnd[n])then begin// compare failed
                u:=n-1;
                break;
            end else u:=n;
            if(u>m)then begin// current overlap is max
                m:=u;
                i:=k;
            end;
        end;
        if(u=e)or(u<m)then break;// if end of search reached
    end;
    // select needed index:
    fl.ClearSelection;
    SendMessage(fl.Handle, LB_SELITEMRANGE, 1, MakeLParam(i, i));
    fl.ItemIndex:=i;
    inherited;
end;
//...
/。。。
常数
acceptCharz=[''..'z'];
//...
类型
twoWords=压缩记录a,b:字;结束;
//...
变量
alphs:两个单词的数组[''..'z'];//首字母索引
fs:tStringList;//用于在中搜索的列表
fnd:string;//搜索字符串的字符缓冲区
tk:基数;//计时计数器
//...
步骤t用于m1.按钮1单击(发件人:ToObject);//用项目填充列表的程序
变量
k、 l:整数;
h、 q:字符;
开始
//... 这里列出形成的内容。。。
如果(fsnil),则fs.Free;
fs:=tStringList.Create;
//fltr是一个列表框,其中数据应为自动完成源(列表框2)
fs.AddStrings(fltr.Items);
对于h:=低(alphs)到高(alphs)do alphs[h]。a:=$FFFF;//重置索引
h:=#0;
l:=fs.Count-1;
如果(l=800),则fnd:=''自动完成超时
tk:=getTickCount;
h:=CharLowerr(键);//对于案例不敏感
如果(h在['a'..'z','0'..'9','','''-','..]]中),那么fnd:=fnd+h;//你可以添加所有需要的字符
如果(fnd=''),则退出;//如果找不到字符串
h:=fnd[1];//获取搜索字符串的第一个字母
a:=alphs[h].a;//获取以字母开头的第一项的索引
l:=alphs[h].b;//获取以字母开头的最后一项的索引
如果(a=$FFFF),则退出;//如果没有这些项目
e:=长度(fnd);//获取搜索字符串的长度
u:=1;//当前重叠长度
m:=1;//最大重叠
i:=a;//要选择的索引
如果(e>1),那么对于k:=a到l,开始
s:=fs.Strings[k];
如果(长度)m,则开始//当前重叠最大
m:=u;
i:=k;
结束;
结束;
如果(u=e)或(u