Произвольный индекс для пунктов ComboBox

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Произвольный индекс для пунктов ComboBox

Сообщение Nik » 12.07.2010 18:16:20

Пишу прогу, активно работающую с БД. Есть необходимость запросить у пользователя некие данные. Выбор осуществляется из списка, который - в свою очередь - заполняется каждый раз данными из БД. Нюанс такой: при заполнении списка удобно иметь под рукой не только текст (поле name), но и id каждого пункта (для упрощения проверок и записи обратно в БД). Но в ComboBox id не засунешь. Удобнее всего было бы использовать StringGrid и писать id в отдельный столбец, но таблица слишком громоздка и неудобна. Пока придумал только извращение с комбинацией TEdit и StringGrid.
Может кто-то сталкивался с подобным. Какие ещё есть варианты?
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Произвольный индекс для пунктов ComboBox

Сообщение GrayEddy » 12.07.2010 18:28:09

Пример, cbDivision - обычный ComboBox
Код: Выделить всё
repeat
    cbDivisions.Items.AddObject(DM.IBqryUni.FieldByName('Name').AsString, TObject(DM.IBqryUni.FieldByName('uid').AsInteger));
    DM.IBqryUni.Next;
until DM.IBqryUni.Eof;


Более развернуто, код очень древний
Здесь заполняем
Код: Выделить всё
procedure TfmRefEmployees.FormCreate(Sender: TObject);
begin
  inherited;
  cbDivisions.Items.Clear;
  DM.IBqryUni.Close;
  DM.IBqryUni.SQL.Text := 'select * from refdivisions where flag = 1 order by name';
  DM.IBqryUni.Open;
  repeat
    cbDivisions.Items.AddObject(DM.IBqryUni.FieldByName('Name').AsString, TObject(DM.IBqryUni.FieldByName('uid').AsInteger));
    DM.IBqryUni.Next;
  until DM.IBqryUni.Eof;
  cbDivisions.Items.InsertObject(0, '< ВСЕ >', nil);
  cbDivisions.ItemIndex := 0;
  DM.IBqryUni.Close;
end;


А вот здесь извлекаем из комбобокса
Код: Выделить всё
procedure TfmRefEmployees.cbDivisionsClick(Sender: TObject);
var
  Obj: TObject;
  S: string;
  Bookmark: Integer;
begin
  inherited;
  if Sender is TComboBox then begin
    Bookmark := DM.IBqryEmployees.FieldByName('uid').AsInteger;
    S := 'select * from refemployees';
    if Assigned(TComboBox(Sender).Items.Objects[TComboBox(Sender).ItemIndex]) then begin
      Obj := TComboBox(Sender).Items.Objects[TComboBox(Sender).ItemIndex];
      S := Format('%s where idrefdivisions = %d', [S, Integer(Obj)]);
    end;
    if not cbShowDischarged.Checked then begin
      if Pos('where idrefdivisions', S) > 0 then
        S := S + ' and resigned = 0'
      else
        S := S + ' where resigned = 0';
    end;
    S := S + ' order by surname, name, middle';
    dsReference.Dataset.Close;
    TIBQuery(dsReference.Dataset).Transaction.Active := False;
    TIBQuery(dsReference.Dataset).SQL.Text := S;
    dsReference.Dataset.Open;
    TIBQuery(dsReference.Dataset).FetchAll;
    TIBQuery(dsReference.Dataset).Transaction.Active := True;
    DM.IBqryEmployees.Locate('uid', Bookmark, [loPartialKey]);
  end;
end;


PS: Невнимательно прочел, но что мешает в
Код: Выделить всё
cbDivisions.Items.AddObject(DM.IBqryUni.FieldByName('Name').AsString, TObject(DM.IBqryUni.FieldByName('uid').AsInteger));

в качестве первого параметра взять строку не из таблицы, а сформировать свою - id + табулятор (для ровного отступа) + значение (name) из таблицы
GrayEddy
постоялец
 
Сообщения: 375
Зарегистрирован: 06.05.2005 09:37:56

Re: Произвольный индекс для пунктов ComboBox

Сообщение yurgel » 12.07.2010 18:40:04

стандартный вариант - делать выбор из грида, привязанного к таблице, из которой грузятся данные в комбо, в каком-то модальном окне. соответственно id-ник берётся из самой таблицы без всяких танцев с бубном.

второй вариант, характерный для комбобоксов и прочих. у всех потомков TStrings кроме свойства Items есть полезное свойство Values. если сказать комбобоксу ComboBox1.Items.Add ('RecNo=100');, то:

1. ComboBox1.Items.Names [0] = 'RecNo';
2. ComboBox1.Items.Values ['RecNo'] = '100';
3. ComboBox1.Items.ValueFromIndex [0] = '100';

и т.д.

поэтому иногда в комбобоксах, листбоксах и прочих щастливых обладателях свойства Items: TStrings имеет смысл использовать добавлять значения в виде ('Name=Value'), а потом просто пеорехватывать отрисовку (для комбобокса - свойство Style ставим в csOwnerDrawFixed, а в обработчике OnDrawItem пишем свой код, выводящий на экран только значения Items.Names. но у этого подхода есть существенный недостаток: если в Names содержится знак равно, строка будет распарсена неправильно.

и третий вариант.
Но в ComboBox id не засунешь
- это не так. в TStrings можно запихивать не только строки, но и объекты (см. свойство TStrings.Objects). и это очень часто и очень широко используется, потому что указатель на объект - это longint, 8-разрядное целое, в которое можно запихать практически любой идентификатор либо ссылку на оный. и делаеться это очень просто:

Код: Выделить всё
procedure TForm1.FormCreate(Sender: TObject);
var
  i: integer;
begin
  for i := 1 to 10 do
    ComboBox1.Items.AddObject(IntToStr (i), TObject (i));
end;

procedure TForm1.ComboBox1CloseUp(Sender: TObject);
begin
  ShowMessage (IntToStr (integer (ComboBox1.Items.Objects [ComboBox1.ItemIndex])));
end;


при создании формы мы якобы добавляем объект, а на деле присваиваем указателю нужное нам значение, а потом - просто вытаскиваем его оттуда.
yurgel
новенький
 
Сообщения: 37
Зарегистрирован: 29.06.2010 16:06:58

Re: Произвольный индекс для пунктов ComboBox

Сообщение Nik » 12.07.2010 20:45:36

yurgel
в TStrings можно запихивать не только строки, но и объекты (см. свойство TStrings.Objects).

Век живи - век учись! То, что нужно! Спасибо! :)
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Произвольный индекс для пунктов ComboBox

Сообщение v-t-l » 13.07.2010 15:53:25

yurgel писал(а):указатель на объект - это longint, 8-разрядное целое

32-разрядное (4-байтное) беззнаковое целое на 32-битных платформах и 64-разрядное (8-байтное) - на 64-битных.
Поэтому компилятор будет не доволен :wink:
v-t-l
энтузиаст
 
Сообщения: 735
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Re: Произвольный индекс для пунктов ComboBox

Сообщение grigoreo » 15.07.2010 09:58:24

Зачем такие сложности можно просто взять связанные динамические массивы...
Аватара пользователя
grigoreo
постоялец
 
Сообщения: 195
Зарегистрирован: 10.03.2009 15:43:43
Откуда: С нашей Раши

Re: Произвольный индекс для пунктов ComboBox

Сообщение Nik » 15.07.2010 12:21:37

Лишняя память + необходимость тройной синхронизации данных между интерфейсной частью, БД и промежуточным массивом (использовал в одном из старых проектов подобный подход - очень неудобно). ComboBox есть в любом случае, так что логичнее привязать всё к нему. А никакой особой сложности в методе с ComboBox1.Items.AddObject, который предложил yurgel, я не вижу (собственно, уже применил его на практике - всё отлично работает :) )
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Произвольный индекс для пунктов ComboBox

Сообщение yurgel » 18.07.2010 18:38:57

v-t-l писал(а):
yurgel писал(а):указатель на объект - это longint, 8-разрядное целое

32-разрядное (4-байтное) беззнаковое целое на 32-битных платформах и 64-разрядное (8-байтное) - на 64-битных.
Поэтому компилятор будет не доволен :wink:


с разрядностью я перегнул, каюсь :) а компилятор будет доволен, какая ему разница - указатель и указатель, как мы его используем - наше дело.
yurgel
новенький
 
Сообщения: 37
Зарегистрирован: 29.06.2010 16:06:58


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 69

Рейтинг@Mail.ru
cron