Search code examples
delphigridfiremonkeylivebindings

firemonkey mobile grid with livebindings - changing TextCell text color at runtime XE5


I need to get my money cells on a grid to show the local currency symbol, be right aligned and have negative numbers shown in red.

Unlike similar posts I am populating my TGrid from a dataset using livebindings. Other solutions suggest sub-classing a "TFinancialCell" from a TStringCell for the grid which is difficult when using livebindings.

With Livebindings, the Bind Manager controls the creation of the grid columns and cells so that sub-classing the Bind Manager (and other relevant classes) is probably neither practical nor elegant.


Solution

  • Having messed with this some more I have found a solution which answers my problem

    The money symbol is obtained by using the OnGetText event of the dataset field to return the formatted string:

    procedure FDTableMyCurrFieldGetText(Sender: TField; var Text: string;
      DisplayText: Boolean);
    begin
      DisplayText := True;
      Text := FloatToStrF(Sender.AsCurrency, ffCurrency, 18, 2);
    end;
    

    I could have done this in the Grid OnPainting event but doing it this way formats the field for all linked controls as well as for the grid. I use "Sender" rather than "FDTableMyCurrField" to refer to the Field so that I can point the OnGetText event of all the other currency fields in my datasets to this method.

    The rest of the formatting is done in the Grid. The Cells of the Grid are not exposed explicitly but you can get to them like this "TTextCell(Grid1.Columns[I].Children[J])". Use the Grid OnPainting event to format the cells immediately before they are painted.

    Right alignment is achieved by setting the alignment of the Cell in the grid.

    The cell text color is set by using Styles. We need to create a "textcellnegativestyle" in our application StyleBook. This will be identical to the default "textcellstyle" except that the "foreground" Brush colour will be red. On a desktop application you could drop a TEdit on your application, right-click it and select "Edit Custom Style..." then name the custom style "textcellnegativestyle" based on the "editstyle" but just change the foreground Brush color to red.

    Mine is a mobile app where "Edit Custom Style" does not appear on the Delphi form editor popup menu options for this reason. To add a custom style you have to edit (a copy of) the .style file with Notepad or some text editor.

    1. Copy/paste the "textcellstyle" object
    2. edit the name of the pasted object to "textcellnegativestyle"
    3. change the 'foreground' Brush color to red.
    4. Load the edited file into your application StyleBook.

    Here is how it looks in my .style file:

      object TLayout
        StyleName = 'textcellnegativestyle'
        DesignVisible = False
        Height = 50.000000000000000000
        Width = 50.000000000000000000
        object TLayout
          StyleName = 'content'
          Align = alContents
          Locked = True
          Height = 42.000000000000000000
          Margins.Left = 4.000000000000000000
          Margins.Top = 4.000000000000000000
          Margins.Right = 4.000000000000000000
          Margins.Bottom = 4.000000000000000000
          Width = 42.000000000000000000
        end
        object TBrushObject
          StyleName = 'foreground'
          Brush.Color = claRed
        end
        object TBrushObject
          StyleName = 'selection'
          Brush.Color = x7F72B6E6
        end
        object TFontObject
          StyleName = 'font'
        end
      end
    

    I use the Grid OnPainting event to set the Cells alignment and style. here is my working solution:

    procedure TFormMain.Grid1Painting(Sender: TObject; Canvas: TCanvas;
      const ARect: TRectF);
    var
      I, J: Integer;
      T: TTextCell;
    begin
      // my Column 0 is text, all other columns are money in this example
      for I := 1 to Grid1.ColumnCount - 1 do
        for J := 0 to Grid1.Columns[I].ChildrenCount- 1 do
        begin
          T := TTextCell(Grid1.Columns[I].Children[J]);
          // set the Cell text alignment to right align
          T.TextAlign := TTextAlign.taTrailing;
    
          // test the Cell string for a negative value
          if (T.Text[1] = '-') then
          begin
            // remove the leading minus sign
            T.Text := Copy(T.Text, 2, Length(T.Text) - 1);
            // set the font to red using the style
            T.StyleLookup := 'textcellnegativestyle';
          end
          else T.StyleLookup := 'textcellstyle';
        end;
    end;