Delete TLabel created in run-time - delphi

How to delete created labels. I tried FindComponent but failed , what I have to do? should I set there parent to other component like TPanel or what?
procedure TForm1.Button1Click(Sender: TObject);
var
lblLink: TLabel;
begin
for i := 0 to stringtList.Count-1 do
begin
lblLink := TLabel.create(self);
with lblLink do
begin
name:='lblLink'+inttostr(i);
caption:inttostr(i);
Parent := self;
font.style := [fsUnderline];
cursor := crHandPoint;
color := clBlue;
font.Color := clBlue;
end;
end;
end;

You can iterate over the Components property, then check for the name of the component and finally free the component.
Var
LIndex : Integer;
LComponent : TComponent;
begin
for LIndex := ComponentCount-1 downto 0 do
if StartsText('lblLink',Components[LIndex].Name) then
begin
LComponent:=Components[LIndex];
FreeAndNil(LComponent);
end;
end;

You don't have to free it. You gave the responsibility to free it to the form with lblLink := TLabel.create(self);. The form will free the label when the form is freed.
However, with that being said, you can free it by looping through the form's Components array:
procedure TForm1.DeleteLabel(const LabelName: string);
var
i: Integer;
begin
for i := ComponentCount - 1 downto 0 do
begin
if Components[i] is TLabel then
if Components[i].Name = LabelName then
begin
Components[i].Free;
Break;
end;
end;
end;

You assigned both an Owner and a Parent to each TLabel, so techncally you do not need to free them at all. Both the Owner and the Parent will handle that for you. However, if you wanted to free them earlier, you could loop through the Owner's Components list or the Parent's Controls list, hunting for the labels manually. A better option is to keep your own list of the labels you create, then you can loop through that list when needed, eg:
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
...
private
Labels: TList;
procedure FreeLabels;
...
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Labels := TList.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Labels.Free;
end;
procedure TForm1.FreeLabels;
var
I: Integer;
begin
for I := 0 to Labels.Count-1 do
TLabel(Labels[I]).Free;
Labels.Clear;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
lblLink : TLabel;
...
begin
...
for I := 0 to StringList.Count-1 do
begin
lblLink := TLabel.Create(Self);
try
with lblLink do
begin
Name := 'lblLink' + IntToStr(i);
Parent := Self;
Caption := IntToStr(i);
Font.Style := [fsUnderline];
Cursor := crHandPoint;
Color := clBlue;
Font.Color := clBlue;
end;
Labels.Add(lblLink);
except
lblLink.Free;
raise;
end;
end;
end;

Related

Self deleting button

I have a TScrollBox with a bunch of TPanels with some TButtons generated at runtime.
I need to delete the TPanel when one TButton is clicked but doing that in OnClick end in an access violation...
procedure TMainForm.ButanClick(Sender: TObject);
var
vParentPanel: TPanel;
begin
if (string(TButton(Sender).Name).StartsWith('L')) then
begin
TButton(Sender).Caption := 'YARE YARE DAZE';
end
else
begin
vParentPanel := TPanel(TButton(Sender).GetParentComponent());
TheScrollBox.RemoveComponent(vParentPanel);
vParentPanel.Destroy();
// access violation but the panel is removed
end;
end;
procedure TMainForm.Button3Click(Sender: TObject);
var
i: Integer;
vPanel: TPanel;
vButton: TButton;
begin
for i := 0 to 20 do
begin
vPanel := TPanel.Create(TheScrollBox);
vPanel.Align := alTop;
vPanel.Parent := TheScrollBox;
vButton := TButton.Create(vPanel);
vButton.Align := alLeft;
vButton.Parent := vPanel;
vButton.Name := 'L_butan' + IntToStr(i);
vButton.OnClick := ButanClick;
vButton := TButton.Create(vPanel);
vButton.Align := alRight;
vButton.Parent := vPanel;
vButton.Name := 'R_butan' + IntToStr(i);
vButton.OnClick := ButanClick;
end;
end;
You cannot safely destroy the parent TPanel (or the TButton itself) from inside the TButton's OnClick event. The VCL still needs access to the TPanel/TButton for a beat after the event handler exits. So, you need to delay the destruction until after the handler exits. The easiest way to do that is to use TThread.ForceQueue() to call TObject.Free() on the TPanel, eg:
procedure TMainForm.ButanClick(Sender: TObject);
var
vButton: TButton;
begin
vButton := TButton(Sender);
if vButton.Name.StartsWith('L') then
begin
vButton.Caption := 'YARE YARE DAZE';
end
else
begin
TThread.ForceQueue(nil, vButton.Parent.Free);
end;
end;
The TPanel will remove itself from the TScrollBox during its destruction. You do not need to handle that step manually.
Solved with Renate Schaaf answer:
...
const
WM_REMOVEPANEL = WM_USER + 9001;
procedure ButanClick(Sender: TObject);
procedure OnCustomMessage(var Msg: TMessage); message WM_REMOVEPANEL;
...
procedure TMainForm.ButanClick(Sender: TObject);
var
vParentPanel: TPanel;
begin
if (string(TButton(Sender).Name).StartsWith('L')) then
begin
TButton(Sender).Caption := 'YARE YARE DAZE';
end
else
begin
// SendMessage = access violation again because it wait the return
// while PostMessage return istantly
PostMessage(Handle, WM_REMOVEPANEL, 0, THandle(#Sender));
end;
end;
procedure TMainForm.OnCustomMessage(var Msg: TMessage);
var
vButton: TButton;
begin
if (Msg.Msg = WM_REMOVEPANEL) then
begin
vButton := TButton(Pointer(Msg.LParam)^);
ShowMessage(vButton.Name);
TheScrollBox.RemoveComponent(vButton.GetParentComponent());
TPanel(vButton.GetParentComponent()).Destroy();
Msg.Result := 1;
end
else
Msg.Result := 0;
end;

How to get text from found component?

I have a problem with Text inside of a found TEdit.
This is my code:
function TfrmGenerateExam.zlicz_liczby(Component: TControl): integer;
var
i, j: integer;
begin
Result := 0;
for i := 0 to Component.ComponentCount - 1 do
begin
for j := 0 to Panel.ComponentCount - 1 do
begin
if Components[j] is TEdit then
begin
Result := Result + ???;
end;
end;
end;
end;
In a nutshell:
I create dynamic panels with ComboBoxes, Edits, Buttons etc.
When I have some panels, I want to count the edits which are in panels, which are in ScrollBox:
What do I need to put here?
if Components[j] is TEdit then
begin
Result := Result + ???;
end;
The code provided does not match the screenshot shown. What is being passed as the Component parameter to zlicz_liczby()? Is it the Form itself? The ScrollBox? A specified Panel?
Let's just iterate the Panels in the ScrollBox directly. Try something more like this:
function TfrmGenerateExam.zlicz_liczby: Integer;
var
i, j: integer;
Panel: TPanel;
begin
Result := 0;
for i := 0 to ScrollBox1.ControlCount - 1 do
begin
Panel := ScrollBox1.ControlCount[i] as TPanel;
for j := 0 to Panel.ControlCount - 1 do
begin
if Panel.Controls[j] is TEdit then
Result := Result + StrToIntDef(TEdit(Panel.Controls[j]).Text, 0);
end;
end;
end;
That being said, as #AndreasRejbrand stated in comments, you should use an array instead. When you create a new TPanel with a TEdit on it, put its TEdit into a TList<TEdit>, for instance. If you destroy the TPanel, remove its TEdit from the list. And then you can simply loop through that list whenever needed, without having to hunt for the TEdit controls at all. For example:
private
Edits: TList<TEdit>;
procedure TfrmGenerateExam.FormCreate(Sender: TObject);
begin
Edits := TList<TEdit>.Create;
end;
procedure TfrmGenerateExam.FormDestroy(Sender: TObject);
begin
Edits.Free;
end;
function TfrmGenerateExam.FillScrollBox;
var
Panel: TPanel;
Edit: TEdit;
begin
...
Panel := TPanel.Create(Self);
Panel.Parent := ScrollBox1;
...
Edit := TEdit.Create(Panel);
Edit.Parent := Panel;
...
Edits.Add(Edit);
...
end;
function TfrmGenerateExam.zlicz_liczby: Integer;
var
i: integer;
begin
Result := 0;
for i := 0 to Edits.Count - 1 do
Result := Result + StrToInt(Edits[i].Text);
end;

How to create popup menu with scroll bar that also supports sub-menus

I want to add scroll bars (and/or scroll wheel support) to my existing Delphi application's popup menus, because they are often higher than the screen, and the built in scrolling is not good enough. How to make a popup menu with scrollbar? would be a great solution for me, except that it doesn't support sub-menus, which I absolutely require. The author of that solution hasn't been on StackOverflow since last July, so I don't think he'll reply to my comment. Can anyone see how to modify that code to add support for sub-menus? In case it matters, I need it to work with Delphi 2007.
I share #KenWhite's reservations about how users might receive a huge menu. So apologies to him and readers whose sensibilities the following might offend ;=)
Anyway, I hope the code below shows that in principle, it is straightforward
to create a TreeView based on a TPopUpMenu (see the routine PopUpMenuToTree) which reflects the structure of the PopUpMenu, including sub-items,
and make use of the TreeView's automatic vertical scroll bar. In the code, the
PopUpMenu happens to be on the same form as the TreeView, but that's only for
compactness, of course - the PopUpMenu could be on anothe form entirely.
As mentioned in a comment, personally I would base something like this on a
TVirtualTreeView (http://www.soft-gems.net/index.php/controls/virtual-treeview)
because it is far more customisable than a standard TTreeView.
type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
TreeView1: TTreeView; // alClient-aligned
Start1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure TreeView1Click(Sender: TObject);
private
protected
procedure MenuItemClick(Sender : TObject);
procedure PopUpMenuToTree(PopUpMenu : TPopUpMenu; TreeView : TTreeView);
public
end;
var
Form1: TForm1;
[...]
procedure TForm1.FormCreate(Sender: TObject);
var
Item,
SubItem : TMenuItem;
i,
j : Integer;
begin
// (Over)populate a PopUpMenu
for i := 1 to 50 do begin
Item := TMenuItem.Create(PopUpMenu1);
Item.Caption := 'Item ' + IntToStr(i);
Item.OnClick := MenuItemClick;
PopUpMenu1.Items.Add(Item);
for j := 1 to 5 do begin
SubItem := TMenuItem.Create(PopUpMenu1);
SubItem.Caption := Format('Item %d Subitem %d ', [i, j]);
SubItem.OnClick := MenuItemClick;
Item.Add(SubItem);
end;
end;
// Populate a TreeView from the PopUpMenu
PopUpMenuToTree(PopUpMenu1, TreeView1);
end;
procedure TForm1.MenuItemClick(Sender: TObject);
var
Item : TMenuItem;
begin
if Sender is TMenuItem then
Caption := TMenuItem(Sender).Caption + ' clicked';
end;
procedure TForm1.PopUpMenuToTree(PopUpMenu: TPopUpMenu;
TreeView: TTreeView);
// Populates the TreeView with the Items in the PopUpMenu
var
i : Integer;
Item : TMenuItem;
RootNode : TTreeNode;
procedure AddItem(Item : TMenuItem; ParentNode : TTreeNode);
var
Node : TTreeNode;
j : Integer;
begin
Node := TreeView.Items.AddChildObject(ParentNode, Item.Caption, Item);
for j := 0 to Item.Count - 1 do begin
AddItem(Item.Items[j], Node);
end;
end;
begin
TreeView.Items.BeginUpdate;
TreeView.Items.Clear;
try
for i := 0 to PopUpMenu.Items.Count - 1 do begin
AddItem(PopUpMenu.Items[i], Nil);
end;
finally
TreeView.Items.EndUpdate;
end;
end;
procedure TForm1.TreeView1Click(Sender: TObject);
var
Node : TTreeNode;
Item : TMenuItem;
begin
if Sender is TTreeView then begin
Node := TTreeView(Sender).Selected;
Item := TMenuItem(Node.Data);
Item.Click;
end;
end;
Here's what I have done, by merging How to make a popup menu with scrollbar?, MartynA's code, and some of my own:
unit PopupUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
StdCtrls, Menus, ComCtrls;
type
TPopupMode = (pmStandard, pmCustom);
TPopupMenu = class(Menus.TPopupMenu)
private
FPopupForm: TForm;
FPopupMode: TPopupMode;
public
constructor Create(AOwner: TComponent); override;
procedure Popup(X, Y: Integer); override;
property PopupForm: TForm read FPopupForm write FPopupForm;
property PopupMode: TPopupMode read FPopupMode write FPopupMode;
end;
type
TPopupForm = class(TForm)
private
FPopupForm: TForm;
FPopupMenu: TPopupMenu;
FTreeView: TTreeView;
procedure DoResize;
procedure TreeViewClick(Sender: TObject);
procedure TreeViewCollapsedOrExpanded(Sender: TObject; Node: TTreeNode);
procedure TreeViewKeyPress(Sender: TObject; var Key: Char);
procedure WMActivate(var AMessage: TWMActivate); message WM_ACTIVATE;
protected
procedure CreateParams(var Params: TCreateParams); override;
public
constructor Create(AOwner: TComponent; APopupForm: TForm;
APopupMenu: TPopupMenu); reintroduce;
end;
var
PopupForm: TPopupForm;
implementation
{$R *.dfm}
{ TPopupForm }
constructor TPopupForm.Create(AOwner: TComponent; APopupForm: TForm;
APopupMenu: TPopupMenu);
procedure AddItem(Item : TMenuItem; ParentNode : TTreeNode);
var
I : Integer;
Node : TTreeNode;
begin
if Item.Caption <> '-' then begin
Node := FTreeView.Items.AddChildObject(ParentNode, Item.Caption, Item);
Node.ImageIndex := Item.ImageIndex;
for I := 0 to Item.Count - 1 do begin
AddItem(Item.Items[I], Node);
end;
end;
end;
var
I: Integer;
begin
inherited Create(AOwner);
BorderStyle := bsNone;
FPopupForm := APopupForm;
FPopupMenu := APopupMenu;
FTreeView := TTreeView.Create(Self);
FTreeView.Parent := Self;
FTreeView.Align := alClient;
FTreeView.BorderStyle := bsSingle;
FTreeView.Color := clMenu;
FTreeView.Images := FPopupMenu.Images;
FTreeView.ReadOnly := TRUE;
FTreeView.ShowHint := FALSE;
FTreeView.ToolTips := FALSE;
FTreeView.OnClick := TreeViewClick;
FTreeView.OnCollapsed := TreeViewCollapsedOrExpanded;
FTreeView.OnExpanded := TreeViewCollapsedOrExpanded;
FTreeView.OnKeyPress := TreeViewKeyPress;
FTreeView.Items.BeginUpdate;
try
FTreeView.Items.Clear;
for I := 0 to FPopupMenu.Items.Count - 1 do
begin
AddItem(FPopupMenu.Items[I], NIL);
end;
finally
FTreeView.Items.EndUpdate;
end;
DoResize;
end;
procedure TPopupForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WindowClass.Style := Params.WindowClass.Style or CS_DROPSHADOW;
end;
procedure TPopupForm.DoResize;
const
BORDER = 2;
var
ItemRect, TVRect : TRect;
MF : TForm;
Node : TTreeNode;
begin
TVRect := Rect(0, 0, 0, 0);
Node := FTreeView.Items[0];
while Node <> NIL do begin
ItemRect := Node.DisplayRect(TRUE);
ItemRect.Right := ItemRect.Right + FTreeView.Images.Width + 1;
if ItemRect.Left < TVRect.Left then
TVRect.Left := ItemRect.Left;
if ItemRect.Right > TVRect.Right then
TVRect.Right := ItemRect.Right;
if ItemRect.Top < TVRect.Top then
TVRect.Top := ItemRect.Top;
if ItemRect.Bottom > TVRect.Bottom then
TVRect.Bottom := ItemRect.Bottom;
Node := Node.GetNextVisible;
end;
MF := Application.MainForm;
if Top + TVRect.Bottom - TVRect.Top > MF.Top + MF.ClientHeight then begin
TVRect.Bottom := TVRect.Bottom -
(Top + TVRect.Bottom - TVRect.Top - (MF.Top + MF.ClientHeight));
end;
if Left + TVRect.Right - TVRect.Left > MF.Left + MF.ClientWidth then begin
TVRect.Right := TVRect.Right -
(Left + TVRect.Right - TVRect.Left - (MF.Left + MF.ClientWidth));
end;
ClientHeight := TVRect.Bottom - TVRect.Top + BORDER * 2;
ClientWidth := TVRect.Right - TVRect.Left + BORDER * 2;
end;
procedure TPopupForm.TreeViewClick(Sender: TObject);
var
Node : TTreeNode;
Item : TMenuItem;
begin
if Sender is TTreeView then begin
Node := TTreeView(Sender).Selected;
if assigned(Node) then begin
Item := TMenuItem(Node.Data);
if assigned(Item.OnClick) then begin
Item.Click;
Close;
end;
end;
end;
end;
procedure TPopupForm.TreeViewCollapsedOrExpanded(Sender: TObject;
Node: TTreeNode);
begin
DoResize;
end;
procedure TPopupForm.TreeViewKeyPress(Sender: TObject; var Key: Char);
begin
if Ord(Key) = VK_RETURN then begin
TreeViewClick(Sender);
end
else if Ord(Key) = VK_ESCAPE then begin
Close;
end;
end;
procedure TPopupForm.WMActivate(var AMessage: TWMActivate);
begin
SendMessage(FPopupForm.Handle, WM_NCACTIVATE, 1, 0);
inherited;
if AMessage.Active = WA_INACTIVE then
Release;
FTreeView.Select(NIL, []);
end;
{ TPopupMenu }
constructor TPopupMenu.Create(AOwner: TComponent);
begin
inherited;
FPopupMode := pmStandard;
end;
procedure TPopupMenu.Popup(X, Y: Integer);
begin
case FPopupMode of
pmCustom:
with TPopupForm.Create(nil, FPopupForm, Self) do
begin
Top := Y;
Left := X;
Show;
end;
pmStandard: inherited;
end;
end;
end.

Delphi XE4 Tpanel doesnt change color [duplicate]

got a strange problem: I create a TPanele at runtime and change its color - however, the color is still clBtnFace.
Here' the code:
procedure TForm1.Button1Click(Sender: TObject);
var
pnlTest : TPanel;
begin
pnlTest := TPanel.Create(Form1);
pnlTest.Parent := Form1;
pnlTest.Width := 100;
pnlTest.Height := 100;
pnlTest.Color := clRed;
end;
Any ideas? Thanks!
When you want to have colored panels under a themed OS you have to set ParentBackground to False.
Try this :-)
procedure TForm1.Button1Click(Sender: TObject);
var
pnlTest : TPanel;
begin
pnlTest := TPanel.Create(Form1);
pnlTest.Parent := Form1;
pnlTest.Width := 100;
pnlTest.Height := 100;
pnlTest.ParentBackground := false;
pnlTest.Color := clRed;
end;
This the code for maXbox scripting:
procedure SetArrayLength2Panels(var arr: array of array of TPanel;
asize1, asize2: Integer);
var i: Integer;
begin setlength(arr, asize1);
for i:= 0 to asize1-1 do SetLength(arr[i], asize2);
end;
procedure TMyFormInitialisePanels(aform: Tform; RowCount,ColCount: Integer);
var
aLeft,aTop,aWidth,aHeight, row,col: Integer;
Panel: TPanel;
FPanels: array of array of TPanel;
begin
//SetLength(FPanels, RowCount, ColCount);
SetArrayLength2Panels(Fpanels, RowCount, ColCount)
aTop:= 0;
for Row:= 0 to RowCount-1 do begin
aLeft:= 0;
aHeight:= (aform.ClientHeight-aTop) div (RowCount-Row);
for Col:= 0 to ColCount-1 do begin
Panel:= TPanel.Create(Self);
FPanels[Row][Col]:= Panel;
Panel.Parent:= aform; //Self;
//panel.parentcolor:= false;
panel.ParentBackground:= false;
panel.color:= random(clred)
aWidth:= (aform.ClientWidth-aLeft) div (ColCount-Col);
Panel.SetBounds(aLeft, aTop, aWidth, aHeight);
inc2(aLeft, aWidth);
end;
inc2(aTop, aHeight);
end;
end;

How can I filter the contents of a combo box based on what's been typed?

We have a combo box with more than 100 items.
We want to filter out the items as we enter characters in combo box. For example if we entered 'ac' and click on the drop down option then we want it to display items starting with 'ac' only.
How can I do this?
Maybe you'd be happier using the autocompletion features built in to the OS. I gave an outline of how to do that here previously. Create an IAutoComplete object, hook it up to your combo box's list and edit control, and the OS will display a drop-down list of potential matches automatically as the user types. You won't need to adjust the combo box's list yourself.
To expand on Rob's answer about using the OnChange event, here is an example of how to do what he suggests.
procedure TForm1.FormCreate(Sender: TObject);
begin
FComboStrings := TStringList.Create;
FComboStrings.Add('Altair');
FComboStrings.Add('Alhambra');
FComboStrings.Add('Sinclair');
FComboStrings.Add('Sirius');
FComboStrings.Add('Bernard');
FComboStrings.Sorted := True;
ComboBox1.AutoComplete := False;
ComboBox1.Items.Text := FComboStrings.Text;
ComboBox1.Sorted := True;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(FComboStrings);
end;
procedure TForm1.ComboBox1Change(Sender: TObject);
var
Filter: string;
i: Integer;
idx: Integer;
begin
// Dropping down the list puts the text of the first item in the edit, this restores it
Filter := ComboBox1.Text;
ComboBox1.DroppedDown := True;
ComboBox1.Text := Filter;
ComboBox1.SelStart := Length(Filter);
for i := 0 to FComboStrings.Count - 1 do
if SameText(LeftStr(FComboStrings[i], Length(ComboBox1.Text)), ComboBox1.Text) then
begin
if ComboBox1.Items.IndexOf(FComboStrings[i]) < 0 then
ComboBox1.Items.Add(FComboStrings[i]);
end
else
begin
idx := ComboBox1.Items.IndexOf(FComboStrings[i]);
if idx >= 0 then
ComboBox1.Items.Delete(idx);
end;
end;
My brief contribution working with objects in the combobox:
procedure FilterComboBox(Combo: TComboBox; DefaultItems: TStrings);
function Origin: TStrings;
begin
if Combo.Tag = 0 then
begin
Combo.Sorted := True;
Result := TStrings.Create;
Result := Combo.Items;
Combo.Tag := Integer(Result);
end
else
Result := TStrings(Combo.Tag);
end;
var
Filter: TStrings;
I: Integer;
iSelIni: Integer;
begin
if(Combo.Text <> EmptyStr) then
begin
iSelIni:= Length(Combo.Text);
Filter := TStringList.Create;
try
for I := 0 to Origin.Count - 1 do
if AnsiContainsText(Origin[I], Combo.Text) then
Filter.AddObject(Origin[I], TObject(Origin.Objects[I]));
Combo.Items.Assign(Filter);
Combo.DroppedDown:= True;
Combo.SelStart := iSelIni;
Combo.SelLength := Length(Combo.Text);
finally
Filter.Free;
end;
end
else
Combo.Items.Assign(DefaultItems);
end;
You can handle the combo box's OnChange event. Keep a master list of all items separate from the UI control, and whenever the combo box's edit control changes, adjust the combo box's list accordingly. Remove items that don't match the current text, or re-add items from the master list that you removed previously.
As Rob already answered, you could filter on the OnChange event, see the following code example. It works for multiple ComboBoxes.
{uses}
Contnrs, StrUtils;
type
TForm1 = class(TForm)
ComboBox1: TComboBox;
ComboBox2: TComboBox;
procedure FormCreate(Sender: TObject);
procedure ComboBoxChange(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FComboLists: TList;
procedure FilterComboBox(Combo: TComboBox);
end;
implementation
{$R *.dfm}
procedure TForm1.ComboBoxChange(Sender: TObject);
begin
if Sender is TComboBox then
FilterComboBox(TComboBox(Sender));
end;
procedure TForm1.FilterComboBox(Combo: TComboBox);
function Origin: TStrings;
begin
if Combo.Tag = 0 then
begin
Combo.Sorted := True;
Result := TStringList.Create;
Result.Assign(Combo.Items);
FComboLists.Add(Result);
Combo.Tag := Integer(Result);
end
else
Result := TStrings(Combo.Tag);
end;
var
Filter: TStrings;
I: Integer;
begin
Filter := TStringList.Create;
try
for I := 0 to Origin.Count - 1 do
if AnsiStartsText(Combo.Text, Origin[I]) then
Filter.Add(Origin[I]);
Combo.Items.Assign(Filter);
Combo.SelStart := Length(Combo.Text);
finally
Filter.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FComboLists := TObjectList.Create(True);
// For Each ComboBox, set AutoComplete at design time to false:
ComboBox1.AutoComplete := False;
ComboBox2.AutoComplete := False;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FComboLists.Free;
end;

Resources