Jump to content
jarto

TW3StringGrid is available

Recommended Posts

A new update is available in the development-channel of SmartUpdate. It contains a completely new Grid: TW3StringGrid. It's a completely new design, which was made to be very fast and able to handle lots of data. This is achieved through dynamic drawing: Only the visible grid lines are rendered.

There is a new StringGrid-demo in the Featured Demos. It downloads a json file and populates the grid with data from it.

TW3StringGrid supports six different column types:

  • Text (column class TW3StringGridTextColumn)
  • Numeric (column class  TW3StringGridNumericColumn)
  • EditBox (column class TW3StringGridEditColumn)
  • ComboBox (column class TW3StringGridComboColumn)
  • Checkmark (column class TW3StringGridCheckmarkColumn)
  • Button (column class TW3StringGridButtonColumn)

Columns are created by calling:

MyNewColumn:=Grid.AddColumn(ColumnClass);

If no ColumnClass is given, a Text column is created.

Column properties:

  • Caption
  • Width
  • BorderType
    • Default is btLightBorderRight. Set to btNone if you don't want any vertical borders.
  • Backgroundtype
    • Default is btNone to let the line color through.
  • AlignText (The same way as in TW3Label)
    • taLeft (default)
    • taCenter
    • taRight
  • SelectOptions (for TW3StringGridComboColumn only)
    • This is an array of selectable values. First value (index 0) is the value for no selection. For example: SelectOptions:=['','First','Second','Third'];
  • RowBorderType:
    • Default is btLightBorderBottom. Set to btNone if you don't want any horizontal borders.
  • RowBackgroundType:
    • Default is bsListItemBackground. Set to bsDecorativeListItemBackground (or test other backgrounds) to change the background style for even rows.
  • RowOddBorderType:
    • Default is btLightBorderBottom. Set to btNone if you don't want any horizontal borders. Affects odd rows.
  • RowOddBackgroundType:
    • Default is bsListItemBackground. Set to bsDecorativeListItemBackground (or test other backgrounds) to change the background style for odd rows.

Grid properties:

  • RowCount: Set number of rows to show
  • FixedColumns: How many columns should be fixed (aka not scrollable horizontally)
  • LineHeight
  • MultiSelect

Events:

  • OnCellClick: Is triggered when the row is clicked.
  • OnCellChanged: Is triggered when cell content changes through editing (for example: through editing)
  • OnDrawGridLineTheme: Can be used to set custom backgrounds and borders for a row. (for example, set background to bsErrorBackground for lines that should be highlighted to the user)

Methods:

  • InvalidateGrid: Triggers a repaint of the grid.
  • Sort

Sorting

TW3StringGrid supports sorting based on one of multiple columns. Clicking on the column headers sets or reverses sort order. You can also control sorting in code:

procedure AddSortColumn(Index: Integer; SortOrder: TW3SortOrder = soNormal); overload;
procedure AddSortColumn(Col: TW3StringGridColumn; SortOrder: TW3SortOrder = soNormal); overload;
procedure SetSortColumn(Index: Integer; SortOrder: TW3SortOrder = soNormal); overload;
procedure SetSortColumn(Col: TW3StringGridColumn; SortOrder: TW3SortOrder = soNormal); overload;
procedure ToggleSortColumn(Index: Integer);

For example:

Grid.SortOptions.AddSortColumn(3,soReverse); //Set primary sort column
Grid.SortOptions.AddSortColumn(1); //Add secondary sort columns
Grid.Sort;

Working with sorted data

When the Grid is sorted, it only affects how data is shown. Sorting does not change Grid data itself at all. When you work with a sorted grid events and indexes (for example SelectedIndex) always refer to the index in the grid data itself and NOT the visible line number.

TW3StringGrid uses these events:

TW3StringGridColumnEvent = procedure(const Sender: TW3StringGridColumn; const Row: Integer);
TW3StringGridEvent = procedure(const Sender: TObject; const Row, Col: Integer);

If you have a Grid where "Australia" is on line 2, SelectedIndex:=2 selects that row regardless of how the grid is sorted. Clicking on that row or changing data on that row also returns Row=2 regardless of how the grid is sorted.

Share this post


Link to post
Share on other sites

I have just done a light review of this StringGrid demo and was wondering if TW3Button is an option. What the real question is how to get the unique ID of selected row and then take the user to either a new form or view based on the selected item.

At this time, I have used the TW3Grid, but was interested in perhaps switching over to this one.

Share this post


Link to post
Share on other sites
15 hours ago, Tim Koscielski said:

I have just done a light review of this StringGrid demo and was wondering if TW3Button is an option. What the real question is how to get the unique ID of selected row and then take the user to either a new form or view based on the selected item.

At this time, I have used the TW3Grid, but was interested in perhaps switching over to this one.

Sure, I can add a Button column type too. Also OnCellChanged will be added in the next update.

I've also been working on sorting. As the data is dynamically drawn, it's actually surprisingly easy to add. The trickiest is just to decide how the sorting interface should be done (properties etc.) so that I don't unnecessarily restrict future features. For example, in many Delphi grids there are quite detailed possibilities to control sorting.

Share this post


Link to post
Share on other sites

@sibar

You can use the built-in theme background from SmartCL.Theme.pas

 

example:

  W3StringGrid1.RowBackgroundType:= bsDisplayBackground;
  W3StringGrid1.RowOddBackgroundType:= bsDisplayBackground;

 here are you choices/options

TW3ThemeBackground  = (
    bsNone = 0,
    bsDisplayBackground,
    bsControlBackground,
    bsContainerBackground,
    bsListBackground,
    bsListItemBackground,
    bsDecorativeListItemBackground,
    bsListItemSelectedBackground,
    bsEditBackground,
    bsButtonBackground,
    bsDialogButtonBackground,
    bsDecorativeBackground,
    bsDecorativeInvertBackground,
    bsDecorativeDarkBackground,
    bsToolContainerBackground,
    bsToolButtonBackground,
    bsToolControlBackground,
    bsTransparentBackground
    );

you can do the same with the columns

procedure TForm1.InitializeObject;
var
C: TW3StringGridColumn;
begin
  inherited;
  {$I 'Form1:impl'}
  fSG:= TW3StringGrid.Create(self);
  C:= fSG.AddColumn;
  C.Caption:= 'One';
  C.Width:= 100;
  c.BackgroundType := bsDecorativeDarkBackground;

end;

 

Share this post


Link to post
Share on other sites
48 minutes ago, sibar said:

@IElite 

Yes, but I want the background to be different depending on data. Ie. normally all rows are white, but on error conditions the rows should be red.

I'll have a look at this.

Share this post


Link to post
Share on other sites

A new event was added: OnDrawGridLineTheme

This event can be used to set custom backgrounds and borders for a row. For example, set background to bsErrorBackground for lines that should be highlighted to the user. Example:

procedure TForm1.W3StringGrid1DrawGridLineTheme(const Sender: TObject; const Row: Integer; var BackgroundTheme: TW3ThemeBackground; var BorderTheme: TW3ThemeBorder);
begin
  if Row=3 then
    BackgroundTheme := bsErrorBackground;
end;

Notice, that the Row is the data row. So it corresponds to the line in your data and NOT the physical line, as the physical line depends on how the grid is sorted.

The update is available in the development-channel.

Share this post


Link to post
Share on other sites

Available with a easy way  to select one line only?
(like in the delphi Stringgrid1.options  with gorowselect=true value)
I tried to change the  SetContentSelectionMode  with all values ( tsmNone,    tsmAuto,    tsmText,     tsmAll,     tsmElement) but nothing  changed.

Maybe I misunderstood something, but then what this SetContentSelectionMode function good for?

Share this post


Link to post
Share on other sites
2 hours ago, kockas said:

Available with a easy way  to select one line only?
(like in the delphi Stringgrid1.options  with gorowselect=true value)
I tried to change the  SetContentSelectionMode  with all values ( tsmNone,    tsmAuto,    tsmText,     tsmAll,     tsmElement) but nothing  changed.

Maybe I misunderstood something, but then what this SetContentSelectionMode function good for?

Use SelectedIndex to set or read the index. The grid does not use ContentSelectionMode.

 

Share this post


Link to post
Share on other sites

Thank you Jarto!

Finally I found what was the problem...... I worked with the master channel where the stringgrid absolute not available :) 
and the the normal grid was so promising ..... while I not found the Development channel...

Now I feel good with the new components.
The "new" stringgrid likeable!!
 

Share this post


Link to post
Share on other sites

@tristan

You will need to create your own / derive your own  column from TW3StringGridColumn located in the unit SmartCL.Controls.StringGrid.

Take a look at the SmartCL.Controls.StringGrid unit and see how for example, the button column (TW3StringGridButtonColumn)  is created

TW3StringGridButtonColumn = class(TW3StringGridColumn)
  protected
    function GetClasses: String; override;
  public
    constructor Create; override;
    function GenerateHtml(GridLine: TW3RenderedGridLine; ColumnIndex, CurrentLeft: Integer): String; override;
    procedure SetColumnEvents(Sender: TW3CustomStringGrid; GridLine: TW3RenderedGridLine; ColumnIndex: Integer); override;
  end;

{ TW3StringGridButtonColumn }

constructor TW3StringGridButtonColumn.Create;
begin
  FBaseClass := 'TW3Button';
  AlignText := taLeft;
  VAlign := tvCenter;
  BorderType := btLightBorderRight;
  BackgroundType := bsNone;
end;

function TW3StringGridButtonColumn.GenerateHtml(GridLine: TW3RenderedGridLine; ColumnIndex, CurrentLeft: Integer): String;
begin
  var ItemId:=Grid.Handle.id+'_row_'+IntToStr(GridLine.DataIndex)+'_btncol_'+IntToStr(ColumnIndex);
  GridLine.ItemIds.Add(ItemId);
  result:='<input id="'+ItemId+'" type="button" class="'+GetClasses+'" style="visibility: visible; display: inline-block; overflow: hidden; left: '+IntToStr(CurrentLeft)+'px; position: absolute; width: '+IntToStr(Width)+'px; height: 100%;border-radius: 0px;" value="'+TString.EncodeTags(Grid.Cells[GridLine.DataIndex,ColumnIndex])+'"</input>';
end;

function TW3StringGridButtonColumn.GetClasses: String;
begin
  result:=inherited GetClasses+' TW3ButtonBackground';
end;

procedure TW3StringGridButtonColumn.SetColumnEvents(Sender: TW3CustomStringGrid; GridLine: TW3RenderedGridLine; ColumnIndex: Integer);
//  Note: This is used by the combo box too
var cHandle: THandle;
begin
  try
    cHandle := GridLine.FixedCols.Handle.GetChildById(GridLine.ItemIds[ColumnIndex]);
    if not (cHandle) then cHandle := GridLine.ScrollableCols.Handle.GetChildById(GridLine.ItemIds[ColumnIndex]);
    cHandle['oninput'] := @Sender.HandleDataChanged;
  except
  end;
end;

 

Share this post


Link to post
Share on other sites

For anyone needing something similar

 

unit SmartCL.Controls.StringGrid.ImageColumn;

interface

uses 
  W3C.DOM,
  System.Types,
  System.Types.Graphics,
  System.Types.Convert,
  System.Time,
  System.Dictionaries,
  SmartCL.Application,
  SmartCL.Components,
  SmartCL.System,
  SmartCL.Theme,
  SmartCL.Css.Classes,
  SmartCL.Scroll,
  SmartCL.Controls.Label,
  SmartCL.Controls.StringGrid,
  SmartCL.Controls.Image;

type
  TW3StringGridImageColumn = class(TW3StringGridColumn)
  protected
    function GetClasses: String; override;
  public
    constructor Create; override;
    function GenerateHtml(GridLine: TW3RenderedGridLine; ColumnIndex, CurrentLeft: Integer): String; override;
    procedure SetColumnEvents(Sender: TW3CustomStringGrid; GridLine: TW3RenderedGridLine; ColumnIndex: Integer); override;
  end;

implementation


constructor TW3StringGridImageColumn.Create;
begin
  FBaseClass := 'TW3Image';
  AlignText := taCenter;
  VAlign := tvCenter;
  BorderType := btLightBorderRight;
  BackgroundType := bsNone;
end;

function TW3StringGridImageColumn.GenerateHtml(GridLine: TW3RenderedGridLine; ColumnIndex, CurrentLeft: Integer): String;
begin
  var ItemId:=Grid.Handle.id+'_row_'+IntToStr(GridLine.DataIndex)+'_btncol_'+IntToStr(ColumnIndex);
  GridLine.ItemIds.Add(ItemId);
  result:='<img id="'+ItemId+'" class="'+GetClasses+'" style="visibility: visible; display: inline-block; overflow: hidden; left: '+IntToStr(CurrentLeft)+'px; position: absolute; width: '+IntToStr(Width)+'px; height: 100%;border-radius: 0px;" src="'+TString.EncodeTags(Grid.Cells[GridLine.DataIndex,ColumnIndex])+'"</img>';
end;

function TW3StringGridImageColumn.GetClasses: String;
begin
  result:=inherited GetClasses+' TW3ButtonBackground';
end;

procedure TW3StringGridImageColumn.SetColumnEvents(Sender: TW3CustomStringGrid; GridLine: TW3RenderedGridLine; ColumnIndex: Integer);
//  Note: This is used by the combo box too
var cHandle: THandle;
begin
  try
    cHandle := GridLine.FixedCols.Handle.GetChildById(GridLine.ItemIds[ColumnIndex]);
    if not (cHandle) then cHandle := GridLine.ScrollableCols.Handle.GetChildById(GridLine.ItemIds[ColumnIndex]);
   // cHandle['oninput'] := @Sender.HandleDataChanged;
  except
  end;
end;


end.

 

Share this post


Link to post
Share on other sites

Thank you @tristan and @IElite

Yeah, creating new culumn types is really as simple as generating the right html. Especially with images. With images you probably don't even have to override SetColumnEvents. It's mainly used with controls where the used can change the cell value, like Edit, Combo and Boolean.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×