checkboxes2Доброго времени суток дорогие читатели блога. Хочу поздравить Вас с прошедшими праздниками, пожелать в Новом Году всего самого наилучшего, выполнению всех желаний, чтобы у Вас было все, как Вы задумали. Теперь давайте вернемся непосредственно к самой статье.

Давайте продолжим нашу тему по работе с checkboxes в TDBGrid с использованием вычисляемого поля (предлагаю вспомнить первую часть статьи). В данной статье мы рассмотрим, как можно вообще работать с отмеченными записями подобным образом. То есть, когда у нас значение поля checkboxes хранилось в поле таблицы (True или False, 1 или 0), можно было циклом или запросом выбрать нужные нам записи, здесь ситуация почти похожая.

В данной статье мы рассмотрим следующие нюансы:

  • Поиск нужного значения (отмечаем запись checkboxes)
  • Удаление отмеченных записей
  • Выборка отмеченных записей
  • Отметка всех записей отображенных в TDBGrid
  • Снятие отметки всех записей отображенных в TDBGrid

На самом деле, подобным образом с отмеченными записями можно производить любые операции. Это связано с тем, что идентификатор этих записей у нас хранятся в универсальном списке TList. А если у нас есть идентификатор записи, то можно его и удалить с таблицы и найти и так далее.

Давайте начнем с того, что нам необходимо поместить идентификаторы отмеченных записей в сам список TList (у меня переменная списка – ListSelect). Тут необходимо определиться, по какому событию мы будем добавлять в наш список идентификаторы записей. Обычно это делается, когда пользователь нажимает на сам checkboxes, но у меня еще сделано таким образом, что выделять (отмечать) запись можно и клавишей пробел (Space) с переходом на последующую строку. Поэтому, отмечать записи можно по любому событию, как будет удобно.

Мы сделаем все стандартно – по нажатию (клику) на запись (самому checkboxes). Для этого выделяем TDBGridEh, переходим во вкладку события и находим событие OnCellClick. Затем на данное событие пишем следующий код:

procedure TForm2.DBGridEh1CellClick(Column: TColumnEh);
var Value : Integer;
begin
 if CompareText(Column.Field.FieldName , 'SEL') = 0 then begin
   Value := Column.Field.DataSet.FieldByName('ID').AsInteger;
   if ListSelect.Count > 0 then
     if ListSelect.IndexOf(Pointer(Value)) >=0 then
       ListSelect.Delete(ListSelect.IndexOf(Pointer(Value)))
     else begin
       ListSelect.Add(Pointer(Value));
     end else begin
       ListSelect.Add(Pointer(Value));
     end;
  DBGridEh1.Columns[0].Footer.Value:=IntToStr(ListSelect.Count);
  Column.Grid.Refresh;
 end;
end;

Давайте немного разберем код. Вы помните, что согласно прошлой статье у нас ListSelect: TList;

Код у нас самый простой. Мы получаем идентификатор нашей записи — это поле ID — в моей таблице – уникальное (простым языком – поле-счетчик). Затем проверяем наличие этого идентификатора в нашем списке, если есть и пользователь снимает галочку (отметку) checkboxes, то нам необходимо удалить его и из списка, если в списке его нет, то необходимо добавить в список, чтобы в дальнейшем производить определенные действия с этой записью.

Этот код Вы можете применить на любое событие, чтобы отмеченная запись добавлялась в наш список (ее идентификатор). Я уже говорил, что у меня еще данные код написан на событие TDBGridEh – OnKeyDown. Там я проверяю, если была нажата клавиша Пробел, то также отмечаю запись checkboxes.

Теперь, давайте также добавим идентификатор записи в список при поиске. Например, имеется у нас TEdit, в нем мы будем вводить данные, а программа будет искать совпадения, если имеется, то переходить на эту запись и ставить отметку checkboxes. На событие OnChange компонента TEdit мы напишем следующий код:

procedure TForm2.cxTextEdit1PropertiesChange(Sender: TObject);
var
 Value:integer;
begin
   try
    if ADOQuery1.Active=True then
     begin
      if ADOQuery1.Locate('JARLIK', cxTextEdit1.Text, [loCaseInsensitive]) then
       begin
        if CompareText(DBGridEh1.Columns.Items[0].Field.FieldName , 'SEL') = 0 then begin
         Value := DBGridEh1.Columns.Items[0].Field.DataSet.FieldByName('ID').AsInteger;
        if ListSelect.Count > 0 then
         if ListSelect.IndexOf(Pointer(Value)) >=0 then
          ListSelect.Delete(ListSelect.IndexOf(Pointer(Value)))
         else begin
          ListSelect.Add(Pointer(Value));
         end else begin
          ListSelect.Add(Pointer(Value));
         end;
        DBGridEh1.Columns[0].Footer.Value:=IntToStr(ListSelect.Count);
        DBGridEh1.Columns.Items[0].Grid.Refresh;
      end;
     end;
   except
    on e:Exception do
   end;
end;

То есть, у нас опять же, все тоже самое, только добавляется условие поиска. Если есть совпадения, то переходим к данной строке и ставим отметку для записи, при повтором поиске этой записи, отметка убирается. Но если не хотите, чтобы отметка убиралась, то достаточно закомментировать или убрать строчку ListSelect.Delete(ListSelect.IndexOf(Pointer(Value))), где из списка удаляется идентификатор записи, при снятии галочки.

Идем дальше. Определить количество отмеченных записей не составит труда. Это можно вытащить из ListSelect.Count. То есть, просто выводим количество элементов в нашем списке.

Теперь переходим к самому интересному. Как же нам обработать все отмеченные записи. Например, давайте сделаем выборку всех записей, которые у нас отмечены checkboxes в нашем TDBGridEh.

Код у нас будет примерно следующим:

procedure TForm4.cxButton1Click(Sender: TObject);
var
   s:string;
   i:integer;
begin
   try
    s:='';
    for i:=0 to ListSelect.Count-1 do
     s:=s+IntToStr(Integer(ListSelect.Items[i]))+',';
    if s='' then
     Exit;
    s:='('+Copy(s, 1, Length(s)-1)+')';
    ADOQuery1.SQL.Clear;
    ADOQuery1.SQL.Add('SELECT * FROM DOSTAVKA WHERE ID IN '+S);
    ADOQuery1.Active:=True;
   except
    on e:Exception do
   end;
end;

Итак, давайте немного разбираться. Я уже Вам говорил, что в списках у нас хранятся уникальные идентификаторы записей в таблице. Зная их, мы можем делать в запросах с записями что угодно. Мы в цикле проходим по всем элементам списка и формируем строку, состоящую из наших идентификаторов записей. Строка будет иметь примерно следующий вид:

100,20,1,101

Далее мы просто делаем запрос, в котором в условии задаем, что необходимо выбирать все записи, поле ID которых содержится в нашей строке s, которая равна s=’100,20,1,101′

В итоге запрос нам должен вернуть 4 записи, идентификаторы (поле ID), которых равняется 100, 20, 1 и 101.

Ну а с записями в запросе можно делать, что Вам захочется. Таким же образом формируются и другие запросы: DELETE, UPDATE. Если надо удалить эти 4 записи, то запрос будет примерно таким:

ADOQuery1.SQL.Clear;
    ADOQuery1.SQL.Add('DELETE FROM DOSTAVKA WHERE ID IN '+S);
    ADOQuery1.ExecSQL;

В итоге запрос удалит 4 записи. Если необходимо обновить данные, то будет тоже самое с запросом UPDATE. Главное в условие запроса добавлять ID IN (либо другое ваше поле, которое соответствует уникальной записи таблицы)

Ну, давайте уже плавно подходить к концу нашей статьи и напоследок рассмотрим, как можно отметить все записи таблицы (проставить checkboxes) и снять выделение всех записей. Во многих программных продуктах замечали подобный функционал. Например, на панели инструментов имеется кнопка: выделить все и рядом – снять выделение для всех, у меня это выглядит примерно так:

img1

Например, функция, которая у меня отмечает все записи, выглядит следующим образом:

function GridSelectAll(Grid: TDBGridEh): Longint;
var
 value:integer;
begin
  Result:=0;
  Grid.SelectedRows.Clear;
  ListSelect.Clear;
  with Grid.Datasource.DataSet do
  begin
    First;
    DisableControls;
    try
      while not EOF do
      begin
       if CompareText(Form2.DBGridEh1.Columns.Items[0].Field.FieldName , 'SEL') = 0 then begin
         Value := Form2.DBGridEh1.Columns.Items[0].Field.DataSet.FieldByName('ID').AsInteger;
        if ListSelect.Count > 0 then
         if ListSelect.IndexOf(Pointer(Value)) >=0 then
          ListSelect.Delete(ListSelect.IndexOf(Pointer(Value)))
         else begin
          ListSelect.Add(Pointer(Value));
         end else begin
          ListSelect.Add(Pointer(Value));
        end;
        end;
        inc(Result);
        Next;
      end;
    finally
      EnableControls;
      Form2.DBGridEh1.Columns[0].Footer.Value:=IntToStr(ListSelect.Count);
    end;
  end;
end;

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

function GridNotSelectAll(Grid: TDBGridEh): Longint;
var
 value:integer;
begin
  Result:=0;
  Grid.SelectedRows.Clear;
  ListSelect.Clear;
  with Grid.Datasource.DataSet do
  begin
    First;
    DisableControls;
    try
      while not EOF do
      begin
       if CompareText(Form2.DBGridEh1.Columns.Items[0].Field.FieldName , 'SEL') = 0 then begin
         Value := Form2.DBGridEh1.Columns.Items[0].Field.DataSet.FieldByName('ID').AsInteger;
        if ListSelect.Count > 0 then
         if ListSelect.IndexOf(Pointer(Value)) >=0 then
          ListSelect.Delete(ListSelect.IndexOf(Pointer(Value)))
        end;
        inc(Result);
        Next;
      end;
    finally
      EnableControls;
      Form2.DBGridEh1.Columns[0].Footer.Value:=IntToStr(ListSelect.Count);
    end;
  end;
end;

Все тоже самое, в цикле проходимся, если запись отмечена, то удаляем из списка и так далее. Хотя я думаю можно сделать намного проще:

ListSelect.Clear;
DBGridEh1.Columns.Items[0].Grid.Refresh;

Очищаем список и обновляем наш грид.

Использовать функции можно: GridNotSelectAll(DBGridEh1) и GridSelectAll(DBGridEh1)

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

Также тут в комментариях сказали, что для чего использовать списки и вычисляемое поле, если есть компонент TMemTableEh из Ehlib и он отлично справляется с этой задачей. Возможно, но не забывайте, что данный способ работает на всех гридах, необязательно устанавливать компоненты Ehlib. Да и не непонятно еще, что больше грузит память: списки или TMemTableEh.

Удачи Вам и до новых встреч!

Метки: , , ,




К записи “Установка checkboxes в ячейках с использованием вычисляемоего поля. Часть 2” оставлено комментариев: 5.

    • Andrey:

      Всегда пожалуйста! Обращайтесь, если что непонятно, то пишите. Также если хотите, чтобы я рассмотрел какие-то темы определенные по Delphi, то также пишите, предлагайте!

  1. Володимир:

    Спасибо.
    1. Можно ли ето же сделать в стандартном гриде?
    2. Давно интересует пример как создать програму, которая работает на нескольких пк и совместно использует одну базу (mdb). Понимаю, что на центральном пк нужно создать сервер, на локальних клиенты, которые обращаются к серверу и он уже передает в базу. Но нигде нет примера как это реализовать. Желательно еще, чтоб клиенти сами в сети нашли сервер :) а не прописывать ip адрес на клиентах в ручную.

  2. Panacea:

    «данный способ работает на всех гридах, необязательно устанавливать компоненты Ehlib»
    И как на обычном dbgrid такое реализовать не покажете?

Оставить комментарий на Andrey

Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*