Работа с Lookup-полями.

Вопросы стыковки визуальных компонент (DataControls, EhGrid, VirtualTreeView, DevExpress и т.п.) с данными из БД.

Модераторы: kdv, CyberMax

Ответить
beresa
Сообщения: 9
Зарегистрирован: 05 дек 2007, 16:45

Работа с Lookup-полями.

Сообщение beresa » 11 сен 2008, 07:12

Есть главная таблица, с которой связаны внешними ключами справочники. Для добавления данных в эту таблицу в наборе данных создал lookup-поля и связал из с TDBLoolupCombobox.

Всё бы ничего, но при добавлении в главную таблицу данных, которых нет в справочнике, приходится сначала открывать этот справочник, добавлять в него новые данные и только после этого появляется возможность занесения новых данных в главную таблицу – что очень не удобно.

Есть ли какие-нибудь компоненты для работы с lookup-полями, которые при внесении значения, которого ещё нет в справочнике, автоматически создают новую запись в справочнике и полю главной таблицы присваивают id созданной записи?

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Работа с Lookup-полями.

Сообщение WildSery » 11 сен 2008, 11:34

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

beresa
Сообщения: 9
Зарегистрирован: 05 дек 2007, 16:45

Re: Работа с Lookup-полями.

Сообщение beresa » 11 сен 2008, 12:35

WildSery писал(а):Таких компонент не видел.
И сдаётся мне, что не бывает. Слишком много телепатических действий он должен уметь делать.
Подумай сам, сколько всего нужно сделать для такой операции, даже зная структуру твоего справочника.
Да, в принципе согласен с вами.

Мне бы хотелось узнать, как правильно и рационально сделать интерфейс для добавления данных в главную таблицу и как обычно это делают?

Пока я вижу два варианта:
1) поставить кнопку рядом с DBLoolupCombobox.
Но, когда на форме около 10 DBLoolupCombobox’ов и столько же кнопок, интерфейс формы кажется перегруженным.
2) Разместить тупо DBLoolupCombobox и пользователям объяснить, что, если в выпадающем списке нет нужных значений, необходимо сначала открыть справочник и добавить требуемое туда.
Но это тоже получается лишняя морока для пользователей.

А так-то у меня справочники все однотипные и состоят из 2-ух полей - id и значение (varchar). В принципе, можно отказаться от справочников и всё хранить в одной таблице; тогда то, что я задумал можно сделать с помощью DBCombobox. Но, это, наверное, не есть правильно.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Работа с Lookup-полями.

Сообщение kdv » 11 сен 2008, 12:42

в 1с 7.7 нет таких лукапов. там есть вызов форм справочников. где как раз можно добавить или отредактировать элемент, а затем кликнуть на нем, и он попадет как значение из справочника в нужную форму.
То есть, лукапы обычно предназначены когда надо выбрать, а не редактировать значения.
1) поставить кнопку рядом с DBLoolupCombobox.
ага.

WildSery
Заслуженный разработчик
Сообщения: 1738
Зарегистрирован: 05 июн 2006, 16:19

Re: Работа с Lookup-полями.

Сообщение WildSery » 11 сен 2008, 13:16

kdv писал(а):
1) поставить кнопку рядом с DBLoolupCombobox.
ага.
+1
А вот лукап-боксы, в которые можно свои кнопки справа к стандартной стрелке добавлять (и/или заменять стрелку) - есть готовые.
Посмотри, например, набор компонент EhLib, тем более, что есть бесплатная версия, хоть и старая, но с отличным фунцкционалом.

beresa
Сообщения: 9
Зарегистрирован: 05 дек 2007, 16:45

Re: Работа с Lookup-полями.

Сообщение beresa » 11 сен 2008, 15:23

Спасибо за ответы! :D

Использование кнопоки для добавления новых данных в справочнике самое лучшее решение и здесь, согласен с WildSery, DBLookupComboboxEh из набора Ehlib – будет самое то. Кнопочка есть в этом луккомбобоксе.

Kotъ-Begemotъ
Сообщения: 250
Зарегистрирован: 25 июл 2007, 21:33

Re: Работа с Lookup-полями.

Сообщение Kotъ-Begemotъ » 12 сен 2008, 23:29

Смотря что надо. Приведу пример. Есть "простые" справочники - грузов, городов, улиц (они могут быть и не простыми, я привёл исключительно для примера, что в ряде приложений они МОГУТ быть простыми). Так вот, для таких справочников как-то нелогично вызывать окно справочника, в котором нужно добавить новое значение, а потом его и выбрать. Это логично для справочников, где нужно при добавлении записи заполнить несколько полей...
А для простого справочника у меня делается так: пользователь вводит текст в Edit, по мере ввода, под (над) Edit'ом появляется "выпадающее меню" с полями справочника, выбор из которого осуществляется нажатием Enter в Edit'е. А если нужно добавить в справочние, воодится новое значение, и нажимается Tab. Всё. Ну, запрос можно поставить, что значения "ххх" нет в справочнике, добавить? Да/Нет. И на уникальность проверить, потому что для "простых" справочников, обычно уникальность актуальна...
А уж как добавить - вопрос чисто технический, можно по-разному.

beresa
Сообщения: 9
Зарегистрирован: 05 дек 2007, 16:45

Re: Работа с Lookup-полями.

Сообщение beresa » 13 сен 2008, 08:31

Kotъ-Begemotъ писал(а): А для простого справочника у меня делается так: пользователь вводит текст в Edit, по мере ввода, под (над) Edit'ом появляется "выпадающее меню" с полями справочника, выбор из которого осуществляется нажатием Enter в Edit'е...
Интересная идея. :idea:
А что за компонент вы используете?

Я пытался что-то типо такого сделать, но, если в свойстве DataField какой-либо компонента (хоть DBLookupCombobox или же DBLookupComboboxEh) указать lookup-поле, то вводить такие значения, которых ещё нет в справочнике, просто не получается.

Kotъ-Begemotъ
Сообщения: 250
Зарегистрирован: 25 июл 2007, 21:33

Re: Работа с Lookup-полями.

Сообщение Kotъ-Begemotъ » 13 сен 2008, 13:31

beresa писал(а): Интересная идея. :idea:
А что за компонент вы используете?
Я пытался что-то типо такого сделать, но, если в свойстве DataField какой-либо компонента (хоть DBLookupCombobox или же DBLookupComboboxEh) указать lookup-поле, то вводить такие значения, которых ещё нет в справочнике, просто не получается.
Обычный Edit для которого обрабатываются OnChange. По мере ввода текста, если еще не открыто показывается окно справочника без заголовка, с шириной, равной ширине Edit'а в котором DBGrid с Align = alClient, но фокус не передаётся в это окно, остаётся в Edit'е и по мере ввода текста в Edit происходит поиск наиоблее подходящего значения справочника. Обработаны так же нажатия клавиш на Edit - стрелка вверх/вниз (Next и Prior для датасета справочника) и Tab - как я уже говорил. При нажатии Enter в Edit подставляется текстовое значение из справочника, а в определённой переменной сохраняется ID записи справочника, после чего окно справочника закрывается, и фокус переходит к следующему компоненту формы.
То есть здесь не используется Data-aware компонентов на форме ввода. Только в справочнике (Grid, DataSource, который ссылается на Dataset разположенный на DataModule)

beresa
Сообщения: 9
Зарегистрирован: 05 дек 2007, 16:45

Re: Работа с Lookup-полями.

Сообщение beresa » 16 сен 2008, 15:18

Kotъ-Begemotъ, спасибо большое за подробное объяснение. С воодушевлением принялся за воплощение вашей идеи. И когда сделал так, как вы описали, появилась даже мысль разработать собственный компонент. Поэтому начал разбираться как делаются компоненты, просматривать исходники. В исходнах компонента DBLookupComboboxEh обратил внимание на свойство Style. И оказалось, что если выставить Style равным csDropDownEh (по умолчанию стоит csDropDownListEh), то в поле ввода можно вводить такие значение, которых ещё нет в справочнике. А это как раз мне было и нужно!

Итак, если вы хотите обеспечить максимум комфорта пользователям при добавлении данных в базу, рекомендую следующее.
Во-первых и самое главное – использоватать обязательно компонент DBLookupComboboxEh (данных компонент входит в библиотеку Еhlib, которая для «нашего брата» бесплатна). Далее в свойствах этого компонента установите следующее:
DataSource – источник данных главной таблицы
DataField– поле внешнего ключа, ссылающегося на справочник, в главной таблице
ListSource – источник данных справочника
KeyField – поле первичного ключа в справочнике
ListField – поле, значение которого будут показываться в выпадающем списке.
Style = csDropDownEh. (в этом случае появляется возможность вводить в поле ввода такие значения, которых нет в справочнике);
DropDownBox->AutoDrop = true. (по мере ввода данных автоматически будет появляться выпадающий список).

А теперь исходники:

Код: Выделить всё

procedure TfMain.lcbEhChange(Sender: TObject);
var
  s: string;
begin
  with TDBLookupComboboxEh(Sender) do begin
    if Tag = 0 then
      exit;

    s := Copy (Text, 0, SelStart);
    //фильтруем
    ListSource.DataSet.Filtered := false;
    ListSource.DataSet.Filter := ListField + ' LIKE ''' + s + '%''';
    ListSource.DataSet.Filtered := true;

    Tag := 0;
end;
end;

procedure TfMain.lcbEhExit(Sender: TObject);
var
  s: string;
begin
with TDBLookupComboboxEh(Sender) do begin
   // если введенного текста нет в справочнике, то добавляем
  if (Text<> ListSource.DataSet.FieldByName(ListField).AsString)
    and (Text <> '') then
  // но сначала спросим у пользователя
  if Application.MessageBox(pChar('Вы действительно хотите' +
    'добавить в справочник "'+ Hint+'" запись "'+Text+'"?'),
    'Подтверждение', MB_ICONINFORMATION + MB_OKCANCEL) = id_ok then
  begin
    // добавляем в справочник
    ListSource.DataSet.Insert;
    ListSource.DataSet.FieldByName(ListField).AsString := Text;
    ListSource.DataSet.Post;
    s := Text;
    ListSource.DataSet.Close;
    ListSource.DataSet.Open;

    // а затем в основную таблицу
    ListSource.DataSet.Locate(ListField, s, [loCaseInsensitive]);
    DataSource.DataSet.FieldByName(DataField).AsInteger :=
      ListSource.DataSet.FieldByName(KeyField).AsInteger;
  end;

    // отмена фильтрации в справочнике
    ListSource.DataSet.Filtered := false;
    ListSource.DataSet.Filter := '';
    ListSource.DataSet.Filtered := true;
end;
end;

procedure TfMain.lcbEhKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
with TDBLookupComboboxEh(Sender) do begin
if Char(key) = #13 then begin
  DataSource.DataSet.FieldByName(DataField).AsString :=
    ListSource.DataSet.FieldByName(KeyField).AsString;
  SelectNext(Sender as TWinControl, True, True);
end;

end;
end;

procedure TfMain.lcbEhKeyPress(Sender: TObject; var Key: Char);
begin
  TDBLookupComboboxEh(Sender).Tag := 1;
  //Чтобы  не было лишнего звука при нажатии на Enter
   if Key = #13 then
     Key := #0;
end;
Я думаю ясно, что событию OnChange нужно назначить процедуру lcbEhChange, OnKeyDown lcbEhKeyDown и т.д.
Приведу небольшие комментарии.
Фильтрацию данных по мере ввода текста пользователем реализуем в событии OnChange (процедура lcbEhChange). Было замечено, что в некоторых случаях событие OnChange у компонента DBLookupComboboxEh срабатывает несколько раз подряд, поэтому в lcbEhKeyDown свойству Tag компонента присваиваем 1, а в конце процедуры lcbEhChange это свойство делаем равным 0;

Процедуры lcbEhKeyDown и lcbEhKeyPress необходимы для того, чтобы при выборе из выпадающего списка каких-либо значений с помощью клавиш стрелка вверх/вниз и нажатии на Enter осуществлялся переход к следующему компоненту. Пришлось использовать процедуру OnKeyDown, т.к. при выборе нажатием на Enter значений из списка, в событие OnKeyPress невозможно перехватить нажатие на Enter (компонент в этом случае при нажатии на Enter присваивает переменной Key код клавиши 0).

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

В конце замечу, что описанное выше идеально подходит для простых справочников, т.е. в которых всего два поля - первичный ключ и какое-либо значение. Если имеем дела со справочниками, у которых несколько полей, то без кнопочки, вызывающей форму для редактирования, тут уж не обойтись.

EhLib супер! =D>

Ответить