zoukankan      html  css  js  c++  java
  • 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

    1. Upon typing some chars, TAutocompleteEdit will check the typed word agains a word list. When no match found, do nothing.
    2. When one or more matches found, TAutocompleteEdit show the matches in a TListBox.We will call this TListBoxWordList.
    3. User can move between TAutocompleteEdit and WordList using down and up arrow.
    4. User select a complete word from WordList by highlighting the word and press Enter key.
    5. After user selected a word, the word will replace whatever content in TAutocompleteEdit.
    6. If user press Escape in TAutocompleteEdit or in WordList, WordList must dissapear.
    7. If TAutocompleteEdit lost focus, and the new focus is not in WordList, WordList must dissapear.
    8. If WordList lost focus, and the new focus is not in TAutocompleteEdit, WordList must dissapear.
    9. 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.

    1. 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.
    2. HideWordList.
      This method is responsible to hide and clean up WordList.
    3. 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.
    4. 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.
    5. 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 begin
    100   Result := False;
    101   AWord := UpperCase(AWord);
    102   for i := 0 to FWords.Count-1 do
    103   begin
    104     Result := System.Pos(AWord, FWords.Names[i]) > 0;
    105     if Result then
    106       Break;
    107   end;
    108 end;
    109 
    110 function TAutocompleteMan.IsRecognized(AWord: string;
    111   AWordList: TStrings): Boolean;
    112 var
    113   i: Integer;
    114 begin
    115   Result := False;
    116   AWord := UpperCase(AWord);
    117   AWordList.Clear;
    118   for i := 0 to FWords.Count-1 do
    119   begin
    120     if System.Pos(AWord, FWords.Names[i]) > 0 then
    121     begin
    122       Result := True;
    123       AWordList.Add(FWords.ValueFromIndex[i]);
    124     end;
    125   end;
    126 end;
    127 
    128 procedure TAutocompleteMan.LoadFromFile(const AFilename: string);
    129 var
    130   i: Integer;
    131   F: TStrings;
    132 begin
    133   F := TStringList.Create;
    134   try
    135     F.LoadFromFile(AFilename);
    136     for i := 0 to F.Count-1 do
    137       AddWord(F[i]);
    138   finally
    139     F.Free;
    140   end;
    141 end;
    142 
    143 { TAutocompleteEdit }
    144 
    145 procedure TAutocompleteEdit.Change;
    146 var
    147   S: TStrings;
    148 begin
    149   inherited;
    150   if AutocompleteMan.IsRecognized(Self.Text) then
    151   begin
    152     S := TStringList.Create;
    153     try
    154       if AutocompleteMan.IsRecognized(Self.Text, S) then
    155         ShowWordList(S);
    156     finally
    157       S.Free;
    158     end;
    159   end
    160   else
    161     HideWordList;
    162 end;
    163 
    164 procedure TAutocompleteEdit.HandleHideWordList(var AMsg);
    165 begin
    166   HandleHideWordList;
    167 end;
    168 
    169 constructor TAutocompleteEdit.Create(AOwner: TComponent);
    170 begin
    171   inherited;
    172   FWordListHeight := 60;
    173 end;
    174 
    175 procedure TAutocompleteEdit.DoExit;
    176 begin
    177   if Assigned(FWordList) and FWordList.Visible and not FWordList.Focused then
    178     HideWordList;
    179   inherited;
    180 end;
    181 
    182 procedure TAutocompleteEdit.HandleHideWordList;
    183 begin
    184   FWordList.Free;
    185   FWordList := nil;
    186 end;
    187 
    188 procedure TAutocompleteEdit.HandleWordListKeyDown(ASender: TObject;
    189   var Key: Word; Shift: TShiftState);
    190 begin
    191   if (Key=VK_UP) and (FWordList.ItemIndex=0) then
    192     RegainFocus;
    193 end;
    194 
    195 procedure TAutocompleteEdit.HandleWordListKeyPress(Sender: TObject;
    196   var Key: Char);
    197 begin
    198   case Key of
    199     #13: begin
    200            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: begin
    208            RegainFocus;
    209            HideWordList;
    210          end;
    211     else begin
    212       RegainFocus;
    213     end;
    214   end;
    215 end;
    216 
    217 procedure TAutocompleteEdit.HandleWordListLostFocus(ASender: TObject);
    218 begin
    219   if not Self.Focused then
    220     HideWordList;
    221 end;
    222 
    223 procedure TAutocompleteEdit.HandleWordListSelectItem(ASender: TObject);
    224 begin
    225   Self.Text := FWordList.Items[FWordList.ItemIndex];
    226   HideWordList;
    227 end;
    228 
    229 procedure TAutocompleteEdit.HideWordList;
    230 begin
    231   PostMessage(Self.Handle, MSG_HIDEWORDLIST, 0, 0);
    232 end;
    233 
    234 procedure TAutocompleteEdit.KeyDown(var Key: Word; Shift: TShiftState);
    235 begin
    236   if Key=VK_ESCAPE then
    237     HideWordList
    238   else if (Key=VK_DOWN) and Assigned(FWordList) and FWordList.Visible then
    239   begin
    240     FCaretPos := Self.SelStart;
    241     FWordList.SetFocus;
    242     if FWordList.ItemIndex < 0 then
    243       FWordList.ItemIndex := 0;
    244   end
    245   else
    246     inherited;
    247 end;
    248 
    249 procedure TAutocompleteEdit.RegainFocus;
    250 begin
    251   Self.SetFocus;
    252   Self.SelStart := FCaretPos;
    253   Self.SelLength := 0;
    254 end;
    255 
    256 procedure TAutocompleteEdit.SetWordListHeight(const Value: Integer);
    257 begin
    258   if FWordListHeight <> Value then
    259   begin
    260     FWordListHeight := Value;
    261     if Assigned(FWordList) then
    262       FWordList.Height := FWordListHeight;
    263   end;
    264 end;
    265 
    266 procedure TAutocompleteEdit.SetWordListWidth(const Value: Integer);
    267 begin
    268   if FWordListWidth <> Value then
    269   begin
    270     FWordListWidth := Value;
    271     if Assigned(FWordList) then
    272     begin
    273       if FWordListWidth < 1 then
    274         FWordList.Width := Self.Width
    275       else
    276         FWordList.Width := FWordListWidth;
    277     end;
    278   end;
    279 end;
    280 
    281 procedure TAutocompleteEdit.ShowWordList(AWords: TStrings);
    282 begin
    283   if FWordList=nil then
    284   begin
    285     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 then
    297     FWordList.SetBounds(Self.Left, Self.Top + Self.Height, Self.Width, FWordListHeight)
    298   else
    299     FWordList.SetBounds(Self.Left, Self.Top + Self.Height, FWordListWidth, FWordListHeight);
    300 
    301   FWordList.Show;
    302 end;
    303 
    304 initialization
    305   AutocompleteMan := TAutocompleteMan.Create;
    306 
    307 finalization
    308   AutocompleteMan.Free;
    309 end.
  • 相关阅读:
    RabbitMQ入门(二)工作队列
    RabbitMQ入门之Hello World
    利用JMeter测试Tornado的多线程
    使用SQLAlchemy操作MySQL
    计算斐波那契数列的性能对比:Python,Java,Go
    PyCharm使用之配置SSH Interpreter
    Android数据绑定技术一,企业级开发
    Retrofit网络请求库应用02——json解析
    Servlet与Jsp的结合使用实现信息管理系统二
    Retrofit网络请求库应用01
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4036253.html
Copyright © 2011-2022 走看看