7

如何创建一个包含两列的TComboBox,其中一列隐藏,以便它可以保留一个 id 值以及其中的实际项目?然后如何以编程方式获得该 id 值?

4

2 回答 2

11

这里不需要两列。

您可以利用这样一个事实,即TComboBox.Items(与 Delphi 中的许多其他东西一样,如TStringListTMemo.LinesTListBox.Items)都来自TStrings,它同时具有StringsObjects属性。Objects存储任何大小的 a TObject,它是一个指针。

这意味着您可以通过在添加整数时简单地将其类型转换为TObject并在检索时将其类型转换回Integer来存储整数值。

像这样的东西应该工作:

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;

要检索值:

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;

请注意,由于Objects属性实际上是用来存储对象的,因此这为您提供了很大的灵活性。这是一个将客户的联系信息存储在关联对象实例中并在选择列表框中的项目时将其显示在标签中的示例(故意非常简单)。

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.
于 2013-04-21T07:01:03.243 回答
9

ComboBox 控件不支持列,并且无论如何您都不需要隐藏列来完成您需要的操作。

TComboBox.Items财产是TStrings后代。它可以同时保存字符串值和关联的用户定义数据值,但用户只能在 UI 中看到字符串值。使用Items.AddObject()方法将字符串+ID 值添加到列表中,然后Items.Objects[]在需要时使用属性检索 ID 值。

或者,您可以将 ID 值存储在与 ComboBox 具有相同元素数量的单独数组中,然后使用 ComboBox 项索引来访问数组值。如果您需要存储 -1 的值,这一点尤其重要,因为正如 Rob 所说,由于 getter 方法的实现方式,该特定值无法从Objects[]a 的属性中检索到。TComboBox

于 2013-04-15T08:02:34.457 回答