[Note: this article is still a work in progress. Please visit again in near future to see the final version.]
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 TListBox WordList.
- 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
2542 downloads. Feel free to use it or improve it for any kind of use.
Cheers!