TMSFMXGrid - Progress Cell and Text Issues

Greetings, I have a livebound grid with a column containing text and I
would like to show the progress of the different rows by a color coded
progress cell. I can create whatever records I need with calculated
fields or SQL, so for the sake of this question, let's say I have the
following:

Boolean Field : IsCompleted
Integer Field : PercentDone (from 0 to 100)
DateTime Field : CompletionDate

I would like one visible column in my grid with the following properties for each row:
- If IsCompleted,
  then color the whole cell blue and text = 'Done ' + DateTimeToStr(CompletionDate)

- If not IsCompleted,
  then use green and fill in the part of the cell using PercentDone for Progress Max and Value
  text = IntToStr(PercentDone) + '% Due ' + DateTimeToStr(CompletionDate)

I
did look at the CellsControlDemo under Grid Features Demos
, but the
Progress Bar drawing was connected to the row number of the cell, which
for demonstration purposes is frustratingly useless. That demo should be
re-done to use some kind of value stored in each row, which is the only
realistic reason one would put a progress bar in the cell of a grid.

Any
help would be appreciated. I have a progress bar working, but it is
hiding my cell text and showing only the integer percent value in the
progress bar.
I have tried the following properties and had no success
so far:

procedure TFormMain.gridClassesGetCellProperties(Sender: TObject; ACol, ARow: Integer; Cell: TFmxObject);
begin
  if Cell is TTMSFMXProgressGridCell then
  begin
    (cell as TTMSFMXProgressGridCell).ProgressBar.Max := gridClasses.RowCount;
    (cell as TTMSFMXProgressGridCell).ProgressBar.Value := gridClasses.RowCount - ARow;
    (cell as TTMSFMXProgressGridCell).ProgressBar.ShowText := true;
    (cell as TTMSFMXProgressGridCell).ProgressBar.GetText.Text := 'hello';
  end;
end;

Things I specifically need to accomplish my goals:
- The cell contents of a particular row, even if the column is hidden?
- In which grid method do I set the text or make it visible?
- In which grid method do I set the color of the progress bar and how?

Thanks,
Scott

 


I did find an improvement I would recommend for the CellsControlDemo, If you have a header row for a grid, I doubt you want progress cells in the header row, and here is how you remove it for that cell:

procedure TFormMain.gridClassesGetCellClass(Sender: TObject; ACol,  ARow: Integer; var CellClassType: TFmxObjectClass);
begin
  if (ACol = 5) and (ARow > 0) then CellClassType := TTMSFMXProgressGridCell;
end;

I also went back and started rereading the grid PDF from TMS and after 100 hours using this component, it is helping a bit more. I found I can grab a cell string value and I can set the progress to look better using the following - something like this might also be added to the CellsControlDemo:

procedure TFormMain.gridClassesGetCellProperties(Sender: TObject; ACol, ARow: Integer; Cell: TFmxObject);
var
  iValue : integer;
begin
  if Cell is TTMSFMXProgressGridCell then
  begin
    iValue := StrToIntDef(gridClasses.Cells[ACol, ARow], 0);
    (cell as TTMSFMXProgressGridCell).ProgressBar.Max := 100;
    (cell as TTMSFMXProgressGridCell).ProgressBar.Value := iValue;
  end;
end;

To do what I need, I still need to do the following:
- Set or make visible the text to show in the progress cell.
- Set the color of the progress bar.

Thanks,
Scott

First, I still very much am looking for answers to my original post, so this last addition is just for free for someone else!!! I tried my hand at custom drawing and it works, but I think the TMS progress bar is more attractive. If anyone else wants a custom draw example, well, here is one...

(Note: for this one I am storing an integer in the field from 0 to 101 where 101 is marked fully completed and colored blue instead of green. This is a calculated database field where the 101 is stored in OnCalcFields)

procedure TFormMain.gridClassesCellBeforeDraw(Sender: TObject; ACol,
  ARow: Integer; ACanvas: TCanvas; var ARect, ATextRect: TRectF; var ADrawText,
  ADrawBackGround, AllowDraw: Boolean);
var
  iValue : integer;
  sText : string;
  ProgressRect : TRectF;
  W, H : single;
begin
  if (ACol = 5) and (ARow > 0) then begin
    // We have a progress cell!
    iValue := StrToIntDef(gridClasses.Cells[ACol, ARow], 0);
    if (iValue < 0) then iValue := 0;
    if (iValue > 100) then begin
      // Class Mark Completed, Fill it with blue
      // ACanvas.Stroke.Color := TAlphaColors.Blue;
      ACanvas.Stroke.Color := $FF7B84E1;
      ACanvas.Fill.Color := $FF7B84E1;
      ACanvas.FillRect(ATextRect, 0, 0, [], 1);
      ADrawBackGround := false;
      sText := 'Completed';
    end else if (iValue = 100) then begin
      // Class Completed but Not Marked, Fill Green
      ACanvas.Stroke.Color := $FF53E176;
      ACanvas.Fill.Color := $FF53E176;
      ACanvas.FillRect(ATextRect, 0, 0, [], 1);
      ADrawBackGround := false;
      sText := '100%';
    end else begin
      // Not completed, Draw your own progress bar
      ACanvas.Stroke.Color := $FFCCCCCC;
      ACanvas.Fill.Color := $FFCCCCCC;
      ACanvas.FillRect(ATextRect, 0, 0, [], 1);
      ACanvas.Stroke.Color := $FF53E176;
      ACanvas.Fill.Color := $FF53E176;
      ProgressRect.Left := ATextRect.Left;
      ProgressRect.Top := ATextRect.Top;
      ProgressRect.Bottom := ATextRect.Bottom;
      ProgressRect.Right :=
        ATextRect.Left +
        ((ATextRect.Right - ATextRect.Left) * iValue / 100);
      ACanvas.FillRect(ProgressRect, 0, 0, [], 1);
      ADrawBackground := false;
      sText := IntToStr(iValue) + '%';
    end;
    // We have sText with the contents, draw it centered in the rectangle
    W := ACanvas.TextWidth(sText);
    // Note, I don't want some lines aligning differently, so standardized centering
    H := ACanvas.TextHeight('Ayg');
    ACanvas.Fill.Color := $FF000000;
    ACanvas.FillText(ATextRect, sText, false, 1.0,
      [TFillTextFlag.ftRightToLeft],
      TTextAlign.taCenter, TTextAlign.taCenter);
    ADrawText := false;
  end else begin
    ADrawBackground := true;
  end;
end;

Hi, 


Thank you for your sample code.
Can you please re-phrase the remaining questions regarding the progress bar approach so we can help you out on this?

Greetings,

So I did some custom draw experiments and learned quite a lot, but I really want to use the existing progress cell because it looks superior to my custom draw efforts so far. So I want to detect by row and column as mentioned above and set the cell type to progress, but I want to change the color of the progress bar depending on the input conditions as mentioned in the first post.

I have three database fields:
- A boolean indicated IsFinished
- A date time field (or could be a text field)
- An integer field indicating percent complete

I want one column to be visible in my grid with the progress bar in it.

- If IsFinished, then the Progress.Max = 100 and Progress.Value would be 100
and the color would be blue. Text on top in that cell would be 'Finished';

- If not IsFinished, then Color would be green and progress set to the integer value.
And the text in that cell would be maybe the percent done and completion date.
i.e. "68% Due 4/4/2017"

So using the progress bar option, how do I programmatically set the color of the bar and how do I specify the tex to show over the bar instead of displaying the contents of progress.value?

Thanks,
Scott

Hi, 


We have attached a sample that demonstrates how this can be accomplished. Please note that the TTMSFMXProgressBar only adds a text, but is not able to change the color to blue.

http://www.tmssoftware.net/public/Demo_ProgressBar.zip

Greetings,

I greatly appreciate your help. Very excited to see this solution. Using the format string to store the output would do the job, except there are a few dangers in doing so. You have to run your demo a few times to hit the problem condition where other digits in the format string get replaced in error creating strange output.

Here is an example:


Looking for work-arounds to putting numbers in a 'format' string.
But this will already be an acceptable workaround for now.
It would be great if TTMSFMXProgressGridCell had a Text property.
I will post a fix if I find it. Hopefully before March 374!!!

Hah! I got it. That wasn't hard at all. The Progress cell has a
TTMSFMXProgressBar inside it. I dropped one of those in a form. Set the
format='35% to 1/1/2017' and the value to 22. Which in the Gui gave me a
progress bar with the text of '35% to 1/1/22217'. Then started playing
with the format field. Putting single quotes around the format string in
the box appears to tell the formatter to ignore that part.

So my solution is
    if bCompleted then begin
      PGC.ProgressBar.Format := '''Done ' + sCompleted + '''';
    end else begin
      PGC.ProgressBar.Format := '''' + FloatToStrF(iValue, ffFixed, 3, 0) + '% to ' + sCompleted + '''';
    end;

So
I am very happy, and here is my final OnGetCellProperties method for
anyone else that wants to go down this road. In my DataSetOnCalcFields, I
have a calculated field that contains the percentage complete and the
due date. If it is already marked completed, I just set the percent to
101 in that routine. The integer value is left padded with zeroes to
make it process faster. So example entries might be:

'034|4/4/2017'
'101|3/12/2016'
'000|5/5/2016'

If
you didn't read the previous posts, the
bGridClassesProgrammaticChangeFlag is a boolean declared in the private
section of the form and set to false in OnCreate.

procedure TFormMain.gridClassesGetCellProperties(Sender: TObject; ACol,
  ARow: Integer; Cell: TFmxObject);
var
  iValue : integer;
  bCompleted : boolean;
  sValue, sCompleted : string;
  PGC : TTMSFMXProgressGridCell;
begin
  if bGridClassesProgrammaticChangeFlag then exit;

  if Cell is TTMSFMXProgressGridCell then
  begin
    bGridClassesProgrammaticChangeFlag := true;

    PGC := (Cell as TTMSFMXProgressGridCell);
    // So progress is a string with a 3 char PadL integer and a delimiter
    // qryClassesClassStatus.AsString := sProgress + '|' + sProjectedEnd;
    // Example might be '034|5/6/2018'
    sValue := gridClasses.Cells[ACol, ARow];
    iValue := StrToIntDef(sValue.Substring(0, 3), 0);
    sCompleted := sValue.Substring(4);
    if (iValue = 101) then begin
      bCompleted := true;
      iValue := 100;
    end else bCompleted := false;

    // PGC.ProgressBar.
    PGC.ProgressBar.Value := iValue;
    PGC.ProgressBar.Max := 100;
    PGC.ProgressBar.GetText.Align := TAlignLayout.Client;
    PGC.ProgressBar.GetText.AutoSize := True;
    PGC.ProgressBar.GetText.WordWrap := False;
    if bCompleted then begin
      PGC.ProgressBar.Format := '''Done ' + sCompleted + '''';
    end else begin
      PGC.ProgressBar.Format := '''' + FloatToStrF(iValue, ffFixed, 3, 0) + '% to ' + sCompleted + '''';
    end;
    bGridClassesProgrammaticChangeFlag := false;
  end;
end;

Thank you Pieter. This was very useful.
I like you so much, I am naming my next child after you, even if it's a girl!!!

- Scott

Thank you for your kind feedback Scott! If there is anything else, please let us know!