1

继这个问题及其非常有用的答案之后:我在我的项目中实现了肯的答案的变体,在那里我有类似的代码以多种形式出现。但我注意到我也有一些带有 DrawColumnCell 处理程序的表单,如下所示

procedure TEditDocket.DBGrid1DrawColumnCell(Sender: TObject;
           const Rect: TRect; DataCol: Integer; Column: TColumn;
           State: TGridDrawState);
var
 DrawRect: TRect;

begin
 if column.Index  = 3 then
  begin
   DrawRect:= Rect;
   drawrect.left:= rect.left + 24;
   InflateRect (DrawRect, -1, -1);
   dbgrid1.Canvas.FillRect (Rect);
   DrawFrameControl (dbgrid1.Canvas.Handle, DrawRect, DFC_BUTTON,
                 ISChecked[Column.Field.AsInteger]);
  end
 else dbgrid1.DefaultDrawColumnCell (Rect, DataCol, Column, State);
end;

如何将上述代码与通用 OnDrawColumnCell 处理程序结合起来?是否可以使用额外的参数定义通用处理程序(这将是列索引;如果它是 -1,那么上面的代码将不会执行)?我如何将这样的参数传递给处理程序?

4

3 回答 3

1

独立地,我使用网格的“标签”属性得出了以下答案。

在客户表格中,我写

 dbGrid1.OnDrawColumnCell:= dm.DBGrid1DrawColumnCell;
 dbGrid1.tag:= 3;  // column with checkbox
 dbGrid2.OnDrawColumnCell:= dm.DBGrid1DrawColumnCell;
 dbGrid2.tag:= $23;  // both columns 2 and 3 are checkboxes 

默认处理程序现在是

procedure TDm.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
          DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
  IsChecked : array[0..1] of Integer =
                (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED);

var
 DrawRect: TRect;
 tag: integer;
 cols: set of byte;

begin
 if sender is TDBGrid then
  begin
   tag:= TDBGrid (sender).tag;
   if (THackDBGrid (sender).DataLink.ActiveRecord + 1 = THackDBGrid (sender).Row)
   or (gdFocused in State) or (gdSelected in State) then
    with TDBGrid (sender) do
     begin
      canvas.Brush.Color:= clMoneyGreen;
      canvas.font.color:= clNavy;
     end;

   cols:= [];
   while tag > 0 do
    begin
     cols:= cols + [tag mod 16];
     tag:= tag div 16
    end;

   if column.Index in cols then
    begin
     DrawRect:= Rect;
     drawrect.left:= rect.left + 24;
     InflateRect (DrawRect, -1, -1);
     TDBGrid (sender).Canvas.FillRect (Rect);
     DrawFrameControl (TDBGrid (sender).Canvas.Handle, DrawRect, DFC_BUTTON,
                   ISChecked[Column.Field.AsInteger]);
    end
   else
    begin
     TDBGrid (sender).DefaultDrawColumnCell (Rect, DataCol, Column, State);
    end;
  end;
end;

这意味着第 0 列决不能是复选框。使用一个集合最多允许网格中的四列是复选框。

于 2014-02-28T19:41:06.677 回答
1

我看到(从评论链)你想要调用通用或(在某些情况下)也调用复选框绘图的代码。

通用 OnDrawColumnCell 处理程序处理单元格的背景颜色。如何扩展它以创建一个处理程序,该处理程序也将在需要时绘制复选框?顺便说一句,通用代码必须在复选框代码之前调用,而不是之后。

这其实很简单。使用正确的签名定义这两种方法(通用方法和复选框方法)(未经测试的代码!)。不过,仅将通用事件连接到TDBGrid.OnDrawColumnCell事件 - 如果需要,将链接复选框:

// Generic (from my other post) - notice method name has changed
procedure TDataModule1.GenericDrawColumnCell(Sender: TObject; 
  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
const
  RowColors: array[Boolean] of TColor = (clSilver, clDkGray);
var
  OddRow: Boolean;
  Grid: TDBGrid;
begin
  if (Sender is TDBGrid) then
  begin
    Grid := TDBGrid(Sender);
    OddRow := Odd(Grid.DataSource.DataSet.RecNo);
    Grid.Canvas.Brush.Color := RowColors[OddRow];
    Grid.DefaultDrawColumnCell(Rect, DataCol, Column, State);

    // If you want the check box code to only run for a single grid,
    // you can add that check here using something like
    //
    // if (Column.Index = 3) and (Sender = DBGrid1) then
    //
    if (Column.Index = 3) then // 
      CheckBoxDrawColumCell(Sender, Rect, DataCol, Column, State)
  end;
end;

// Checkbox (from yours) - again, notice method name change.
procedure TEditDocket.CheckBoxDrawColumnCell(Sender: TObject; 
  const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState);
var
 DrawRect: TRect;
 Grid: TDBGrid;
begin
  // Don't use DBGrid1, because it makes the code specific to a single grid.
  // If you need it for that, make sure this code only gets called for that 
  // grid instead in the generic handler; you can then use it for another 
  // grid later (or a different one) without breaking any code
  if column.Index = 3 then
  begin
    Grid := TDBGrid(Sender);
    DrawRect:= Rect;
    Drawrect.Left := Rect.Left + 24;
    InflateRect (DrawRect, -1, -1);
    Grid.Canvas.FillRect (Rect);
    DrawFrameControl (Grid.Canvas.Handle, DrawRect, DFC_BUTTON,
      ISChecked[Column.Field.AsInteger]);  // Don't know what ISChecked is 
   end;

   // The below should no longer be needed, because DefaultDrawColumnCell has
   // been called by the generic handler already.
   //
   // else 
   //  Grid.DefaultDrawColumnCell (Rect, DataCol, Column, State);
end;

看到您对 Sertac 的评论后:

在一个网格中,它可能是第 3 列,而它可能是需要绘制为复选框的第 4 列。

我在上面的代码中提供了一种方法来解决这个问题(请参阅 中的注释GenericDrawColumnCell)。另一种选择(假设您在每个网格中只有一列需要复选框)是在属性中指示包含复选框的列TDBGrid.Tag

if (Column.Index = Grid.Tag) then
于 2014-02-28T16:20:55.897 回答
0

希望这对使用原生 TDBGrid 的 c++ builder XE 用户也有帮助。下面的代码在 TDBGrid 列中添加了一个复选框图像。


void GridCheckbox( TColumn *Column, const TRect &Rect, bool isChecked, bool isCentered)
{
    
    //use or call this function inside OnDrawColumnCell
       
    TDBGrid *grd = (TDBGrid*)Column->Grid;

    String sImg;
    if (isChecked){   // record current status if checked or unchecked      
        sImg = "" + checkbox_on.bmp"; 
    }else{
        sImg = "" + checkbox_off.bmp";
    }

    if ( FileExists(sImg) ){

        TBitmap *img;
        img = new TBitmap();
        img->Transparent = True;
        img->TransparentColor = img->Canvas->Brush->Color;
        // img->TransparentMode = tmAuto;
        img->LoadFromFile(sImg);

        int ntLeft = Rect.Left + 5;
        if ( isCentered ) ntLeft = Rect.Left + ( (Rect.Width() / 2) - (img->Width / 2) ) ;

        grd->Canvas->Draw(ntLeft, Rect.Top + 2,img);

        delete img;
    }

}
于 2021-09-30T01:59:42.843 回答