Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Name Value Pairs in a ComboBox

I'm convinced this must be a common problem, but I can't seem to find a simple solution...

I want to use a combobox control with name value pairs as the items. ComboBox takes TStrings as its items so that should be fine.

Unfortunately the drawing method on a combobox draws Items[i] so you get Name=Value in the box.

I'd like the value to be hidden, so I can work with the value in code, but the user sees the name.

Any Ideas?

like image 207
James Barrass Avatar asked Jun 11 '10 13:06

James Barrass


People also ask

How do I select items in ComboBox?

When you set the SelectedItem property to an object, the ComboBox attempts to make that object the currently selected one in the list. If the object is found in the list, it is displayed in the edit portion of the ComboBox and the SelectedIndex property is set to the corresponding index.

How do I find the index of a ComboBox?

Get Index Of Selected Value (ComboBoxCell) Search the cell value (Cell. Value) in the ComboBox. Items property collection to get the index of the value selected in the combo box cell.


2 Answers

Set Style to csOwnerDrawFixed and write

procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
  ComboBox1.Canvas.TextRect(Rect, Rect.Left, Rect.Top, ComboBox1.Items.Names[Index]);
end;
like image 92
Andreas Rejbrand Avatar answered Nov 09 '22 00:11

Andreas Rejbrand


If your values are integers: Split the name value pairs, store the names in the strings of the combobox and the values in the corresponding objects.

  for i := 0 to List.Count - 1 do
    ComboBox.AddItem(List.Names[i], TObject(StrToInt(List.ValueFromIndex[i], 0)));

This way you can keep using your controls in a generic way and still have the value avalaible through:

Value := Integer(ComboBox.Items.Objects[ComboBox.ItemIndex]);

This approach can also be used for lists of other objects. For example a TObjectList containing TPerson object instances:

var
  i: Integer;
  PersonList: TObjectList;
begin
  for i := 0 to PersonList.Count - 1 do
    ComboBox.AddItem(TPerson(PersonList[i]).Name, PersonList[i]);

and retrieve the corresponding TPerson of the selected item through:

Person := TPerson(ComboBox.Items.Objects[ComboBox.ItemIndex]);

Update

A better way - and one not dependent on the values being integers - is to pre-process the List, wrapping the values in a simple class and adding instances thereof to the List's Objects.

Simple - extended RTTI based - wrapper class:

type
  TValueObject = class(TObject)
  strict private
    FValue: TValue;
  public
    constructor Create(const aValue: TValue);
    property Value: TValue read FValue;
  end;

  { TValueObject }

constructor TValueObject.Create(const aValue: TValue);
begin
  FValue := aValue;
end;

If you are using a pre-D2010 version of Delphi, just use string instead of TValue.

Pre-processing the list:

// Convert the contents so both the ComboBox and Memo can show just the names
// and the values are still associated with their items using actual object
// instances.
for idx := 0 to List.Count - 1 do
begin
  List.Objects[idx] := 
    TValueObject.Create(List.ValueFromIndex[idx]);

  List.Strings[idx] := List.Names[idx];
end;

Loading the list into the Combo is now a simple assignment:

// Load the "configuration" contents of the string list into the combo box
ComboBox.Items := List; // Does an Assign!

Do bear in mind that internally this does an assign, so you had better make sure that the combo can no longer access the instances its list's objects before you free List.

Getting the name and value from the list:

begin
  Name_Text.Caption := List.Items[idx];
  Value_Text.Caption := TValueObject(List.Objects[idx]).Value.AsString;
end;

or from the ComboBox:

begin
  Name_Text.Caption := ComboBox.Items[idx];
  Value_Text.Caption := TValueObject(ComboBox1.Items.Objects[idx]).Value.AsString;
end;

The same information with more comprehensive explanation can be found on my blog: TL;DR version of Name Value Pairs in ComboBoxes and Kinfolk

like image 35
Marjan Venema Avatar answered Nov 09 '22 00:11

Marjan Venema