DBGrid+AutoComplete

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

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

DBGrid+AutoComplete

Сообщение lordgray » 26.08.2017 12:52:00

Здравствуйте! Решил сделать автозаполнение при вводе в DBGrid, как в 1с8, когда в документе в колонке товара начинаешь писать, она, если 1 вариант, то сразу подставляет в ячейку, если найдено несколько вариантов, выпадает список для выбора, при этом можно продолжать писать, для уточнения, и список сокращается. Например: есть справочник товаров, в котором есть "вобла", "вода", "водка". Вводим "во", и выпадает список со всеми тремя позициями. Продолжаем ввод, "вод", и в списке уже 2 элемента, далее вводим "водк", и программа сама дополняет ячейку до "водка".

Теперь, как и что я делал. Пишу пока под Debian Jessi x64, но будет и под Windows. Lazarus 1.6.2. Решил подменить стандартный редактор ячейки типа TPickListCellEditor, чтобы сделать доступным его OnChange.
Код: Выделить всё
TMyPickListCellEditor = class(TPickListCellEditor)
public
  property OnChange;
end;

У формы объявил переменную, где будет ссылка на экземпляр редактора
Код: Выделить всё
fNameEditor: TCompositeCellEditor;
fPickListEditor: TMyPickListEditor;

Композитный редактор нужен, чтобы помимо ручного ввода и выпадающего списка, была кнопка для вызова справочника для подбора. Далее, при создании формы, инициализирую редактор:
Код: Выделить всё
fPickListEditor := TMyPickListEditor.Create(Self);
fPickListEditor.Name := 'PickListEditor';
fPickListEditor.Visible := False;
fPickListEditor.AutoSize := False;
fPickListEditor.OnChange := @Self.NameChange;
//fPickListEditor.AutoComplete := True;
TStringList(fPickListEditor.Items).OwnsObject := True;

fNameEditor := TCompositeCellEditor.Create(Self)
fNameEditor.Name := 'NameEditor';
fNameEditor.Visible := False;
fNameEditor.AddEditor(fPickListEditor, alClient, True);
fNameEditor.AddEditor(G.EditorByStyle(cbsButton), alRight, False);//G - мой DBGrid

У DBGrid сел на OnSelectEditor, чтобы подставить свой редактор
Код: Выделить всё
procedure TDocForm.GSelectEditor(Sender: TObject; Column: TColumn; var Editor: TWinControl);
begin
  if SameText(Column.FieldName, 'NAME') then Editor := fNameEditor;
end;

Ну и действия при изменении текста в ячейке:
Код: Выделить всё
procedure TDocForm.NameChange(Sender: TObject);
var
  Item: TLstItem;
  CB: TMyPickListCellEditor;
begin
  CB := Sender as TMyPickListCellEditor;
  CB.Items.Clear;
  if UTF8Length(CB.Text) > 1 then
  begin
    IBSQL.Close;
    IBSQL.SQL.Text := 'select first 11 * from tovars where upper(name) starting upper(:n)';
    IBSQL.ParamByName('n').AsString := CB.Text;
    IBSQL.ExecQuery;
    while not IBSQL.Eof do
    begin
      Item := TLstItem.Create;
      Item.ID := IBSQL.FieldByName('ID').AsInteger;
      Item.NAME := IBSQL.FieldByName('NAME').AsString;
      CB.AddItem(Item.Name, Item);
      IBSQL.Next;
    end;
    if CB.Items.Count > 0 then CB.DroppedDown := True;
  end;
end;


Теперь сам вопрос: когда список выпадает (CB.DroppedDown := True), ввод в ячейку становится недоступным. Похоже, что выпавший список получает фокус ввода. Где и что надо дописать, чтобы, после выпадания списка, можно было продолжать ввод в ячейку?

P.S. Это, так сказать, пробный код, в конечном коде будет подругому, как минимум, запрос и заполнение выпадающего списка вынесу в поток, на случай, если запрос будет долго выполняться. Ну и т.д.

Так много написал, чтоб ясно было, что и как сделал, вдруг кому пригодится мой опыт, задача ведь распространенная.
lordgray
новенький
 
Сообщения: 39
Зарегистрирован: 10.10.2010 00:19:11

Re: DBGrid+AutoComplete

Сообщение olegy123 » 26.08.2017 13:11:47

lordgray писал(а):Теперь сам вопрос: когда список выпадает (CB.DroppedDown := True), ввод в ячейку становится недоступным. Похоже, что выпавший список получает фокус ввода. Где и что надо дописать, чтобы, после выпадания списка, можно было продолжать ввод в ячейку?

Список - это другое окно, без заголовка и бордюра.
Можно переключить фокус ввода, можно ввод перенаправлять в родительское.
olegy123
энтузиаст
 
Сообщения: 583
Зарегистрирован: 25.02.2016 12:10:20

Re: DBGrid+AutoComplete

Сообщение lordgray » 26.08.2017 13:22:02

olegy123 писал(а):Список - это другое окно, без заголовка и бордюра.
Можно переключить фокус ввода

С фокусом не получилось. Делал
Код: Выделить всё
   ...
   CB.DroppedDown := True;
   CB.SetFocus;

Не помогает. Если в Delphi ComboBox действительно состоит из Edit+ListBox, то в Лазаре это что-то другое, у компонента нет ссылки на окно списка (или я слепой). Соответственно, и сесть на ввод в списке не понятно как :?:
lordgray
новенький
 
Сообщения: 39
Зарегистрирован: 10.10.2010 00:19:11

Re: DBGrid+AutoComplete

Сообщение LearnMagic » 27.08.2017 02:11:14

lordgray, см. исходники EditBtn или библиотеку RX (обсуждение, исходники)
LearnMagic
новенький
 
Сообщения: 21
Зарегистрирован: 10.11.2016 23:13:38

Re: DBGrid+AutoComplete

Сообщение lordgray » 27.08.2017 11:33:43

Спасибо, посмотрю.
Начинаю склоняться к мысли, что, ну его, этот TPickListCellEditor, может задействовать обычный Edit и самому к нему привязать список. В общем, посмотрю, подумаю, попробую... Если получится, отпишусь.
lordgray
новенький
 
Сообщения: 39
Зарегистрирован: 10.10.2010 00:19:11

Re: DBGrid+AutoComplete

Сообщение olegy123 » 28.08.2017 00:50:39

На сколько помню, то можно обычный ComboBox задействовать.
Но нужно посылать сообщения на выпадающий список об обновлении..
в процедуре, которая принимает сообщения читаешь что вписано в edit и обновляешь список по логике.


это оно?
https://stackoverflow.com/questions/546 ... hi/5465826
olegy123
энтузиаст
 
Сообщения: 583
Зарегистрирован: 25.02.2016 12:10:20

Re: DBGrid+AutoComplete

Сообщение lordgray » 28.08.2017 12:19:15

Это то, что я уже сделал. Надо наоборот, не список обновлять, когда вводишь (это я сделал, нормально работает), а иметь возможность продолжать вводить, когда список выпал. А он не дает, перехватывает все события. Если б он в комбобоксе был отдельным компонентом, я б его перекрыл и перенаправил ввод, но он вообще непонятно, как реализован. Докопал до ВиджетСетов, но методы исходников пустые.

Порылся я в EditBtn, и решил отказаться от комбобокса, решил использовать обычный MaskEdit + ListBox. Еще не дописал, но, пока все получается (список выпадает, фокус не забирает). Допишу - выложу
lordgray
новенький
 
Сообщения: 39
Зарегистрирован: 10.10.2010 00:19:11

Re: DBGrid+AutoComplete

Сообщение pupsik » 28.08.2017 16:53:43

а это, для примера подойдёт?
pupsik
энтузиаст
 
Сообщения: 992
Зарегистрирован: 20.08.2014 16:20:13

Re: DBGrid+AutoComplete

Сообщение Лекс Айрин » 28.08.2017 17:15:31

lordgray писал(а):Это то, что я уже сделал. Надо наоборот, не список обновлять, когда вводишь (это я сделал, нормально работает), а иметь возможность продолжать вводить, когда список выпал.

Запрещаешь AutoComplete и AutoSelect. Поле ввода это text при вводе в него сокращаешь количество элементов(можно просто тупо удалять, т. к. всегда можно заново загрузить и если остается один, то присваиваешь его Text. Связка из обычного Editа и списка сложнее в реализации.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 3931
Зарегистрирован: 19.02.2013 16:54:51

Re: DBGrid+AutoComplete

Сообщение lordgray » 30.08.2017 16:56:59

pupsik писал(а):а это, для примера подойдёт?

Ну да, можно прикрутить. Примерно тем же путем иду, пробую. Спасибо!
Лекс Айрин писал(а):Запрещаешь AutoComplete и AutoSelect. Поле ввода это text при вводе в него сокращаешь количество элементов(можно просто тупо удалять, т. к. всегда можно заново загрузить и если остается один, то присваиваешь его Text.

Это все я уже попробовал, все работает на ура. Но! НАДО не просто AutoComplete. Его достаточно, когда точно знаешь название, а если только примерно? Для этого и нужен выпадающий список, чтоб человек видел, какие есть варианты, и дописал или выбрал. Бывают же многопользовательские проги, и на 100% нельзя быть уверенным, как другой пользователь завел товар/клиента. Может он опечатался, или два пробела поставил, вместо одного. А так, выпал список и все видно.
lordgray
новенький
 
Сообщения: 39
Зарегистрирован: 10.10.2010 00:19:11

Re: DBGrid+AutoComplete

Сообщение Лекс Айрин » 30.08.2017 17:32:48

lordgray, не знаю, почему у тебя не получается, но логика действий элементарна. Просто по мере ввода из списка убираешь неподходящие элементы. И, кстати, если вводить без учета определенных служебных правил, то никакой автокомплит не поможет -- названия позиций могут различаться достаточно сильно. Например, я встречал; системная или материнская платы. Иногда пишут по английски ( motherboard или mainboard).
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 3931
Зарегистрирован: 19.02.2013 16:54:51


Вернуться в Lazarus

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

Сейчас этот форум просматривают: Google Adsense [Bot] и гости: 8

Рейтинг@Mail.ru