首页 > 代码库 > Autocomplete TEdit
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
- Upon typing some chars, TAutocompleteEdit will check the typed word agains a word list. When no match found, do nothing.
- When one or more matches found, TAutocompleteEdit show the matches in a TListBox.We will call this TListBoxWordList.
- User can move between TAutocompleteEdit and WordList using down and up arrow.
- User select a complete word from WordList by highlighting the word and press Enter key.
- After user selected a word, the word will replace whatever content in TAutocompleteEdit.
- If user press Escape in TAutocompleteEdit or in WordList, WordList must dissapear.
- If TAutocompleteEdit lost focus, and the new focus is not in WordList, WordList must dissapear.
- If WordList lost focus, and the new focus is not in TAutocompleteEdit, WordList must dissapear.
- 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.
- 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. - HideWordList.
This method is responsible to hide and clean up WordList. - 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. - 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. - 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 begin100 Result := False;101 AWord := UpperCase(AWord);102 for i := 0 to FWords.Count-1 do103 begin104 Result := System.Pos(AWord, FWords.Names[i]) > 0;105 if Result then106 Break;107 end;108 end;109 110 function TAutocompleteMan.IsRecognized(AWord: string;111 AWordList: TStrings): Boolean;112 var113 i: Integer;114 begin115 Result := False;116 AWord := UpperCase(AWord);117 AWordList.Clear;118 for i := 0 to FWords.Count-1 do119 begin120 if System.Pos(AWord, FWords.Names[i]) > 0 then121 begin122 Result := True;123 AWordList.Add(FWords.ValueFromIndex[i]);124 end;125 end;126 end;127 128 procedure TAutocompleteMan.LoadFromFile(const AFilename: string);129 var130 i: Integer;131 F: TStrings;132 begin133 F := TStringList.Create;134 try135 F.LoadFromFile(AFilename);136 for i := 0 to F.Count-1 do137 AddWord(F[i]);138 finally139 F.Free;140 end;141 end;142 143 { TAutocompleteEdit }144 145 procedure TAutocompleteEdit.Change;146 var147 S: TStrings;148 begin149 inherited;150 if AutocompleteMan.IsRecognized(Self.Text) then151 begin152 S := TStringList.Create;153 try154 if AutocompleteMan.IsRecognized(Self.Text, S) then155 ShowWordList(S);156 finally157 S.Free;158 end;159 end160 else161 HideWordList;162 end;163 164 procedure TAutocompleteEdit.HandleHideWordList(var AMsg);165 begin166 HandleHideWordList;167 end;168 169 constructor TAutocompleteEdit.Create(AOwner: TComponent);170 begin171 inherited;172 FWordListHeight := 60;173 end;174 175 procedure TAutocompleteEdit.DoExit;176 begin177 if Assigned(FWordList) and FWordList.Visible and not FWordList.Focused then178 HideWordList;179 inherited;180 end;181 182 procedure TAutocompleteEdit.HandleHideWordList;183 begin184 FWordList.Free;185 FWordList := nil;186 end;187 188 procedure TAutocompleteEdit.HandleWordListKeyDown(ASender: TObject;189 var Key: Word; Shift: TShiftState);190 begin191 if (Key=VK_UP) and (FWordList.ItemIndex=0) then192 RegainFocus;193 end;194 195 procedure TAutocompleteEdit.HandleWordListKeyPress(Sender: TObject;196 var Key: Char);197 begin198 case Key of199 #13: begin200 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: begin208 RegainFocus;209 HideWordList;210 end;211 else begin212 RegainFocus;213 end;214 end;215 end;216 217 procedure TAutocompleteEdit.HandleWordListLostFocus(ASender: TObject);218 begin219 if not Self.Focused then220 HideWordList;221 end;222 223 procedure TAutocompleteEdit.HandleWordListSelectItem(ASender: TObject);224 begin225 Self.Text := FWordList.Items[FWordList.ItemIndex];226 HideWordList;227 end;228 229 procedure TAutocompleteEdit.HideWordList;230 begin231 PostMessage(Self.Handle, MSG_HIDEWORDLIST, 0, 0);232 end;233 234 procedure TAutocompleteEdit.KeyDown(var Key: Word; Shift: TShiftState);235 begin236 if Key=VK_ESCAPE then237 HideWordList238 else if (Key=VK_DOWN) and Assigned(FWordList) and FWordList.Visible then239 begin240 FCaretPos := Self.SelStart;241 FWordList.SetFocus;242 if FWordList.ItemIndex < 0 then243 FWordList.ItemIndex := 0;244 end245 else246 inherited;247 end;248 249 procedure TAutocompleteEdit.RegainFocus;250 begin251 Self.SetFocus;252 Self.SelStart := FCaretPos;253 Self.SelLength := 0;254 end;255 256 procedure TAutocompleteEdit.SetWordListHeight(const Value: Integer);257 begin258 if FWordListHeight <> Value then259 begin260 FWordListHeight := Value;261 if Assigned(FWordList) then262 FWordList.Height := FWordListHeight;263 end;264 end;265 266 procedure TAutocompleteEdit.SetWordListWidth(const Value: Integer);267 begin268 if FWordListWidth <> Value then269 begin270 FWordListWidth := Value;271 if Assigned(FWordList) then272 begin273 if FWordListWidth < 1 then274 FWordList.Width := Self.Width275 else276 FWordList.Width := FWordListWidth;277 end;278 end;279 end;280 281 procedure TAutocompleteEdit.ShowWordList(AWords: TStrings);282 begin283 if FWordList=nil then284 begin285 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 then297 FWordList.SetBounds(Self.Left, Self.Top + Self.Height, Self.Width, FWordListHeight)298 else299 FWordList.SetBounds(Self.Left, Self.Top + Self.Height, FWordListWidth, FWordListHeight);300 301 FWordList.Show;302 end;303 304 initialization305 AutocompleteMan := TAutocompleteMan.Create;306 307 finalization308 AutocompleteMan.Free;309 end.
Autocomplete TEdit