tListBox使用来自其他ListBox的AutoComplete导航

时间:2016-05-24 12:46:33

标签: delphi autocomplete listbox delphi-7

有没有办法使用原生 tListBox 自动完成导航系统但是基于其他ListBox的项目?所以当ListBox1聚焦时,我输入一些字符应根据ListBox2中的数据选择。两者都有相同数量的物品。

2 个答案:

答案 0 :(得分:2)

  

有没有办法使用原生的tListBox自动完成导航系统,但是基于其他ListBox的项目?

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

答案 1 :(得分:0)

我试图让它原生,但据我所知 - 不可能将不同的项目高度功能(Style = lbOwnerDrawVariable )与DataFind事件处理相结合。当然可以在“ VCL \ StdCtrls ”中编辑TCustomListBox.KeyPress程序,但我不想深入研究vcl来源。所以我决定自己实现自动完成功能。 首先,我决定将项目字符串编入索引以便更快地进行搜索,但是没有必要在我的情况下制作完整的图形(octotree ...无论......)cuz搜索(我有大约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;
//...

是的,这段代码有点难看,但它工作得很好,正如我所说的 - 几乎是瞬间,我只能看到选择如何在我打字的时候通过物品跳跃,而且我打字很快......

所以这是我昨天写的代码,所有这些都可以在这里结束,但今天我意识到这完全是愚蠢的决定:在我的情况下,正如我上面提到的,我有使用OwnerDrawVariable风格的列表框,所以我有自定义MeasureItem和DrawItem过程以及在这种情况下的最佳决策是将AutoComplete属性设置为true并使用ListBox2中的项填充ListBox1。显示所需的字符串无论如何都可以在DrawItem过程中显示。也可以删除ListBox2并保留字符串以显示在tStringList变量中。所以士气高涨 - 不要急于编写样板,并在行动之前尝试更多思考=))

P.S。但是可以使用此代码进行一些自定义AutoComplete处理...