1
votes

I have a string grid where user can change colors of columns. I'm storing a color in a string it looks likethis : columnToColor:= '1;233,233,233' 1 is the column 233;233;233 is a rgb color; I change this string everytime i have to change colors. It never contains more than one column and one color

In my drawcellevent i'm doing this:

color := Explode(';',columnToColor); //this will return an array
if (length(color)-1 >= 0) then
begin
  if TryStrToInt(color[0], val) then
  begin
    if aCol = StrToInt(color[0]) then
    begin
      cellText := grid.Cells[aCol,aRow];
      grid.Canvas.Brush.Color := TColor(RGB(StrToInt(color[1]),StrToInt(color[2]),StrToInt(color[3])));
      rec := grid.CellRect(aCol,aRow);
      grid.Canvas.FillRect(rec);
      grid.Canvas.TextOut(rec.Left,rec.top,cellText);
    end;
  end;
end;

I'm calling invalidateCol from another procedure using a hacked StringGrid class:

With TCustomStringGrid(grid) do
  InvalidateCol(grid.col)

This works when i change only one column color. I can scroll freely trought the grid and it will still be there with the good column color. But when i change the color of another column the colors are shown when their are still visibile. Once i scroll horizontally and get back to the columns only the last colored column is colored and other are set to default color. The color only stays on the last colored column. So if i color 2 columns and i click on the first one, the cell's color is set to default. And i scroll horizontally the whole column 1 is set to default color. Only the second column keep its color what ever i do.

How can i fix this pls?

1
length(color)-1 is more easily written as high(color) - David Heffernan
I'm not sure I understand this. Don't you need to invalidate two columns when you change the color string? And wouldn't it be easier just to invalidate the whole control? - David Heffernan
In my grid the user selects a column by right clicking on it and the there's a popup menu. The popupmenu option that user selected gets the column clicked set a color depending on which option the user clicked. At this time i invalidate the column he clicked on. Then, he can also do this with another option, on another column. So i invalidate the other column he clicked and change to another particular colar depending on the option he clicked. - user28470
If i invalidate the whole stringgrid redraws directly any other columns despite the last one that was colored. Invalidating only a particular column keeps the color of my other columns, at least until they are not shown anymore - user28470
So everytime i scroll trought the grid the colors are set to default despite the last colored column. I want to keep those colored column obviously x) I hate grids haha - user28470

1 Answers

5
votes

This is perhaps becoming a little more clear to me. The problem is that you want the grid control to paint each column in separate colors. Although your columnToColor string specifies the color for only a single column, you want each column to have, potentially, a different color. When you scroll the grid, and columns are re-painted, only the column specified in columnToColor has the desired color.

All this is happening because Windows controls need to be able to re-paint themselves completely at any time. Once you have painted a control, the control does not remember its state. If it becomes invalid (control dragged over, scrolled, etc.) then the control must be able to re-paint itself in its entirety.

Your code fails to do that. Since it only remembers the color for the most recently modified column, when it needs to paint other columns, they get the default color. Your approach cannot succeed since the control only keeps track of one single column color.

The solution is simple enough. You need to remember the color for each column. An obvious way to do so would be to hold the colors in an array:

FColumnColor: array of TColor;

or

FColumnColor: TArray<TColor>;

in a more modern Delphi. Or perhaps even TList<TColor>.

When you need to change a column's color do so by modifying FColumnColor[ColIndex]. Likewise, whenever you need to paint, read the color out of FColumnColor[ColIndex].