自动完成简介 大家一定都非常熟悉IE浏览器的地址输入编辑框它提供了自动完成的功能自动完成(Auto Complete)功能简化了编辑框的输入功能它可以根据已经输入的部分字符串进行预测和匹配图的例子演示了自动完成可以依据输入的pro给出Pascal的保留字中与其相匹配的字符串列表procedureprogramproperty
在利用自动完成功能前必须要知道自动完成并不是任意版本的Windows都支持自动完成功能实际上是由Internet Explorer 引入并必须有版及以上的Shelldll的支持很多早期的系统包括很多安装了IE 的系统并不支持这项特性所以使用自动完成功能时必须确保要安装的系统支持这项功能如果不支持就需要安装IE和集成外壳
自动完成功能是通过一组COM接口来实现的这些接口使我们可以连接自动完成到编辑框添加编辑框可以枚举的字符串列表并配置其显示属性
自动完成的用途
使用自动完成功能可以增强程序的易用性它可以节省用户反复输入一些常用字符串的时间并减少输入错误它还可以用于部分字符匹配的查找系统可以用它实现对数据库内容的快速查找另外它还支持向浏览器历史最近运行程序和外壳目录输入等功能中添加自定义的完成列表
配置自动完成
需要知道的是在Delphi里并没有提供自动完成功能相关COM接口的pascal声明单元由于一般这类接口在微软都是以C语言的头文件形式提供接口Delphi不可能及时提供最新的相应的Pascal包装单元所以为了使用这项功能本文中额外提供了一个shlintf单元翻译了相应的头文件的声明下表总结了Shlintf的内容
COM对象接 口CLSID_AutoCompleteIAutoCompleteCLSID_ACLHistoryIAutoComplete
CLSID_ACListISFIACListCLSID_ACLMRUIACList
CLSID_ACLMultiICurrentWorkingDirectoryIObjMgr
自动完成功能最基本的一个接口就是IAutoComplete接口它的声明如下
type
IAutoComplete = interface(IUnknown)
[SID_IAutoComplete]
function Init(hwndEdit: HWND; punkACL: IUnknown; pwszRegKeyPath: PWideChar;
pwszQuickComplete: PWideChar): HResult; stdcall;
function Enable(fEnable: Boolean): HResult; stdcall;
end;
IautoComplete接口有两个方法Init和Enable
Init方法用来把IAutoComple接口以及自动完成列表同编辑框相连接参数pwszRegKeyPath和pwszQuickComplete使得IAutoComplete接口可以按预定义的格式扩展部分输入的字符串快捷键为CTRL+ENTER比如设定pwszQuickComplete为http://www%scn/后当用户输入csai 到编辑框并按下快捷键CTRL+ENTER编辑框中的文本就会更新为http://wwwcsaicn/
Enable方法是根据fEnable标识来切换自动完成功能的开关状态的缺省时是激活的
下图显示了IAutoComplete接口是如何自动完成字符串的当用户在编辑框中输入字符时一种可能是最能匹配已经输入字符串的候选字符会被反白显示
回过头再来看看Init方法的punkACL参数它是一个必须的参数而且必须指向一个提供字符串的接口注意不是我们熟悉的Delphi中提供的TStrings对象而是一个IEnumString字符串接口IEnumString接口负责生成一个用于自动完成的候选字符串列表除了IEnumString接口外punkACL参数还可以是IACList和IACList等其他接口
IACList接口简单地说就是可以对候选字符串分类来改善自动完成的效率本文中将不加介绍
要注意的是Microsoft并没有停止对自动完成功能的改进在Internet Explorer 中Microsoft 还提供了IAutoComplete接口IAutoComplete接口进行了进一步的扩展它使得我们可以设定一系列的选项来设定自动完成的可视化表达以及操作下面是 IAutoComplete接口的声明
type
IAutoComplete = interface(IAutoComplete)
[SID_IAutoComplete]
function SetOptions(dwFlag: DWORD): HResult; stdcall;
function GetOptions(out dwFlag: DWORD):HResult; stdcall;
end;
IAutoComplete接口引入了两种新的方法这两种方法使用同样的标识组合作为参数下表列出了可用的标识及其意义
标 识说 明ACO_NONE不使用自动完成ACO_AUTOSUGGEST使用下拉列表ACO_AUTOAPPEND允许自动附加在init方法中pwszQuickComplete参数所代表的字符串ACO_SEARCH在下拉列表最后添加
查找
文本ACO_FILTERPREFIXES防止自动完成匹配常用前缀比如
www
http://
等ACO_USETABTAB键可以用来选择下拉列表项ACF_UPDOWNKEYDROPSLIST上下按键可以用来调出下拉列表框ACO_RTLREADING按由右到左的顺序读
就像下图所显示的那样IAutoComplete同IAutoComplete的显示方式有一点不同就是因为IAutoComplete支持不同的显示模式这些模式可以通过SetOptions 方法来设定
实现自动完成
自动完成功能是通过COM对象来实现的下面代码用As操作符来获得IAutoComplete接口
FAutoComplete :=
CreateComObject(CLSID_AutoComplete) as IAutoComplete;
获得接口后我们就可以实现自动完成功能了下面代码是一个简单的例子
unit Main;
interface
uses
Windows Messages SysUtils Classes Graphics
Controls Forms Dialogs ShlIntf ActiveX
ComObj StdCtrls StrTools;
type
TAutoCompleteForm = class(TForm)
CompletionEdit: TEdit;
CompletionLabel: TLabel;
SourceGroupBox: TGroupBox;
SourceMemo: TMemo;
procedure FormCreate(Sender: TObject);
private
FAutoComplete: IAutoComplete;
FStrings: IUnknown;
end;
var
AutoCompleteForm: TAutoCompleteForm;
implementation
{$R *DFM}
{ TAutoCompleteForm }
procedure TAutoCompleteFormFormCreate(Sender: TObject);
begin
FAutoComplete := CreateComObject(CLSID_AutoComplete) as IAutoComplete;
FStrings := TEnumStringCreate(SourceMemoLines) as IUnknown;
OleCheck(FAutoCompleteSetOptions(ACO_AUTOSUGGESTor ACO_UPDOWNKEYDROPSLIST));
OleCheck(FAutoCompleteInit(CompletionEditHandle FStrings nil nil));
end;
end
上面的例程首先获得IAutoComplete接口如果系统不支持IAutoComplete接口as操作符将引发EinvalidCastError异常接下来的一行代码会创建一个TEnumString类的实例并取得IUnknown接口这个接口将作为FAutoComplete的Init方法的punkACL参数TEnumString类是从TInterfacedObject类继承的实现在StrTools单元中实现它的目的是使TStrings类同IEnumString接口兼容然后设定显示选项使自动完成支持下拉列表和自动建议最后初始化FAutoComplete并同编辑框相连接被连接的编辑框就支持自动完成了
标准自动完成列表
除了支持标准的编辑框的自动完成Microsoft还允许通过下表中的一组COM对象来存取标准自动完成列表
COM对象说 明CLSID_History允许存取历史列表项CLSID_ACListISF允许操作外壳命名空间的内容CLSID_MRU提供最近运行过的程序列表
上面列出的COM对象提供了一个IUnknown接口接口可以作为IAutoComplete接口的Init方法的punkACL参数每个IUnknown接口都支持IEnumString和IACList接口同时还支持其他特殊接口比如外壳空间的IUnknown接口还公开了ICurrentWorkingDirectory和IPersistFolder接口使用这些对象可以根据外壳空间的变化动态地改变候选字符串列表
ICurrentWorkingDirectory和IPersistFolder接口的区别在于IPersistFolder使用item lists 而不是字符串Item lists 便于存取虚拟文件夹比如控制面板
下面的代码演示了如何使用自动完成功能来设定C:\下的外壳内容为候选字符串列表
var
WorkingDirectory: ICurrentWorkingDirectory;
begin
FAutoComplete := CreateComObject(CLSID_AutoComplete) as IAutoComplete;
FStrings := CreateComObject(CLSID_ACListISF);
WorkingDirectory := FStrings as ICurrentWorkingDirectory;
OleCheck(WorkingDirectorySetDirectory(C:\));
OleCheck(FAutoCompleteSetOptions(ACO_AUTOSUGGEST or ACO_UPDOWNKEYDROPSLIST));
OleCheck(FAutoCompleteInit(CompletionEditHandle FStrings nil nil));
end;
改进自动完成虽然自动完成功能实现起来很简单但为了更好在Delphi中使VCL框架一致应该创建对它的VCL封装另外的改进应该是要提供对其他嵌入编辑框的控件的自动完成功能的实现如下图TAutoComplete组件被连接到了一个TtreeView控件上
总的来说自动完成功能是一项非常棒的功能它可以简化用户同经常输入的文本交互的过程用好自动完成功能会使得你的程序显得很专业