lk75 lk75 - 1 month ago 14
Pascal Question

Drawing and image on a button in a cell in a TStringGrid

I have a TStringGrid in Lazarus, running on Linux. I have a column which has editor type cbsButton. I want the button to display a certain image, instead of an ellipsis. I have the following code, which causes an error:

procedure TForm1.streams_gridDrawCell(Sender: TObject; aCol, aRow: Integer; aRect: TRect; aState: TGridDrawState);
var
aCanvas: TCanvas;
aGrid: TStringGrid;
Editor: TWinControl;
image: TImage;
begin
if (aCol <> 1) or (aRow = 0) then begin
Exit;
end;

aGrid := (Sender as TStringGrid);

aCanvas := image.Canvas;
aCanvas.FillRect(aRect);
imagelist1.Draw(aCanvas, aRect.Left+2, aRect.Top+2, 8);

Editor := (aGrid.EditorByStyle(cbsButton) as TButtonCellEditor);
Editor.Brush.Style := TBrushStyle.bsImage;
(Editor.Brush.Image as TImage) := image; // causes the error below
end;


The error is:


mainform.pas(156,23) Error: Class or Object types "TFPCustomImage" and
"TImage" are not related


At this point, I'm sure I'm going about this in entirely the wrong way. Could someone please put me back on the right path?

Answer

I doubt that the OnDrawCell event is the correct place to modify a cell editor because probably the correct cell editor does not exist at this moment when the cell is painted.

The correct event to define the cell editor is the OnSelectEditor event of the grid. Please read the wiki (http://wiki.lazarus.freepascal.org/Grids_Reference_Page).

The cbsButton editor which you use inherits from TButton. A TButton does not have a Glyph property - you cannot assign a bitmap to the button. But can you write your own cell editor easily, just follow the standard example in examples/gridexamples/gridcelleditor:

  • Add a TBitBtn to the form. Delete its Caption, add the requested image to the Glyph property. Set the Visible property to false.
  • In the OnClick event of this button write how you want to edit the cell. Access the cell specified by the properties Col and Row of the grid. As an example, I assume here that you just want to open an InputBox:
    procedure TForm1.BitBtn1Click(Sender: TObject);
    begin
      StringGrid1.Cells[StringGrid1.Col, StringGrid1.Row] := 
        InputBox('Input some text', 'Text:', '');
    end;
  • Now write an event handler for the OnSelectEditor event of the grid. It must assign the BitBtn to the Editor parameter of the event and make sure that the button is at the correct position within the selected cell - that's all!
    procedure TForm1.StringGrid1SelectEditor(Sender: TObject; aCol, aRow: Integer;
      var Editor: TWinControl);
    var
      R: TRect;
    begin
      if (aCol=2) and (aRow > 0) then begin
        R := StringGrid1.CellRect(aCol, ARow);
        R.Left := R.Right - (R.Bottom - R.Top);
        BitBtn1.BoundsRect := R;
        Editor := BitBtn1;
      end;
    end;