Autocomplete TEdit

http://forum.codecall.net/topic/75946-autocomplete-tedit/

Overview

Autocomplete feature really helpful for us speeding up our typing job.

For you who is not familiar with the term autocomplete,

it‘s when you type partial part of a word and then

you will be presented with a list of possible complete words.

You can just select the correct word from the list,

and that partial word will be automatically completed.

In programming, this feature very helpful to

"remember" class names, routine names, and variable name.

Not only to speed up the typing, autocomplete also very helpful to avoid typo.

In this tutorial I will show you a technique to implement autocomplete

in your Delphi program in order to provide your users the benefits of autocomplete.

I will implement autocomplete in a descendant of TEdit. I name it TAutocompleteEdit.

TAutoCompleteEdit

Behaviors

  1. Upon typing some chars, TAutocompleteEdit will check the typed word agains a word list. When no match found, do nothing.
  2. When one or more matches found, TAutocompleteEdit show the matches in a TListBox.We will call this TListBoxWordList.
  3. User can move between TAutocompleteEdit and WordList using down and up arrow.
  4. User select a complete word from WordList by highlighting the word and press Enter key.
  5. After user selected a word, the word will replace whatever content in TAutocompleteEdit.
  6. If user press Escape in TAutocompleteEdit or in WordList, WordList must dissapear.
  7. If TAutocompleteEdit lost focus, and the new focus is not in WordList, WordList must dissapear.
  8. If WordList lost focus, and the new focus is not in TAutocompleteEdit, WordList must dissapear.
  9. If later user type in another character and no match found, WordList must dissapear.

Key Methods

From the above behaviors, we decided to have the following methods.

  1. ShowWordList(AWords: TStrings).
    This method is responsible to create WordList TListBox when needed,
    populate it with words contained in AWords, and
    also to patch its events so we can achieve behavior #3, #4, #5, #6, and #8.
  2. HideWordList.
    This method is responsible to hide and clean up WordList.
  3. Change.
    This is where to respond when the content of TAutocompleteEdit changed.
    So this is where we do the checking.
    This method actually already exist in TAutocompleteEdit‘s parent.
    So what we are going to do is override it, and introduce our behavior.
  4. DoExit.
    This method also already exist in TAutocompleteEdit‘s parent.
    We are going to override it and introduce new behavior, in order to achieve behavior #7.
  5. KeyDown(var Key: Word; Shift: TShiftState).
    This method also already exist in TAutocompleteEdit‘s parent.
    We are going to override it to achieve behavior #3 and #6.

Key Methods Implementations

1. ShowWordList(AWords: TStrings).


procedure TAutocompleteEdit.ShowWordList(AWords: TStrings);
begin
  if FWordList=nil then
  begin
    FWordList := TListBox.Create(Self);
    FWordList.ParentCtl3D := False;
    FWordList.Ctl3D := False;
    FWordList.Parent := Self.Parent;
    FWordList.TabStop := False;
    FWordList.OnExit := HandleWordListLostFocus;
    FWordList.OnKeyPress := HandleWordListKeyPress;
    FWordList.OnKeyDown := HandleWordListKeyDown;
  end;

  FWordList.Items.Assign(AWords);
  if FWordListWidth < 1 then
    FWordList.SetBounds(Self.Left, Self.Top + Self.Height, Self.Width, FWordListHeight)
  else
    FWordList.SetBounds(Self.Left, Self.Top + Self.Height, FWordListWidth, FWordListHeight);

  FWordList.Show;
end;
 

2. HideWordList

procedure TAutocompleteEdit.HideWordList;
begin
  PostMessage(Self.Handle, MSG_HIDEWORDLIST, 0, 0);
end;

Note that in the above method we only post a custom message. The custom message handler in turn will call this private method.

procedure TAutocompleteEdit.HandleHideWordList;
begin
  FWordList.Free;
  FWordList := nil;
end;

3. Change.

procedure TAutocompleteEdit.Change;
var
  S: TStrings;
begin
  inherited;
  if AutocompleteMan.IsRecognized(Self.Text) then
  begin
    S := TStringList.Create;
    try
      if AutocompleteMan.IsRecognized(Self.Text, S) then
        ShowWordList(S);
    finally
      S.Free;
    end;
  end
  else
    HideWordList;
end;

4. DoExit.

procedure TAutocompleteEdit.DoExit;
begin
  if Assigned(FWordList) and FWordList.Visible and not FWordList.Focused then
    HideWordList;
  inherited;
end;

5. KeyDown(var Key: Word; Shift: TShiftState).

procedure TAutocompleteEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
  if Key=VK_ESCAPE then
    HideWordList
  else if (Key=VK_DOWN) and Assigned(FWordList) and FWordList.Visible then
  begin
    FCaretPos := Self.SelStart;
    FWordList.SetFocus;
    if FWordList.ItemIndex < 0 then
      FWordList.ItemIndex := 0;
  end
  else
    inherited;
end;

Here is the complete source code of TAutocompleteEdit:

TEdit with Autocomplete.zip   1.84MB   603 downloads.

Feel free to use it or improve it for any kind of use.

Cheers!

  1 unit AutocompleteEdit;
  2
  3 interface
  4
  5 uses
  6   Windows
  7   , Classes
  8   , Vcl.StdCtrls
  9   , SysUtils
 10   , StrUtils
 11   , Messages
 12   ;
 13
 14 const
 15   MSG_HIDEWORDLIST = WM_USER + 222;
 16
 17 type
 18   TAutocompleteEdit=class(TEdit)
 19   private
 20     FWordList: TListBox;
 21     FCaretPos: Integer;
 22     FWordListHeight: Integer;
 23     FWordListWidth: Integer;
 24
 25     procedure HandleWordListLostFocus(ASender: TObject);
 26     procedure HandleWordListSelectItem(ASender: TObject);
 27     procedure HandleWordListKeyPress(Sender: TObject; var Key: Char);
 28     procedure HandleWordListKeyDown(ASender: TObject; var Key: Word; Shift: TShiftState);
 29     procedure HandleHideWordList(var AMsg); overload; message MSG_HIDEWORDLIST;
 30     procedure HandleHideWordList; overload;
 31     procedure SetWordListHeight(const Value: Integer);
 32     procedure SetWordListWidth(const Value: Integer);
 33
 34     procedure RegainFocus;
 35   protected
 36     procedure ShowWordList(AWords: TStrings);
 37     procedure HideWordList;
 38     procedure Change; override;
 39     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
 40     procedure DoExit; override;
 41   public
 42     constructor Create(AOwner: TComponent); override;
 43   published
 44     property WordListHeight: Integer read FWordListHeight write SetWordListHeight;
 45     property WordListWidth: Integer read FWordListWidth write SetWordListWidth;
 46   end;
 47
 48   TAutocompleteMan=class
 49   private
 50     FWords: TStrings;
 51   public
 52     constructor Create;
 53     destructor Destroy; override;
 54
 55     function IsRecognized(AWord: string): Boolean; overload;
 56     function IsRecognized(AWord: string; AWordList: TStrings): Boolean; overload;
 57
 58     procedure LoadFromFile(const AFilename: string);
 59     procedure AddWord(const AWord: string);
 60
 61     property Words: TStrings read FWords;
 62   end;
 63
 64   procedure Register;
 65
 66 var
 67   AutocompleteMan: TAutocompleteMan;
 68
 69
 70 implementation
 71
 72 procedure Register;
 73 begin
 74   RegisterComponents(‘CodeCall‘, [TAutocompleteEdit]);
 75 end;
 76
 77 { TAutocompleteMan }
 78
 79 procedure TAutocompleteMan.AddWord(const AWord: string);
 80 begin
 81   FWords.Add(UpperCase(AWord) + ‘=‘ + AWord);
 82 end;
 83
 84 constructor TAutocompleteMan.Create;
 85 begin
 86   FWords := TStringList.Create;
 87   TStringList(FWords).Duplicates := dupIgnore;
 88 end;
 89
 90 destructor TAutocompleteMan.Destroy;
 91 begin
 92   FWords.Free;
 93   inherited;
 94 end;
 95
 96 function TAutocompleteMan.IsRecognized(AWord: string): Boolean;
 97 var
 98   i: Integer;
 99 begin
100   Result := False;
101   AWord := UpperCase(AWord);
102   for i := 0 to FWords.Count-1 do
103   begin
104     Result := System.Pos(AWord, FWords.Names[i]) > 0;
105     if Result then
106       Break;
107   end;
108 end;
109
110 function TAutocompleteMan.IsRecognized(AWord: string;
111   AWordList: TStrings): Boolean;
112 var
113   i: Integer;
114 begin
115   Result := False;
116   AWord := UpperCase(AWord);
117   AWordList.Clear;
118   for i := 0 to FWords.Count-1 do
119   begin
120     if System.Pos(AWord, FWords.Names[i]) > 0 then
121     begin
122       Result := True;
123       AWordList.Add(FWords.ValueFromIndex[i]);
124     end;
125   end;
126 end;
127
128 procedure TAutocompleteMan.LoadFromFile(const AFilename: string);
129 var
130   i: Integer;
131   F: TStrings;
132 begin
133   F := TStringList.Create;
134   try
135     F.LoadFromFile(AFilename);
136     for i := 0 to F.Count-1 do
137       AddWord(F[i]);
138   finally
139     F.Free;
140   end;
141 end;
142
143 { TAutocompleteEdit }
144
145 procedure TAutocompleteEdit.Change;
146 var
147   S: TStrings;
148 begin
149   inherited;
150   if AutocompleteMan.IsRecognized(Self.Text) then
151   begin
152     S := TStringList.Create;
153     try
154       if AutocompleteMan.IsRecognized(Self.Text, S) then
155         ShowWordList(S);
156     finally
157       S.Free;
158     end;
159   end
160   else
161     HideWordList;
162 end;
163
164 procedure TAutocompleteEdit.HandleHideWordList(var AMsg);
165 begin
166   HandleHideWordList;
167 end;
168
169 constructor TAutocompleteEdit.Create(AOwner: TComponent);
170 begin
171   inherited;
172   FWordListHeight := 60;
173 end;
174
175 procedure TAutocompleteEdit.DoExit;
176 begin
177   if Assigned(FWordList) and FWordList.Visible and not FWordList.Focused then
178     HideWordList;
179   inherited;
180 end;
181
182 procedure TAutocompleteEdit.HandleHideWordList;
183 begin
184   FWordList.Free;
185   FWordList := nil;
186 end;
187
188 procedure TAutocompleteEdit.HandleWordListKeyDown(ASender: TObject;
189   var Key: Word; Shift: TShiftState);
190 begin
191   if (Key=VK_UP) and (FWordList.ItemIndex=0) then
192     RegainFocus;
193 end;
194
195 procedure TAutocompleteEdit.HandleWordListKeyPress(Sender: TObject;
196   var Key: Char);
197 begin
198   case Key of
199     #13: begin
200            Key := #0;
201            Self.Text := FWordList.Items[FWordList.ItemIndex];
202            Self.SetFocus;
203            Self.SelStart := Length(Self.Text);
204            Self.SelLength := 0;
205            HideWordList;
206          end;
207     #27: begin
208            RegainFocus;
209            HideWordList;
210          end;
211     else begin
212       RegainFocus;
213     end;
214   end;
215 end;
216
217 procedure TAutocompleteEdit.HandleWordListLostFocus(ASender: TObject);
218 begin
219   if not Self.Focused then
220     HideWordList;
221 end;
222
223 procedure TAutocompleteEdit.HandleWordListSelectItem(ASender: TObject);
224 begin
225   Self.Text := FWordList.Items[FWordList.ItemIndex];
226   HideWordList;
227 end;
228
229 procedure TAutocompleteEdit.HideWordList;
230 begin
231   PostMessage(Self.Handle, MSG_HIDEWORDLIST, 0, 0);
232 end;
233
234 procedure TAutocompleteEdit.KeyDown(var Key: Word; Shift: TShiftState);
235 begin
236   if Key=VK_ESCAPE then
237     HideWordList
238   else if (Key=VK_DOWN) and Assigned(FWordList) and FWordList.Visible then
239   begin
240     FCaretPos := Self.SelStart;
241     FWordList.SetFocus;
242     if FWordList.ItemIndex < 0 then
243       FWordList.ItemIndex := 0;
244   end
245   else
246     inherited;
247 end;
248
249 procedure TAutocompleteEdit.RegainFocus;
250 begin
251   Self.SetFocus;
252   Self.SelStart := FCaretPos;
253   Self.SelLength := 0;
254 end;
255
256 procedure TAutocompleteEdit.SetWordListHeight(const Value: Integer);
257 begin
258   if FWordListHeight <> Value then
259   begin
260     FWordListHeight := Value;
261     if Assigned(FWordList) then
262       FWordList.Height := FWordListHeight;
263   end;
264 end;
265
266 procedure TAutocompleteEdit.SetWordListWidth(const Value: Integer);
267 begin
268   if FWordListWidth <> Value then
269   begin
270     FWordListWidth := Value;
271     if Assigned(FWordList) then
272     begin
273       if FWordListWidth < 1 then
274         FWordList.Width := Self.Width
275       else
276         FWordList.Width := FWordListWidth;
277     end;
278   end;
279 end;
280
281 procedure TAutocompleteEdit.ShowWordList(AWords: TStrings);
282 begin
283   if FWordList=nil then
284   begin
285     FWordList := TListBox.Create(Self);
286     FWordList.ParentCtl3D := False;
287     FWordList.Ctl3D := False;
288     FWordList.Parent := Self.Parent;
289     FWordList.TabStop := False;
290     FWordList.OnExit := HandleWordListLostFocus;
291     FWordList.OnKeyPress := HandleWordListKeyPress;
292     FWordList.OnKeyDown := HandleWordListKeyDown;
293   end;
294
295   FWordList.Items.Assign(AWords);
296   if FWordListWidth < 1 then
297     FWordList.SetBounds(Self.Left, Self.Top + Self.Height, Self.Width, FWordListHeight)
298   else
299     FWordList.SetBounds(Self.Left, Self.Top + Self.Height, FWordListWidth, FWordListHeight);
300
301   FWordList.Show;
302 end;
303
304 initialization
305   AutocompleteMan := TAutocompleteMan.Create;
306
307 finalization
308   AutocompleteMan.Free;
309 end.
时间: 2024-10-29 10:45:41

Autocomplete TEdit的相关文章

JQuery UI之Autocomplete(2)

1.Autocomplete获取后台数据 首先引入css和js文件,以及对应的HTML代码如下: <link href="../css/jquery-ui.css" rel="stylesheet" /> <script type="text/javascript" src="../js/jquery-1.9.1.min.js" ></script> <script type=&quo

c#+jquery.autocomplete.js

html代码: $(document).ready(function () { $.ajax({ type: "POST", contentType: "json", url: "a.ashx?action=findlist", data: "{}", dataType: "html", success: function (data) { var dataset = eval('(' + data + '

JQuery UI之Autocomplete(4)多值输入、远程缓存与组合框

1.多值输入 首先加入相关的css和js文件,以及对应的HTML代码如下: <link href="../css/jquery-ui.css" rel="stylesheet" /> <script type="text/javascript" src="../js/jquery-1.9.1.min.js" ></script> <script type="text/java

jq 之Autocomplete 引发联想及思考

前情纪要:JQuery UI 是以 JQuery 为基础的开源 JavaScript 网页用户界面代码库.包含底层用户交互.动画.特效和可更换主题的可视控件,这些控件主要包括:Accordion,Autocomplete,ColorPicker,Dialog,Slider,Tabs,DatePicker,Magnifier,ProgressBar,Spinner等,其中Autocomplete能够非常容易的帮我们实现类似于百度搜索的智能提示功能. 我现在要实现的是在订单中心下单时,实现通过输入客

百度地图之自动提示--autoComplete

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width"> <title>百度地图之

JQuery 插件 autocomplete

最近有个功能就是对文本框里的内容模糊查询,并出现一个下拉框对模糊查询出来的内容进行选择.最开始写的时候我就想起以前的公司遇到过,用的是rpc(简称人品差),but我已经记不得咋个实现的了,然后各种求助以前的同事.然而他们都不晓得咋个弄了.好吧,咋办呢,我就问旁边的同事有没有遇到过这种类似的功能,怎么做的,早点问也不至于时间白白浪费吧.于是就有了autocomplete.我的知识面不广,所以现在我也尽量在总结,不要笑. 进入主题: 官网地址:api.jqueryui.com/autocomplet

自动完成--autoComplete插件

js下载地址:https://github.com/devbridge/jQuery-Autocomplete 1.引入js,引入css --start--------------------------------------------------------------------------------------------- 1.autoComplete()方法 $(selector).autoComplete(配置对象); 具体使用 配置属性 1) lookup 类型:字符串数组或

JQuery Autocomplete实战

废话不多说,先看效果!~ 需要引入的资源如下 <link rel="stylesheet" href="/css/jquery.autocomplete.css" type="text/css"> <script type="text/javascript" src="/lib/jquery.min.js"></script><!--1.8.3--> <

jquery autocomplete 自动补全

写在前面 autocomplete是jqueryUI里的一个插件 效果和说明可以访问这里,作用类似于搜索时的自动提示: 相信用过jQuery autocomplete 自动补全功能同学有不少,但是往往我们所对应的需求不同,有的仅仅是为了省事,敲两个字就有一堆可供选择的信息可供选择,但并不是所有需求都是这样的,我们还有这样的需求,敲两个字,将这个文字对应的实体绑定出来. 主要的参数 jQuery UI Autocomplete常用的参数有: Source:用于指定数据来源,类型为String.Ar