How to create a TComboBox with two columns that has one of its columns hidden so that it can keep an id value along with the actual item in it? And then how to get to that id value programmatically?
There's no need for two columns here.
You can take advantage of the fact that TComboBox.Items
(like many other things in Delphi, like TStringList
, TMemo.Lines
, and TListBox.Items
) descends from TStrings
, which has both the Strings
and Objects
properties. Objects
stores anything the size of a TObject
, which is a pointer.
This means you can store your integer value by simply typecasting it to a TObject when adding it, and typecasting it back to an Integer when retrieving it.
Something like this should work:
procedure TForm1.FormCreate(Snder: TObject);
var
i: Integer;
sItem: String;
begin
for i := 0 to 9 do
begin
sItem := Format('Item %d', [i]);
ComboBox1.Items.AddObject(sItem, TObject(i));
end;
end;
To retrieve the value:
procedure TForm1.ComboBox1Click(Sender: TObject);
var
Idx: Integer;
Value: Integer;
begin
Idx := ComboBox1.ItemIndex;
if Idx <> -1 then
begin
Value := Integer(ComboBox1.Items.Objects[Idx]);
// Do something with value you retrieved
end;
end;
Note that, since the Objects property is actually meant to store objects, this gives you a lot of flexibility. Here's an example (intentionally very trivial) of storing a customer's contact information in an associated object instance and displaying it in labels when an item from a listbox is selected.
unit Unit1;
interface
uses
Windows, Messages, Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TCustomer=class
private
FContact: string;
FPhone: string;
public
constructor CreateCustomer(const AContact, APhone: string);
property Contact: string read FContact write FContact;
property Phone: string read FPhone write FPhone;
end;
TForm1 = class(TForm)
ListBox1: TListBox;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
lblContact: TLabel;
lblPhone: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ListBox1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TCustomer }
constructor TCustomer.CreateCustomer(const AContact, APhone: string);
begin
inherited Create;
FContact := AContact;
FPhone := APhone;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i: Integer;
begin
for i := 0 to ListBox1.Items.Count - 1 do
ListBox1.Items.Objects[i].Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
lblContact.Caption := '';
lblPhone.Caption := '';
// Create some customers. Of course in the real world you'd load this
// from some persistent source instead of hard-coding them here.
ListBox1.Items.AddObject('N Company', TCustomer.CreateCustomer('Nancy', '555-3333'));
ListBox1.Items.AddObject('B Company', TCustomer.CreateCustomer('Brad', '555-1212'));
ListBox1.Items.AddObject('A Company', TCustomer.CreateCustomer('Angie', '555-2345'));
end;
procedure TForm1.ListBox1Click(Sender: TObject);
var
Cust: TCustomer;
begin
if ListBox1.ItemIndex <> -1 then
begin
Cust := TCustomer(ListBox1.Items.Objects[ListBox1.ItemIndex]);
lblContact.Caption := Cust.Contact;
lblPhone.Caption := Cust.Phone;
end;
end;
end.