Поместите TCheckBox внутри TStringGrid в Delphi

Я хочу поставить TCheckBox внутри TStringGrid в Delphi в каждой ячейке определенного столбца. Я использую Delphi XE.

Ответ 1

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

const
  Checked: array[1..4] of boolean = (false, true, false, true);

procedure TForm4.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
const
  PADDING = 4;
var
  h: HTHEME;
  s: TSize;
  r: TRect;
begin
  if (ACol = 2) and (ARow >= 1) then
  begin
    FillRect(StringGrid1.Canvas.Handle, Rect, GetStockObject(WHITE_BRUSH));
    s.cx := GetSystemMetrics(SM_CXMENUCHECK);
    s.cy := GetSystemMetrics(SM_CYMENUCHECK);
    if UseThemes then
    begin
      h := OpenThemeData(StringGrid1.Handle, 'BUTTON');
      if h <> 0 then
        try
          GetThemePartSize(h,
            StringGrid1.Canvas.Handle,
            BP_CHECKBOX,
            CBS_CHECKEDNORMAL,
            nil,
            TS_DRAW,
            s);
          r.Top := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2;
          r.Bottom := r.Top + s.cy;
          r.Left := Rect.Left + PADDING;
          r.Right := r.Left + s.cx;
          DrawThemeBackground(h,
            StringGrid1.Canvas.Handle,
            BP_CHECKBOX,
            IfThen(Checked[ARow], CBS_CHECKEDNORMAL, CBS_UNCHECKEDNORMAL),
            r,
            nil);
        finally
          CloseThemeData(h);
        end;
    end
    else
    begin
      r.Top := Rect.Top + (Rect.Bottom - Rect.Top - s.cy) div 2;
      r.Bottom := r.Top + s.cy;
      r.Left := Rect.Left + PADDING;
      r.Right := r.Left + s.cx;
      DrawFrameControl(StringGrid1.Canvas.Handle,
        r,
        DFC_BUTTON,
        IfThen(Checked[ARow], DFCS_CHECKED, DFCS_BUTTONCHECK));
    end;
    r := Classes.Rect(r.Right + PADDING, Rect.Top, Rect.Right, Rect.Bottom);
    DrawText(StringGrid1.Canvas.Handle,
      StringGrid1.Cells[ACol, ARow],
      length(StringGrid1.Cells[ACol, ARow]),
      r,
      DT_SINGLELINE or DT_VCENTER or DT_LEFT or DT_END_ELLIPSIS);
  end;
end;

Конечно, в реальном сценарии массив Checked не является константой, и вы можете сохранить метрики s и дескриптор темы h между событиями рисования ячеек. Но принцип здесь.

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

РЕДАКТИРОВАНИЕ синим цветом: Чтобы переключить состояние флажка, этот ответ объясняет, как можно использовать метод Invalidate.

Ответ 2

Не пытайтесь установить фактический элемент управления TCheckBox внутри TStringGrid. Используйте событие grid OnDrawCell с помощью функции Win32 API DrawFrameControl(), чтобы нарисовать изображение элемента управления CheckBox внутри каждой ячейки по мере необходимости. Вы можете использовать события OnClick/OnMouse... с помощью свойства grid Objects[][], чтобы отслеживать состояние каждой ячейки, если необходимо. Я считаю, что это намного проще в управлении, поскольку TStringGrid не предназначен для размещения реальных элементов управления.

Ответ 3

Я использую виртуальную сетку под названием ExGridView Романа Мочалова, который поддерживает флажки.

Мой собственный модифицированный виль GridView, портированный для Unicode и т.д., с именем TExGridView вместо TGridView и с демонстрацией флажков находится на битбакете здесь as/wpostma/exgridview.

Компонент ExGridView имеет свойство Checkbox в инспекторе свойств, которое должно быть установлено true. Затем вы должны настроить свои свойства столбца, чтобы в столбце был установлен флажок, установленный на флажок или переключатель. Затем вы должны реализовать обратный вызов события GetCheckState. См. Демонстрацию, включенную в проект bitbucket.

Исходный источник этого кода был здесь, но он не может быть создан для последних версий. Моя версия bitbucket протестирована и работает с Delphi 2007, 2009 и всеми версиями до 2016 года (Delphi 10 Seattle).

enter image description here