Delphi StringGrid with picture in background
Asked Answered
S

3

3

Hi does anyone know if it is possible to display a picture as a background to a string grid, Or is anyone aware of any free Grid component that can do this.

Thanks

colin

Scolecite answered 12/3, 2011 at 21:37 Comment(0)
T
12

You could use a TDrawGrid (or a TStringGrid), which supports owner-drawing, and do

procedure TForm1.FormCreate(Sender: TObject);
begin
  FBg := TBitmap.Create;
  FBg.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\Sample.bmp');
end;

where FBg is a TBitmap (in the form class, for instance), and then do

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  r: TRect;
begin
  if not (Sender is TStringGrid) then Exit;
  BitBlt(TStringGrid(Sender).Canvas.Handle,
         Rect.Left,
         Rect.Top,
         Rect.Right - Rect.Left,
         Rect.Bottom - Rect.Top,
         FBg.Canvas.Handle,
         Rect.Left,
         Rect.Top,
         SRCCOPY);
  if gdSelected in State then
    InvertRect(TStringGrid(Sender).Canvas.Handle, Rect);
  r := Rect;
  TStringGrid(Sender).Canvas.Brush.Style := bsClear;
  DrawText(TStringGrid(Sender).Canvas.Handle,
           TStringGrid(Sender).Cells[ACol, ARow],
           length(TStringGrid(Sender).Cells[ACol, ARow]),
           r,
           DT_SINGLELINE or DT_VCENTER or DT_END_ELLIPSIS);
end;

Sample Screenshot Sample Screenshot Sample Screenshot

Tocology answered 12/3, 2011 at 21:45 Comment(4)
Good answer, but this will work with TStringGrid too, since it inherits from TDrawGrid.Bernal
@David, et al.: I am not sure: First I thought that I need to make sure that I don't try to make BitBlt read pixels that aren't there in the source bitmap, but it seems like the function is able to handle input of this kind in the most kind way there is, namely correcting for the "incorrect" input (like Copy, where you often specify MaxInt as the length of the string). Could you please enlighten me on this issue?Tocology
I presume this only works for the created cell of the TDrawGrid. What if the requirement is to have the background image extend into the parts of the TDrawGrid that aren't covered by cells, i.e. after the last row or columns?Athamas
@rossmcm: See the additional answer.Freytag
F
4

While actually answering here the explicit question of rossmcm in his comment to the code of Andreas Rejbrand, it also complements hís answer to the original question.

Drawing the image beyond the grid boundary, but still within the StringGrid control bounds could be achieved as follows:

type
  TStringGrid = class(Grids.TStringGrid)
  private
    FGraphic: TGraphic;
    FStretched: Boolean;
    function BackgroundVisible(var ClipRect: TRect): Boolean;
    procedure PaintBackground;
  protected
    procedure Paint; override;
    procedure Resize; override;
    procedure TopLeftChanged; override;
  public
    property BackgroundGraphic: TGraphic read FGraphic write FGraphic;
    property BackgroundStretched: Boolean read FStretched write FStretched;
  end;

  TForm1 = class(TForm)
    StringGrid: TStringGrid;
    Image: TImage;
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TStringGrid }

function TStringGrid.BackgroundVisible(var ClipRect: TRect): Boolean;
var
  Info: TGridDrawInfo;
  R: TRect;
begin
  CalcDrawInfo(Info);
  SetRect(ClipRect, 0, 0, Info.Horz.GridBoundary, Info.Vert.GridBoundary);
  R := ClientRect;
  Result := (ClipRect.Right < R.Right) or (ClipRect.Bottom < R.Bottom);
end;

procedure TStringGrid.Paint;
begin
  inherited Paint;
  PaintBackground;
end;

procedure TStringGrid.PaintBackground;
var
  R: TRect;
begin
  if (FGraphic <> nil) and BackgroundVisible(R) then
  begin
    with R do
      ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom);
    if FStretched then
      Canvas.StretchDraw(ClientRect, FGraphic)
    else
      Canvas.Draw(0, 0, FGraphic);
  end;
end;

procedure TStringGrid.Resize;
begin
  inherited Resize;
  PaintBackground;
end;

procedure TStringGrid.TopLeftChanged;
begin
  inherited TopLeftChanged;
  PaintBackground;
end;

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Usage: 
  StringGrid.BackgroundGraphic := Image.Picture.Graphic;
  StringGrid.BackgroundStretched := True;
end;

If you want to draw the image in the cells as well, then combine both techniques. That they do not follow the same approach, for Andreas uses events where I declare a descendant, should not lead to great difficulty with merging.

Freytag answered 25/5, 2011 at 18:6 Comment(1)
note to others, moving the tstringgrid code to a separate unit (say nglncontrol) works fine with designtime forms, if you either put the unit last in the USES clause, or use a typealias (type TStringGrid=nglncontrol.TStringGrid before the form declaration). I use the latter.Belen
B
1

Yes, it is possible. TStringGrid inherits from TDrawGrid and does all drawing on its own. You can use the OnDrawCell event to do custom drawing.

Bernal answered 12/3, 2011 at 21:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.