Delphi中带有背景图片的StringGrid

3

大家好,有人知道是否可以将图片显示为字符串网格的背景吗?或者是否知道任何可以实现这一点的免费网格组件。

谢谢!

Colin

3个回答

12

你可以使用 TDrawGrid(或者TStringGrid),它支持自绘制,然后进行以下操作:

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

其中FBg是一个TBitmap(比如在形式类中),然后执行

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;

示例截图 示例截图 示例截图


5
回答不错,但是这也适用于TStringGrid,因为它继承自TDrawGrid。 - GolezTrol
@David等:我不确定:起初我认为我需要确保我不尝试使BitBlt读取源位图中不存在的像素,但似乎该函数能够以最友好的方式处理这种输入,即纠正“不正确”的输入(例如Copy,其中您经常将MaxInt指定为字符串的长度)。你能否在这个问题上给我一些启示? - Andreas Rejbrand
我认为这仅适用于TDrawGrid的已创建单元格。如果要求将背景图像延伸到未被单元格覆盖的TDrawGrid部分,即在最后一行或列之后,该怎么办? - rossmcm
@rossmcm:请查看额外的答案。 - NGLN

4

在回答Andreas Rejbrand的代码评论中rossmcm明确的问题时,它也补充了对原始问题的回答。

可以通过以下方式在网格边界之外但仍在StringGrid控件范围内绘制图像:

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;

如果您希望在单元格中也绘制图像,则需要结合两种技术。由于Andreas使用事件而我声明了一个后代,这并不会导致合并时出现大问题。


向他人提醒,在设计时窗体中,将 Tstringgrid 代码移到单独的单元(比如 nglncontrol)中是可以正常工作的,只要你将该单元放在 USES 子句的最后或者在窗体声明之前使用 typealias (type TStringGrid=nglncontrol.TStringGrid) 即可。 我使用后者。 - Marco van de Voort

1

是的,这是可能的。TStringGrid 继承自 TDrawGrid 并且自己完成所有绘制。您可以使用 OnDrawCell 事件来进行自定义绘制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接