在TStringGrid中设置选定行的背景颜色

4
我有一个TStringGrid,其中选择的行(最多1行,不支持多选)应始终具有不同的背景颜色。我将DefaultDrawing属性设置为false,并提供了一个OnDrawCell事件的方法,如下所示 - 但它无法正常工作。我甚至无法准确描述它是如何无法正常工作的; 我怀疑如果我能描述清楚,我已经解决了这个问题。总之,与所有具有相同背景颜色的完整行相比,它是一团糟。多个行具有一些“Selected”颜色的单元格,而不是所有选定行的单元格都具有选定颜色。
请注意,我将单元格的行与strnggrid的行进行比较;我无法检查所选单元格的状态,因为只有所选行的单元格是选定的。
procedure TForm1.DatabaseNamesStringGridDrawCell(Sender: TObject;
                                                 ACol, ARow: Integer;
                                                 Rect: TRect;
                                                 State: TGridDrawState);

  var cellText :String;
begin
   if gdFixed in State then
      DatabaseNamesStringGrid.Canvas.Brush.Color := clBtnFace
   else
   if ARow = DatabaseNamesStringGrid.Row then
      DatabaseNamesStringGrid.Canvas.Brush.Color := clAqua
   else
      DatabaseNamesStringGrid.Canvas.Brush.Color := clWhite;

   DatabaseNamesStringGrid.Canvas.FillRect(Rect);
   cellText := DatabaseNamesStringGrid.Cells[ACol, ARow];
   DatabaseNamesStringGrid.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, cellText);
end;

1
Mawg,这个话题有些偏离,但我怀疑clAqua看起来会很奇怪——它是一种非常鲜艳的颜色!尝试使用clHighlight代替,因为它是一个系统颜色,旨在表示高亮/选定的对象。 - David
如果设置了背景颜色,请务必明确设置前景颜色。据我所知,您可以将clAqua BG与clWindowText FG相结合,并且后者可以通过系统的图形设置由用户更改。 - Uli Gerhardt
4个回答

7

如果你想要将选中的行或单元格涂上不同的颜色,你必须检查state变量中的gdSelected值。

procedure TForm1.DatabaseNamesStringGridDrawCell(Sender: TObject;
                                                 ACol, ARow: Integer;
                                                 Rect: TRect;
                                                 State: TGridDrawState);
var
  AGrid : TStringGrid;
begin
   AGrid:=TStringGrid(Sender);

   if gdFixed in State then //if is fixed use the clBtnFace color
      AGrid.Canvas.Brush.Color := clBtnFace
   else
   if gdSelected in State then //if is selected use the clAqua color
      AGrid.Canvas.Brush.Color := clAqua
   else
      AGrid.Canvas.Brush.Color := clWindow;

   AGrid.Canvas.FillRect(Rect);
   AGrid.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, AGrid.Cells[ACol, ARow]);
end;

你确定吗?我非常尊重您,并感谢您过去给予我的帮助,但是,如果我只点击一行中的一个单元格,那么只有该单元格被选中,这一点您确定吗?即使是这样(我对此表示怀疑),我的代码有什么问题吗?难道不是两种指定相同事物的方式吗?为什么它不起作用? - Mawg says reinstate Monica
2
哎呀,@Mawg,我不明白你的意思,在我提供的答案中,选择的行或单元格(取决于您是否在“选项”属性中设置了“goRowSelect”)会用您选择的颜色绘制,例如在这种情况下是clAqua。如果您想要做其他事情,您必须重新表达您的问题以便帮助您。 - RRUZ
1
如果你很难解释需要完成什么,你可以在问题中附上一个样例图片,展示你想要实现的期望行为(一张图片胜过千言万语)。 - RRUZ
我不知道goRowSelect,但我猜这就是我想要的。我会去查一下。谢谢。 - Mawg says reinstate Monica

2

这对我来说很有效

procedure TFmain.yourStringGrid(Sender: TObject; ACol, ARow: Integer; Rect: TRect;
  State: TGridDrawState);
var
  md: integer;
begin
  with yourStringGrid do 
    begin
           if yourStringGrid,Row = ARow then
              Canvas.Brush.Color:= clYellow  //your highlighted color
           else begin
                 md := Arow mod 2;
                 if md <> 0 then Canvas.Brush.Color:= $00BADCC1 else //your alternate color
                 Canvas.Brush.Color:= clwhite;
           end;
           Canvas.FillRect(Rect);
           Canvas.TextOut(L, Rect.top + 4, cells[ACol, ARow]);
        end;
end;

刷新表格

procedure TFmain.yourStringGridClick(Sender: TObject);
begin
  yourStringGrid.Refresh;
end;

注意:有一定的延迟,但除此之外表现良好。(用于Delphi XE2)

2

你是否启用了运行时主题? 运行时主题会覆盖您尝试强制执行的任何Windows Vista及更高版本的颜色方案。


XP,但无论如何,这肯定不能解释单元格选择的“模糊”方式吧?如果你是对的,那么在任何给定行中,每个单元格看起来都应该是相同的吧? - Mawg says reinstate Monica

2

当在字符串网格中选择新单元格时,仅使前一个和新选择的单元格失效。因此,先前和新行的其余单元格未被重绘,导致您所描���的效果。

一种解决方法是为受影响的两行都调用InvalidateRow,但这是一种受保护的方法,您必须找到一种从OnSelectCell事件处理程序访问此方法的方式。根据您的Delphi版本,有不同的实现方法。

最干净的方法是派生自TStringGrid,但在大多数情况下这是不可行的。使用更新的Delphi版本,您可以使用类助手来实现。否则,您必须依赖于通常的protected hack


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