powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / TcxTextEdit с AutoComplete как у Яндекса (Исходник)
5 сообщений из 5, страница 1 из 1
TcxTextEdit с AutoComplete как у Яндекса (Исходник)
    #39476612
Valery_B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Решил создать свой TextEdit с AutoComplete по некой аналогии с Яндексом.
Поиск всегда происходит по содержимому строки, а не только по её началу.

Так же добавил новый Event - OnDelayedChange
Это аналог OnChage, только срабатывает через 750 милисекунд после последнего изменения.
Обычно, используется что бы дождаться окончательного ввода данных, и сработать 1 раз, а не при каждом изменении.

ДропДаун взял из ACComboBox, который я когда-то скачал в интернете. Если честно, не помню от куда.

Пример
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
procedure TForm1.FormCreate(Sender: TObject);
var
 AC:TAutoCompleteTextEdit;
begin
 AC:=TAutoCompleteTextEdit.Create(Self);
 AC.Parent:=Self;
 AC.Width:=300;
 AC.OnDelayedChange:=OnDelayedChange;
 AC.Items.Add('Автоперевозки');
 AC.Items.Add('Высокоскоростная автомагистраль');
 AC.Items.Add('Коробка автоматического переключения передач');
 AC.Items.Add('Обязательное страхование гражданской автоответственности (ОСАГО)');
 AC.Items.Add('Полуавтомат');
 AC.Items.Add('Полупулемёт');
 AC.Items.Add('Автомат Калашникова');
 AC.Items.Add('Помидор');
 AC.Items.Add('Огурец');
 AC.Items.Add('Картофель');
end;

procedure TForm1.OnDelayedChange(Sender: TObject);
begin
 Label1.Caption:= (Sender as TAutoCompleteTextEdit).Text;
end;

CustomControl.AutoCompleteTextEdit.pas

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
unit CustomControl.AutoCompleteTextEdit;

interface

uses SysUtils, Windows, Messages, Classes, Controls, StdCtrls, cxTextEdit,
     cxDBEdit, ExtCtrls, CustomControl.AutoCompleteDropDown;


type
  TOnShowDropDownEvent = procedure (Sender:TObject; ItemsToShow:TStrings) of object;

  TAutoCompleteTextEdit = class(TcxTextEdit, IHaveDropDown)
  private
    FDropped: Boolean;
    FApplyingText:Boolean;
    FItems: TStringList;
    FOnShowDropDown: TOnShowDropDownEvent;
    FMaxDropDownItems: Integer;
    FOnDelayedChange: TNotifyEvent;
    FTimer:TTimer;
    FLastTick:Int64;
    FDelayChangeInterval: Word;
    procedure InternalShowDropDown(Count:Integer);
    procedure InternalCreateTimer;
    procedure SetOnDelayedChange(const Value: TNotifyEvent);
  protected
    FDropDown: TDropDownListBox;
    procedure TryHandleUserInput;
    procedure WMMouseWheel(var M: TWMMouseWheel); message WM_MOUSEWHEEL;
    procedure CMExit(var M: TCMExit); message CM_EXIT;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    function PrepareACStrings(const AText: String):Integer; virtual;
    procedure SendKeyToDropDown(var Key:Word);
    procedure DoChange; override;
    procedure DoOnShowDropDown; virtual;
    procedure DoOnDelayedChange; virtual;
    procedure HandleTimer(Sender:TObject);
    function GetInnerEditClass: TControlClass;override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ShowDropDown;
    procedure HideDropDown(ApplyText:Boolean);
    procedure FinishTimer;
    property Dropped:Boolean read FDropped;
  published
    property Items: TStringList read FItems;
    property DelayChangeInterval:Word read FDelayChangeInterval write FDelayChangeInterval;
    property MaxDropDownItems:Integer read FMaxDropDownItems write FMaxDropDownItems;
    property OnShowDropDown:TOnShowDropDownEvent read FOnShowDropDown write FOnShowDropDown;
    property OnDelayedChange:TNotifyEvent read FOnDelayedChange write SetOnDelayedChange;
  end;


implementation

type
 TInterceptKeyTextEdit = class(TcxCustomInnerTextEdit) //Для перехвата ENTER в модальном окне с TButton.Defualt:=True
  private
    procedure CNKeyDown(var Message: TWMKeyDown); message CN_KEYDOWN;
    function OwnerHasDropDownOpened:Boolean;
 end;

{ TInterceptKeyTextEdit }
procedure TInterceptKeyTextEdit.CNKeyDown(var Message: TWMKeyDown);
begin
  if OwnerHasDropDownOpened=False then
   inherited;
end;

function TInterceptKeyTextEdit.OwnerHasDropDownOpened: Boolean;
begin
 Result:=(Owner is TAutoCompleteTextEdit) and (Owner as TAutoCompleteTextEdit).Dropped=True;
end;

{ TAutoCompleteTextEdit }
procedure TAutoCompleteTextEdit.CMExit(var M: TCMExit);
begin
 inherited;
 HideDropDown(False);
end;

constructor TAutoCompleteTextEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDropDown:=TDropDownListBox.Create(Self);
  FItems:=TStringList.Create;
  DelayChangeInterval:=750;
  FDropped:=False;
  FApplyingText:=False;
  MaxDropDownItems:=7;
end;

destructor TAutoCompleteTextEdit.Destroy;
begin
 FItems.Free;
 inherited Destroy;
end;

procedure TAutoCompleteTextEdit.DoChange;
begin
 inherited DoChange;
 TryHandleUserInput;
 if FApplyingText=False then
  ShowDropDown;
end;

procedure TAutoCompleteTextEdit.DoOnShowDropDown;
begin
 if Assigned(OnShowDropDown) then
  OnShowDropDown(Self,FDropDown.Items);
end;

procedure TAutoCompleteTextEdit.DoOnDelayedChange;
begin
 If Assigned(FTimer)then FTimer.Enabled:=False;
 If Assigned(OnDelayedChange) then
  OnDelayedChange(Self);
end;

function TAutoCompleteTextEdit.GetInnerEditClass: TControlClass;
begin
 Result:=TInterceptKeyTextEdit;
end;

procedure TAutoCompleteTextEdit.HandleTimer(Sender: TObject);
begin
 if (GetTickCount >= FLastTick+DelayChangeInterval) and (Dropped=False) and Enabled then
  DoOnDelayedChange;
end;

procedure TAutoCompleteTextEdit.HideDropDown(ApplyText: Boolean);
var
 I: Integer;
begin
ShowWindow(FDropDown.Handle, SW_HIDE);
if ApplyText then
  begin
  I:=FDropDown.ItemIndex;
  if I<>-1 then
    begin
     FApplyingText:=True;
     Text:=FDropDown.Items[I];
     FApplyingText:=False;
     SelStart:=Length(Text);
     SelLength:=Length(Text);
    end;
  end;
FDropped:=False;
end;

procedure TAutoCompleteTextEdit.InternalShowDropDown(Count:Integer);
var
 P:TPoint;
begin
 If Count>MaxDropDownItems then
  Count:=MaxDropDownItems;
  FDropped:=True;
  P.X:=1;
  P.Y:=Height-1;
  P:=ClientToScreen(P);
  SetWindowPos(FDropDown.Handle, HWND_TOPMOST, P.X, P.Y, Width-GetSystemMetrics(SM_CXVSCROLL)-2, Count*FDropDown.ItemHeight+2, SWP_SHOWWINDOW);
end;

procedure TAutoCompleteTextEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
if (FDropped) then
 case Key of
  VK_ESCAPE: HideDropDown(False);
  VK_RETURN: HideDropDown(True);
  VK_UP, VK_DOWN, VK_NEXT, VK_PRIOR: SendKeyToDropDown(Key);
  else
   inherited KeyDown(Key, Shift);
 end
  else
 inherited KeyDown(Key, Shift)
end;

procedure TAutoCompleteTextEdit.KeyPress(var Key: Char);
begin
if ((Ord(Key)=VK_RETURN) or (Ord(Key)=VK_ESCAPE)) then
 Key:=#0;
inherited KeyPress(Key);
end;


function TAutoCompleteTextEdit.PrepareACStrings(const AText: String):Integer;
var
 x: Integer;
begin
  FDropDown.Items.Clear;
  for x:=0 to FItems.Count-1 do
   If Pos(AnsiLowerCase(AText), AnsiLowerCase(FItems[x]))>0 then
    FDropDown.Items.Add(FItems[x]);
  DoOnShowDropDown;
  Result:= FDropDown.Items.Count;
end;

procedure TAutoCompleteTextEdit.SendKeyToDropDown(var Key: Word);
var
 M: TWMKeyDown;
begin
  FillChar(M, SizeOf(M), 0);
  M.Msg:=WM_KEYDOWN;
  M.CharCode:=Key;
  SendMessage(FDropDown.Handle, TMessage(M).Msg, TMessage(M).WParam, TMessage(M).LParam);
  FillChar(M, SizeOf(M), 0);
  M.Msg:=WM_KEYUP;
  M.CharCode:=Key;
  SendMessage(FDropDown.Handle, TMessage(M).Msg, TMessage(M).WParam, TMessage(M).LParam);
  Key:=0;
end;

procedure TAutoCompleteTextEdit.ShowDropDown;
begin
if (Text='') or (PrepareACStrings(Text)=0) then
  HideDropDown(False)
   else
  InternalShowDropDown(FDropDown.Items.Count);
end;

procedure TAutoCompleteTextEdit.TryHandleUserInput;
begin
 FLastTick:=GetTickCount;
 if Assigned(FTimer) then
  FTimer.Enabled:=Assigned(OnDelayedChange);
end;

procedure TAutoCompleteTextEdit.WMMouseWheel(var M: TWMMouseWheel);
begin
 TMessage(M).Result:=SendMessage(FDropDown.Handle, TMessage(M).Msg, TMessage(M).WParam, TMessage(M).LParam);
 FDropDown.UpdateItemIndex
end;

procedure TAutoCompleteTextEdit.FinishTimer;
begin
 If Assigned(FTimer) and (FTimer.Enabled) then
  begin
   FTimer.Enabled:=False;
   DoOnDelayedChange;
  end;
end;

procedure TAutoCompleteTextEdit.InternalCreateTimer;
begin
If not Assigned(FTimer) then
 begin
  FTimer:=TTimer.Create(Self);
  FTimer.OnTimer:=HandleTimer;
  FTimer.Interval:=500;
  FTimer.Enabled:=False;
  FLastTick:=GetTickCount;
 end; 
end;

procedure TAutoCompleteTextEdit.SetOnDelayedChange(const Value: TNotifyEvent);
begin
  FOnDelayedChange := Value;
  If Assigned(Value) then
   InternalCreateTimer;
end;

end.


CustomControl.AutoCompleteDropDown.pas

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
unit CustomControl.AutoCompleteDropDown;

interface
uses SysUtils, Windows, Messages, Classes, Controls, StdCtrls, Forms;

type
  IHaveDropDown = interface
    ['{DB4435AC-3B5A-4541-9C7E-37A42202CC9C}']
    procedure ShowDropDown;
    procedure HideDropDown(ApplyText:Boolean);
  end;

  TDropDownListBox = class(TListBox)
  protected
    procedure WMActivateApp(var M: TMessage); message WM_ACTIVATEAPP;
    procedure WMMouseMove(var M: TWMMouseMove); message WM_MOUSEMOVE;
    procedure WMLButtonUp(var M: TWMLButtonUp); message WM_LBUTTONUP;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure HideDropDown(ApplyText:Boolean);
  public
    procedure UpdateItemIndex;
  end;

implementation

procedure TDropDownListBox.HideDropDown(ApplyText:Boolean);
begin
 if Assigned(Owner) and Supports(Owner,IHaveDropDown) and (Visible)then
    (Owner as IHaveDropDown).HideDropDown(True);
end;

procedure TDropDownListBox.UpdateItemIndex;
var
 P: TPoint;
 I: Integer;
begin
 GetCursorPos(P);
 P:=ScreenToClient(P);
 I:=ItemAtPos(P, True);
 if I<>-1 then
  ItemIndex:=I;
end;

procedure TDropDownListBox.WMLButtonUp(var M: TWMLButtonUp);
begin
inherited;
 if (ItemIndex<>-1) then
  HideDropDown(True);
end;

procedure TDropDownListBox.WMMouseMove(var M: TWMMouseMove);
begin
 inherited;
 UpdateItemIndex;
end;

procedure TDropDownListBox.CreateParams(var Params: TCreateParams);
begin
 inherited CreateParams(Params);
 Params.ExStyle:=WS_EX_TOOLWINDOW;
 Params.WndParent:=GetDesktopWindow;
 Params.Style:=WS_CHILD or WS_BORDER or WS_CLIPSIBLINGS or WS_OVERLAPPED or WS_VSCROLL or LBS_NOINTEGRALHEIGHT;
end;

procedure TDropDownListBox.WMActivateApp(var M: TMessage);
begin
 inherited;
 HideDropDown(False);
end;

end.


...
Рейтинг: 0 / 0
TcxTextEdit с AutoComplete как у Яндекса (Исходник)
    #39476613
schi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дел на 15 минут со стандартными элементами. Еще можно искать с учетом вариантов различной раскладки.
...
Рейтинг: 0 / 0
TcxTextEdit с AutoComplete как у Яндекса (Исходник)
    #39476615
Valery_B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
schiДел на 15 минут со стандартными элементами. Еще можно искать с учетом вариантов различной раскладки.
Ок. Сделай.
Через 15 минут посмотрю.
...
Рейтинг: 0 / 0
TcxTextEdit с AutoComplete как у Яндекса (Исходник)
    #39476709
schi
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Valery_BschiДел на 15 минут со стандартными элементами. Еще можно искать с учетом вариантов различной раскладки.
Ок. Сделай.
Через 15 минут посмотрю.

Я уже сделал и использую. Давно.
...
Рейтинг: 0 / 0
TcxTextEdit с AutoComplete как у Яндекса (Исходник)
    #39476730
Cobalt747
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Valery_B,

Автор, вы хвастаетесь или жалуетесь?
...
Рейтинг: 0 / 0
5 сообщений из 5, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / TcxTextEdit с AutoComplete как у Яндекса (Исходник)
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]