Пары значение-имя в ComboBox

Я убежден, что это должно быть типичной проблемой, но я, может казаться, не нахожу простое решение...

Я хочу использовать управление полем комбинированного списка с парами значение-имя как объекты. ComboBox берет TStrings в качестве своих объектов так, чтобы был прекрасен.

К сожалению, метод рисования для поля комбинированного списка тянет Объекты [я] так, Вы получаете Name=Value в поле.

Я хотел бы, чтобы значение было скрыто, таким образом, я могу работать со значением в коде, но пользователь видит имя.

Какие-либо идеи?

17
задан James Barrass 11 June 2010 в 13:03
поделиться

3 ответа

Установить Стиль на csOwnerDrawFixed и напишите

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;
14
ответ дан 30 November 2019 в 12:57
поделиться

Текст элементов поля со списком должен содержать отображаемый текст. Это правильный стиль. Затем используйте свойство ItemIndex для поиска значений внутренних ключей. Преодоление свойств элемента управления для хранения кода модели или значений внутренних ключей базы данных является серьезным нарушением принципов ООП.

Давайте просто посмотрим, как кто-то собирается поддерживать ваше приложение в будущем. Вы можете сами вернуться к этому коду и подумать: «О чем я думал?». Помните «принцип наименьшего удивления». Используйте вещи так, как они предназначены, и спасите себя и своих коллег от боли.

1
ответ дан 30 November 2019 в 12:57
поделиться

Если ваши значения целые: Разделите пары значений имени, сохраните имена в строках поля со списком и значения в соответствующих объектах.

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

Таким образом, вы можете продолжать использовать свои элементы управления обычным образом и по-прежнему иметь значение, доступное через:

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

Этот подход также можно использовать для списков других объектов. Например, TObjectList, содержащий экземпляры объекта TPerson:

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

и получение соответствующего TPerson выбранного элемента с помощью:

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

Update

Лучший способ - и тот, который не зависит от значений, являющихся целыми числами, - это предварительно обработать List, заключая значения в простой класс и добавляя их экземпляры к объектам List.

Простой расширенный класс оболочки на основе RTTI:

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;

Если вы используете версию Delphi до D2010, просто используйте строку вместо TValue.

Предварительная обработка списка:

// 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;

Загрузка списка в Combo теперь является простым назначением:

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

Имейте в виду, что внутренне это выполняет назначение, поэтому вам лучше убедиться, что комбинация больше не может получить доступ к экземплярам объектов его списка до того, как освободить список.

Получение имени и значения из списка:

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

или из ComboBox:

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

Эту же информацию с более подробным объяснением можно найти в моем блоге: TL; версия DR пары значений имени в ComboBox и Kinfolk

11
ответ дан 30 November 2019 в 12:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: