Карта сайтаСсылкиКонтакты

CheckBox внутри DBGrid

PDF Печать
Статьи

Есть способ разместить CheckBox в DBGrid для редактирования булевых полей в наборе данных. Предположим, что Вы имеете булево поле в наборе данных. По умолчанию, DBGrid отображает такое поле как True или False в зависимости от значения.

Создадим простое приложение.

Для начала запустим Delphi и разместим на форме TDBGrid, TADOTable, TADOConnection и TDataSource. Оставим все имена, как их определил Delphi. Используйте Инспектор Объектов, чтобы установить свойство ADOConnection компонента ADOConnection1DBGrid1 к DataSource1, DataSource1 к ADOTable1 и наконец, ADOTable1 к ADOConnection1. Свойство TableName компонента ADOTable1 должно указывать на таблицу, в которой мы имеем булево поле (например, Winner).

Если Вы установили все свойства правильно, то когда Вы запустите приложение (если свойство Active компонента TADOTable1 установлено в True), Вы должны видеть это:

Без CheckBox

Что же нужно сделать для того, чтобы наше приложение выглядело, как это, ниже:

С CheckBox

Выберите TDBCheckBox на палитре компонентов и поместите его где-нибудь на форме.

Затем установите его свойство Visible в False. Измените его свойство Color на тот же самый цвет, что и DBGrid1, чтобы он гармонировал с сеткой и удалите Caption. И, что не менее важно, удостоверьтесь, что DBCheckBox1 связан с DataSource1 и с полем (DataSource = DataSource1, DataField = Winner).

Обратите внимание, что все вышеперечисленные свойства могут быть установлены в событии OnCreate формы, например:


procedure TForm1.FormCreate(Sender: TObject);
begin
 DBCheckBox1.DataSource := DataSource1;
 DBCheckBox1.DataField  := 'Winner';
 DBCheckBox1.Visible    := False;
 DBCheckBox1.Color      := DBGrid1.Color;
 DBCheckBox1.Caption    := '';

 //будет разъяснено ниже в статье
 DBCheckBox1.ValueChecked := 'Да'; 
 DBCheckBox1.ValueUnChecked := 'Нет'; 
end;

Далее более интересная часть. При редактировании булева поля в DBGrid, мы должны удостовериться, что DBCheckBox1 помещен в ячейку DBGrid, в которой отображается булево поле. Для остальной части сетки булево поле также должно быть представлено каким-либо изображением (истинного или ложного значения). Это означает, что мы нуждаемся, как минимум в двух изображениях: одно для истинного значения (True) и одно для ложного значения (False). Самый легкий способ выполнить это состоит в том, чтобы использовать функцию Windows API DrawFrameControl, чтобы рисовать непосредственно на холсте DBGrid.

Вот код в обработчике события OnDrawColumnCell, которое происходит, когда сетка должна перерисовывать ячейку:


procedure TForm1.DBGrid1DrawColumnCell(
  Sender: TObject; const Rect: TRect; DataCol:
  Integer; Column: TColumn; State: TGridDrawState);
const IsChecked : array[Boolean] of Integer = 
      (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);
var
  DrawState: Integer;
  DrawRect: TRect;
begin
  if (gdFocused in State) then
  begin
    if (Column.Field.FieldName = DBCheckBox1.DataField) then
    begin
     DBCheckBox1.Left := Rect.Left + DBGrid1.Left + 2;
     DBCheckBox1.Top := Rect.Top + DBGrid1.top + 2;
     DBCheckBox1.Width := Rect.Right - Rect.Left;
     DBCheckBox1.Height := Rect.Bottom - Rect.Top;
     DBCheckBox1.Visible := True;
    end
  end
  else
  begin
    if (Column.Field.FieldName = DBCheckBox1.DataField) then
    begin
      DrawRect:=Rect;
      InflateRect(DrawRect, -1, -1);
      DrawState := ISChecked[Column.Field.AsBoolean];
      DBGrid1.Canvas.FillRect(Rect);
      DrawFrameControl(DBGrid1.Canvas.Handle, DrawRect, 
                       DFC_BUTTON, DrawState);
    end;
  end; 
end;

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


procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
  if DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField then
    DBCheckBox1.Visible := False
end;

Мы нуждаемся еще в обработке двух событий: перехват нажатия клавиатуры и нажатие на Пробел должен изменять состояние CheckBox.


procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
  if (key = Chr(9)) then Exit;
  if (DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField) then
  begin
    DBCheckBox1.SetFocus;
    SendMessage(DBCheckBox1.Handle, WM_Char, word(Key), 0);
  end;
end;

И, наконец, последнее. Это может быть соответствующий заголовок CheckBox, когда пользователь переключает его. Обратите внимание, что DBCheckBox имеет два свойства (ValueChecked и ValueUnChecked), которые определяют значение поля, представленное переключателем. В нашем случае мы можем записать ValueCheckedДа, а ValueUnChecked – Нет.


procedure TForm1.DBCheckBox1Click(Sender: TObject);
begin
  if DBCheckBox1.Checked then
     DBCheckBox1.Caption := DBCheckBox1.ValueChecked
  else
     DBCheckBox1.Caption := DBCheckBox1.ValueUnChecked;
end;

Это все! Запустите проект и проверьте действие переключателя.


 

Комментарии   

 
+1 #1 Константин 08.12.2013 14:17
Пишу прогу по вашему коду,
..."Вот код в обработчике события OnDrawColumnCel l, которое происходит, когда сетка должна перерисовывать ячейку:"...
в втроке - ..."DrawState := ISChecked[Column.Field.AsBoolean];"...
возникает проблемв, только не пойму где?
Цитировать
 
 
+1 #2 Serge 09.12.2013 20:53
А точно поле, на которое ссылается DBCheckBox имеет булево значение? Если не булево, будет выскакивать ошибка.
Цитировать
 
 
+1 #3 Константин 09.12.2013 21:05
С этим я разобрался, а вот когда в гриде нажимаешь на DBCheckBox, он уходит в лево, а не остается на месте. Как это сделать?
Цитировать
 
 
+1 #4 Serge 09.12.2013 21:58
В конструкции самого CheckBox не предусмотрено выравнивание по центру, поэтому он прорисовывается прижатым к левому краю. Проще написать свой CheckBox с выравниванием по центру.
Цитировать
 
 
+1 #5 Константин 16.03.2014 22:37
Помоги пожалуйста написать в конструкции самого DBCheckBox, процедуру выравнивание по центру, после того как в гриде нажимаешь на DBCheckBox, и он уходит в лево.
Цитировать
 
 
0 #6 Poluprovodnik 23.03.2014 10:53
Написал этот пример на Delphi XE5 - не работает :sad:
Как выводило в таблице True/False, так и выводит. Что не так?
Цитировать
 
 
0 #7 Константин 23.03.2014 21:16
Просто не прописывай процедуру:
procedure TForm1.DBCheckB ox1Click(Sender : TObject);
begin
if DBCheckBox1.Che cked then
DBCheckBox1.Cap tion := DBCheckBox1.Val ueChecked
else
DBCheckBox1.Cap tion := DBCheckBox1.Val ueUnChecked;
end;

и это не пиши:

//будет разъяснено ниже в статье
DBCheckBox1.Val ueChecked := 'Да';
DBCheckBox1.Val ueUnChecked := 'Нет';
Цитировать
 
 
0 #8 Alex 24.07.2017 17:11
Интересные эффекты наблюдались при изменении размеров столбца (столбец типа boolean стоял последним) в режиме редактирования.
Пришлось запретить
DBGrid1.Options := DBGrid1.Options - [dgColumnResize];
в момент DBCheckBox1.Vis ible := True;
а разрешать
DBGrid1.Options := DBGrid1.Options + [dgColumnResize];
после DBCheckBox1.Vis ible := False;

> Выберите TDBCheckBox на палитре компонентов и поместите его где-нибудь на форме.
Неверно для случаев, если DBGrid1 стоит на каком-нибудь TPageControl. DBCheckBox1 cледует ставить на один уровень в иерархии с DBGrid1.
А в целом спасибо за код!
Цитировать
 

Добавить комментарий


Защитный код
Обновить