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 ...
随机推荐
- cordova 从xcode7迁移到xcode8
环境以开发流程 当前项目使用的cordova环境 cordova 6.1.1 cordova-ios 3.9.2(vs15自动装的不知道在哪能改,所以考虑升级到vs17,能够手动指定) cordova ...
- 高屋建瓴之WebMail攻与防
0x01:前言 随着互联网的快速发展,我们的生活与互联网的联系愈加的紧密.各种快捷方便的信息化通信工具渐渐取代了传统的通信方式.微博.QQ.MSN.微信.陌陌, …这样的社交软件和平台已经成为了我们生 ...
- 邀请用户进TestFlight 体验 App 的测试版本
iphone手机用户,在工作中常见到,APP版本现在是Beta阶段(iOS版本),需要邀请一些用户来体验新版本,在版本上线前提出更好的建议及时进行修改,此时用到了testflight,很方便的通过邀请 ...
- springcloud 出现unavailable-replicas
springcloud 出现unavailable-replicas 原因: 1. 部分服务不可用 2. 直接使用了ip地址作为hostname application.properties # 不能 ...
- js求连个数之间的数字
整理出自项目中一个需求,求两个数之间的数字. const week = function(arr,arr2){ let a=parseInt(arr); let b=parseInt(arr2); l ...
- SSH整合最简单的一个例子
1.新建mysql数据库 create database spring; 切换数据库 use spring; 新建表 create table user (id int(3) auto_incre ...
- python爬虫实战(四)--------豆瓣网的模拟登录(模拟登录和验证码的处理----scrapy)
在利用scrapy框架爬各种网站时,一定会碰到某些网站是需要登录才能获取信息. 这两天也在学习怎么去模拟登录,通过自己码的代码和借鉴别人的项目,调试成功豆瓣的模拟登录,顺便处理了怎么自动化的处理验证码 ...
- Shiro的鉴权方式
一. 怎么用 Shiro 支持三种方式的授权 编程式:通过写 if/else 授权代码块完成: Subject subject = SecurityUtils.getSubject(); if(sub ...
- openstack首页默认跳转
在/var/www/html新建index.html <html> <head> <meta http-equiv="Content-Language" ...
- HNOI2017滚粗记
DAY0: 高三学长说了考前要么就完全颓废要么就完全学,所以我们就完全开启了颓废模式.上午教练带队去烈士公园游玩,中途机房歌神和QYS一直在谈论如何用LCT动态维护树的直径,ORZORZORZ.... ...