Delphi: 如何在字符串网格中更改单元格的颜色

14
我想改变 Delphi 字符串网格中一个单元格的背景颜色(而不是字体),只想修改一个单元格,而非整行或列。是否可以实现?
RRUZ:您提供的程序是正确且可行的,但在我的程序中却无法生效。
我的程序如下:
x 是一个全局整数数组。
procedure TF_avalie_salon.StringGrid1DrawCell(Sender: TObject; ACol,
    ARow: Integer; Rect: TRect; State: TGridDrawState);
    var   S: string;
begin
    S := StringGrid1.Cells[ACol, ARow];
    StringGrid1.Canvas.FillRect(Rect);
    SetTextAlign(StringGrid1.Canvas.Handle, TA_CENTER);
    StringGrid1.Canvas.TextRect(Rect,Rect.Left + (Rect.Right - Rect.Left) div 2, Rect.Top + 2, S);
    if (ARow<>0 )AND(acol<>0)AND(gridclick=true) then
    begin
        try
          gridclick:=false;
          x[acol+((strtoint(Edit_hafte.Text)-1)*7),arow]:=strtoint(StringGrid1.Cells[ACol, ARow]);
        except
          x[acol+((strtoint(Edit_hafte.Text)-1)*7),arow]:=0;
          StringGrid1.Cells[acol,arow]:='0';
          with TStringGrid(Sender) do
          begin
            Canvas.Brush.Color := clGreen;
            Canvas.FillRect(Rect);
            Canvas.TextOut(Rect.Left+2,Rect.Top+2,Cells[ACol, ARow]);
          end;
        end;
    end;
end;

当我使用下面的代码和Canvas.Brush.Color时,Canvas.Brush.Color不起作用。如果我注释掉下面的代码,我就可以改变单元格的颜色。但是我需要同时实现两个功能。

    S := StringGrid1.Cells[ACol, ARow];
    StringGrid1.Canvas.FillRect(Rect);
    SetTextAlign(StringGrid1.Canvas.Handle, TA_CENTER);
    StringGrid1.Canvas.TextRect(Rect,Rect.Left + (Rect.Right - Rect.Left) div 2, Rect.Top + 2, S);

使单元格变绿的代码仅在出现异常情况下执行,而这几乎只可能在StrToInt函数中发生。这是有意为之吗? - Andreas
是的,安德烈斯,我想在单元格出现问题时更改其颜色。 - Arash
管理员或者主持人:我可以再问一遍这个问题吗?(为了完整和澄清) - Arash
这是重复的,关于在stackoverflow中自定义绘制方面有很多问题。绘制单元格或文本的方式相同。您只需要使用正确的属性即可。 - Rafael Colucci
3个回答

13

你可以在 Rafael 链接中找到所需的一切。使用 OnDrawCell 事件可以绘制 StringGrid 的单元格。查看此示例,它仅绘制特定单元格的背景。

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;  Rect: TRect; State: TGridDrawState);
begin
  if (ACol = 3) and (ARow = 2) then
    with TStringGrid(Sender) do
    begin
      //paint the background Green
      Canvas.Brush.Color := clGreen;
      Canvas.FillRect(Rect);
      Canvas.TextOut(Rect.Left+2,Rect.Top+2,Cells[ACol, ARow]);
    end;
end;

1
谢谢,它可以单独工作,但在我的程序中不行。请检查我问题正文中的过程。谢谢。 - Arash
你说的“不起作用”是什么意思?你尝试在设置背景颜色的那一行(Canvas.Brush.Color := clGreen;)设置断点,检查应用程序是否到达了那个点吗? - RRUZ
RUUZ:是的,我设置了断点,它是可达的。我认为我不能使用它,因为你的代码是正确的,而且它来自应用程序。我不知道该怎么办。 - Arash
这不是关于我的想法或你的想法。这只是一段不到15行的简单代码,我说它们不能一起工作,但它们单独工作得很好。如果你能帮忙,我会非常感激,但其他无用的评论就是垃圾邮件。 - Arash

5

我将这些代码翻译成了C++。有两个特别的注意事项,接下来我会发布代码。

  1. 在"StringGrid1"中,属性"DefaultDrawing"必须为FALSE才能起作用。

  2. "Canvas"对象必须完全限定:即 StringGrid1->Canvas->Font->Color=clBlack。

代码:

void __fastcall TForm3::StringGrid1DrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect,
      TGridDrawState State)
{
UnicodeString   uStr = "Hello";
int     k, l;
char    cc[100];


if(TRUE)
    {
    if((ACol <= 1) || (ARow <= 1))
        {
        StringGrid1->Canvas->Font->Color = clBlack;
        StringGrid1->Canvas->Brush->Color = clBtnFace;
        if(ACol == 0)
            {
            if(ARow > 1)
                {
                sprintf( cc, " %5.1f", rowLabels[ARow - 2]);
                uStr = cc;
                StringGrid1->Canvas->TextRect( Rect, Rect.left+2, Rect.top+2, uStr);
                StringGrid1->Canvas->FrameRect(Rect);
                }
            }
        if(ARow == 0)
            {
            if(ACol > 1)
                {
                sprintf( cc, " %5.1f", colLabels[ACol - 2]);
                uStr = cc;
                StringGrid1->Canvas->TextRect( Rect, Rect.left+2, Rect.top+2, uStr);
                StringGrid1->Canvas->FrameRect(Rect);
                }
            }
        }
    else
        {
        switch (ACol%2)
            {
            case 0:
                {
                StringGrid1->Canvas->Font->Color = clRed;
                StringGrid1->Canvas->Brush->Color = 0x00E1FFF9;
                break;
                }
            case 1:
                {
                StringGrid1->Canvas->Font->Color = clBlue;
                StringGrid1->Canvas->Brush->Color = 0x00FFEBDF;
                break;
                }
            }
        StringGrid1->Canvas->TextRect( Rect, Rect.left+2, Rect.top+2, uStr);
        StringGrid1->Canvas->FrameRect(Rect);
        }
    }
}

0
procedure StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
i:integer;  
begin
  with Sender as TStringGrid do
    begin
        Canvas.FillRect(Rect);
        DrawText (Canvas.Handle,
            PChar(Cells[ACol, ARow]),
            Length(Cells[ACol, ARow]),
            Rect, DT_WORDBREAK or DT_EXPANDTABS or DT_CENTER);
    end;
    for i:=2 to  StringGrid1.RowCount - 1 do
    if StringGrid1.Cells[3,i]='' then
      begin
        StringGrid1.Canvas.Brush.Color:=clRed;
          if ((ACol=3)and(ARow=i)) then
            begin
              StringGrid1.Canvas.FillRect(Rect);

            end;
      end;


end;

1
为什么您要使用Sender as TStringGrid的转换以及对StringGrid1的直接引用?您是否打算将其作为独立过程而不是包含StringGrid1的表单的方法?如果是独立的,您如何设想它会被调用? - MartynA
1
也许你可以解释一下为什么你认为这段代码是正确的,或者原帖中缺失或不正确的地方。 - Francesco B.
使用 Sender 作为 StringGrid 是因为该过程继承了动态 StringGrid,在使用 fastreport 生成报告时。 - Nigth F0X
我认为你的代码设计混乱不堪。我建议你删除它,因为它对未来的读者没有任何价值(这是SO的目的)。 - MartynA
也许这段代码是为了完成任务而快速编写的,但并没有考虑代码的“美观度”,在编写完代码后也没有进行修改。 - Nigth F0X
显示剩余4条评论

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