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 < 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, , );
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 < then
FWordList.ItemIndex := ;
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!
unit AutocompleteEdit; interface uses
Windows
, Classes
, Vcl.StdCtrls
, SysUtils
, StrUtils
, Messages
; const
MSG_HIDEWORDLIST = WM_USER + ; type
TAutocompleteEdit=class(TEdit)
private
FWordList: TListBox;
FCaretPos: Integer;
FWordListHeight: Integer;
FWordListWidth: Integer; procedure HandleWordListLostFocus(ASender: TObject);
procedure HandleWordListSelectItem(ASender: TObject);
procedure HandleWordListKeyPress(Sender: TObject; var Key: Char);
procedure HandleWordListKeyDown(ASender: TObject; var Key: Word; Shift: TShiftState);
procedure HandleHideWordList(var AMsg); overload; message MSG_HIDEWORDLIST;
procedure HandleHideWordList; overload;
procedure SetWordListHeight(const Value: Integer);
procedure SetWordListWidth(const Value: Integer); procedure RegainFocus;
protected
procedure ShowWordList(AWords: TStrings);
procedure HideWordList;
procedure Change; override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure DoExit; override;
public
constructor Create(AOwner: TComponent); override;
published
property WordListHeight: Integer read FWordListHeight write SetWordListHeight;
property WordListWidth: Integer read FWordListWidth write SetWordListWidth;
end; TAutocompleteMan=class
private
FWords: TStrings;
public
constructor Create;
destructor Destroy; override; function IsRecognized(AWord: string): Boolean; overload;
function IsRecognized(AWord: string; AWordList: TStrings): Boolean; overload; procedure LoadFromFile(const AFilename: string);
procedure AddWord(const AWord: string); property Words: TStrings read FWords;
end; procedure Register; var
AutocompleteMan: TAutocompleteMan; implementation procedure Register;
begin
RegisterComponents('CodeCall', [TAutocompleteEdit]);
end; { TAutocompleteMan } procedure TAutocompleteMan.AddWord(const AWord: string);
begin
FWords.Add(UpperCase(AWord) + '=' + AWord);
end; constructor TAutocompleteMan.Create;
begin
FWords := TStringList.Create;
TStringList(FWords).Duplicates := dupIgnore;
end; destructor TAutocompleteMan.Destroy;
begin
FWords.Free;
inherited;
end; function TAutocompleteMan.IsRecognized(AWord: string): Boolean;
var
i: Integer;
begin
Result := False;
AWord := UpperCase(AWord);
for i := to FWords.Count- do
begin
Result := System.Pos(AWord, FWords.Names[i]) > ;
if Result then
Break;
end;
end; function TAutocompleteMan.IsRecognized(AWord: string;
AWordList: TStrings): Boolean;
var
i: Integer;
begin
Result := False;
AWord := UpperCase(AWord);
AWordList.Clear;
for i := to FWords.Count- do
begin
if System.Pos(AWord, FWords.Names[i]) > then
begin
Result := True;
AWordList.Add(FWords.ValueFromIndex[i]);
end;
end;
end; procedure TAutocompleteMan.LoadFromFile(const AFilename: string);
var
i: Integer;
F: TStrings;
begin
F := TStringList.Create;
try
F.LoadFromFile(AFilename);
for i := to F.Count- do
AddWord(F[i]);
finally
F.Free;
end;
end; { TAutocompleteEdit } 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; procedure TAutocompleteEdit.HandleHideWordList(var AMsg);
begin
HandleHideWordList;
end; constructor TAutocompleteEdit.Create(AOwner: TComponent);
begin
inherited;
FWordListHeight := ;
end; procedure TAutocompleteEdit.DoExit;
begin
if Assigned(FWordList) and FWordList.Visible and not FWordList.Focused then
HideWordList;
inherited;
end; procedure TAutocompleteEdit.HandleHideWordList;
begin
FWordList.Free;
FWordList := nil;
end; procedure TAutocompleteEdit.HandleWordListKeyDown(ASender: TObject;
var Key: Word; Shift: TShiftState);
begin
if (Key=VK_UP) and (FWordList.ItemIndex=) then
RegainFocus;
end; procedure TAutocompleteEdit.HandleWordListKeyPress(Sender: TObject;
var Key: Char);
begin
case Key of
#: begin
Key := #;
Self.Text := FWordList.Items[FWordList.ItemIndex];
Self.SetFocus;
Self.SelStart := Length(Self.Text);
Self.SelLength := ;
HideWordList;
end;
#: begin
RegainFocus;
HideWordList;
end;
else begin
RegainFocus;
end;
end;
end; procedure TAutocompleteEdit.HandleWordListLostFocus(ASender: TObject);
begin
if not Self.Focused then
HideWordList;
end; procedure TAutocompleteEdit.HandleWordListSelectItem(ASender: TObject);
begin
Self.Text := FWordList.Items[FWordList.ItemIndex];
HideWordList;
end; procedure TAutocompleteEdit.HideWordList;
begin
PostMessage(Self.Handle, MSG_HIDEWORDLIST, , );
end; 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 < then
FWordList.ItemIndex := ;
end
else
inherited;
end; procedure TAutocompleteEdit.RegainFocus;
begin
Self.SetFocus;
Self.SelStart := FCaretPos;
Self.SelLength := ;
end; procedure TAutocompleteEdit.SetWordListHeight(const Value: Integer);
begin
if FWordListHeight <> Value then
begin
FWordListHeight := Value;
if Assigned(FWordList) then
FWordList.Height := FWordListHeight;
end;
end; procedure TAutocompleteEdit.SetWordListWidth(const Value: Integer);
begin
if FWordListWidth <> Value then
begin
FWordListWidth := Value;
if Assigned(FWordList) then
begin
if FWordListWidth < then
FWordList.Width := Self.Width
else
FWordList.Width := FWordListWidth;
end;
end;
end; 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 < 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; initialization
AutocompleteMan := TAutocompleteMan.Create; finalization
AutocompleteMan.Free;
end.
Autocomplete TEdit的更多相关文章
- autocomplete的使用
autocomplete使用分为本地调用方法和读取远程读取数据源的方法 (1)本地调用方法 <script src="Scripts/jquery-1.4.1.min.js" ...
- 原生js实现autocomplete插件
在实际的项目中,能用别人写好的插件实现相关功能是最好不过,为了节约时间成本,因为有的项目比较紧急,没充分时间让你自己来写,即便写了,你还要花大量时间调试兼容性.但是出于学习的目的,你可以利用闲暇时间, ...
- jQuery ui autocomplete 与easyUI冲突解决办法(重命名ui的autocomplete 和menu部分)
http://jqueryui.com/download/ UI定制只选autocomplete 会自动把依赖的menu模块也加入进来--然而easyUI也有自己的menu,于是就-- 折腾了好久 ...
- AutoComplete
aspx页面 需要引用的文件: <link rel="stylesheet" type="text/css" href="css/jquery. ...
- Bootstrap 中的 Typeahead 组件 -- AutoComplete
Bootstrap 中的 Typeahead 组件就是通常所说的自动完成 AutoComplete,功能很强大,但是,使用上并不太方便.这里我们将介绍一下这个组件的使用. 第一,简单使用 首先,最简单 ...
- Delphi控件之---UpDown以及其与TEdit的配合使用(比如限制TEdit只能输入数字,还有Object Inspector之组件属性的介绍)
最近在开发中使用到了UpDown这个控件,但是因为之前没有使用过,所以很不熟悉,于是就编写了一个简单的demo来学习UpDown以及其结合TEdit的用法. 初步的常用功能的简介 目前(2015.08 ...
- smartComplete——轻量级的autoComplete插件,开源
项目后端觉得autoComplete响应略慢,于是花了两天时间写了这插件,基于jQuery 1.7+,仓库地址 https://github.com/VaJoy/smartComplete ,欢迎各种 ...
- Autocomplete 自动补全(Webform实战篇)
开篇语 因为项目中需要用到一个自动补全的功能,功能描述: 需求一:新增收件人的时候,自动下拉显示出数据库中所有的收件人信息(显示的信息包括:姓名-收件地址-联系方式) 需求二:选中一个值得时候,分别赋 ...
- jQuery AutoComplete在AJAX UpdatePanel环境中PostBack之后无法工作
前些日子,Insus.NET有实现<ASP.NET MVC使用jQuery实现Autocomplete>http://www.cnblogs.com/insus/p/5638895.htm ...
随机推荐
- Tutorial 2: Requests and Responses
转载自:http://www.django-rest-framework.org/tutorial/2-requests-and-responses/ Tutorial 2: Requests and ...
- [ python ] 线程的操作
目录 (见右侧目录栏导航) - 1. 前言 - 1.1 进程 - 1.2 有了进程为什么要有线程 - 1.3 线程的出现 - 1.4 进程和线程的关系 - 1.5 线程的 ...
- java中常见异常汇总(根据自己遇到的异常不定时更新)
1.java.lang.ArrayIndexOutOfBoundsException:N(数组索引越界异常.如果访问数组元素时指定的索引值小于0,或者大于等于数组的长度,编译程序不会出现任何错误,但运 ...
- 20165301 2017-2018-2 《Java程序设计》第四周学习总结
20165301 2017-2018-2 <Java程序设计>第四周学习总结 教材学习内容总结 第五章:子类与继承 一个类只能有一个父类,但是可以有若干个子类. 子类的继承性 子类和父类在 ...
- HBase 入门笔记-安装篇
一.前言 接触HBase已近半年,从一无所知到问题的解决,在数据落地方面也有了一定的了解,在此记录这半年来碰到的一些问题和对一些数据落地方面的见解,本篇主要介绍一下hbase安装方面的信息 二.安装环 ...
- 【hdoj_2100】Lovekey(大数+字符处理)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2100 根据题目意思,现将字符串转化为10进制,再采用10进制加法相加,再转化为26进制. 另一种直接的思路 ...
- Codeigniter的一些优秀实践
最近准备接手改进一个别人用Codeigniter写的项目,虽然之前也有用过CI,但是是完全按着自己的意思写的,没按CI的一些套路.用在公众的项目,最好还是按框架规范来,所以还是总结一下,免得以后别人再 ...
- bitbucket SSH 生成
在bitbucket设置ssh的方法: 1.运行ssh-keygen. 2.一路enter,直接到结束. 3 seeting 中Bitbucket选择.ssh/id_rsa.pub文件
- 借助svn进行半自动多台服务器上线部署
传统简单保留 如果web服务器就那么几台,大致可以在测试服务器上测试好以后,直接在正式的web服务器 压缩拷贝一个,然后再覆盖下,进行简单暴力的发布. 这种纯手工发布往往会带来几个问题 压缩一不小心把 ...
- 木块问题(UVa101)
题目具体描述见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob ...