Knowledge Base Alert May, 2015


VCL

FIREMONKEY

INTRAWEB

DEVELOPER TOOLS

TAdvRichEditor:

How to copy contents from one TAdvRichEditor instance to another



Copying contents from one TAdvRichEditor instance to another can be done in following way:

var
  ms: TMemoryStream;

begin
  ms := TMemoryStream.Create;

  try
    AdvRichEditor1.SaveToStream(ms);
    ms.Position := 0;
    AdvRichEditor2.LoadFromStream(ms);
  finally
    ms.Free;
  end;
end;


TTreeList:

How to set the background color per item



To set the background color per item, implement OnCustomDrawItem and set the Canvas.Brush.Color from this event.

This example code snippet applies color banding to TTreeList:

procedure TForm1.TreeList1CustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); 
begin
  if odd(Node.Index) then
    TreeList1.Canvas.Brush.Color := clInfoBk
  else
    TreeList1.Canvas.Brush.Color := clWindow; 
end;



TAdvSpreadGrid:

How to add formula support in TAdvSpreadGrid to access DB tables



With this small DB sample mathlib, the concept is demonstrated to add formula support in TAdvSpreadGrid to access DB tables:



type

  TDBMathLib = class(TMathLib)
  private
    { Private declarations }
    FDataSource: TDataSource;
  protected
    { Protected declarations }
    procedure Notification(AComponent: TComponent; AOperation: TOperation); override;
  public
    { Public declarations }
    function HandlesStrFunction(FuncName:string):Boolean; override;
    function CalcStrFunction(FuncName:string;Params:TStringList;var ErrType,ErrParam: Integer):string; override;
  published
    { Published declarations }
    property DataSource: TDataSource read FDataSource write FDataSource;
  end;


implementation

{ TDBMathLib }

function TDBMathLib.CalcStrFunction(FuncName: string; Params: TStringList;
  var ErrType, ErrParam: Integer): string;
var
  s: string;
  n,e: integer;
  fld: TField;
begin
  if (FuncName = 'DBV') then
  begin
    if Params.Count <> 2 then
    begin
      ErrType := Error_InvalidNrOfParams;
      Exit;
    end;

    if not Assigned(DataSource) then
    begin
      ErrType := Error_NoDataSource;
      Exit;
    end;

    if not Assigned(DataSource.DataSet) then
    begin
      ErrType := Error_NoDataSet;
      Exit;
    end;

    if not DataSource.DataSet.Active then
    begin
      ErrType := Error_NoDataSetActive;
      Exit;
    end;

    s := Params.Strings[0]; // DB FIELD value

    fld := DataSource.DataSet.FieldByName(s);

    if not Assigned(fld) then
    begin
      ErrType := Error_InvalidValue;
      ErrParam := 1;
    end
    else
    begin
      val(Params.Strings[1],n, e);

      DataSource.DataSet.First;
      DataSource.DataSet.MoveBy(n);

      Result := fld.AsString;
    end;
  end;
end;

function TDBMathLib.HandlesStrFunction(FuncName: string): Boolean;
begin
  Result := FuncName = 'DBV';
end;

procedure TDBMathLib.Notification(AComponent: TComponent;
  AOperation: TOperation);
begin
  inherited;
  if (AOperation = opRemove) and (AComponent = FDataSource) then
    FDataSource := nil;
end;


TAdvStringGrid:

How to store additional information for combobox items in a combobox used as inplace editor in the grid



If there is additional information to store for combobox items in a combobox used as inplace editor in the grid, this additional information can be added in a combobox item’s object.

Example:

procedure TForm1.FormCreate(Sender: TObject);
begin
  AdvStringGrid1.Options := AdvStringGrid1.Options + [goEditing];
  AdvStringGrid1.DefaultEditor := edComboList;
  AdvStringGrid1.Combobox.AddItem('BMW',TObject(1));
  AdvStringGrid1.Combobox.AddItem('Mercedes',TObject(2));
  AdvStringGrid1.Combobox.AddItem('Audi',TObject(3));
  AdvStringGrid1.Combobox.AddItem('Porsche',TObject(4));
end;
If after editing the cell with a combobox, you want that the object associated with the selected item of the combobox is accessible per cell, you can implement OnCellValidate and assign the combobox selected object to the cell object:
procedure TForm1.AdvStringGrid1CellValidate(Sender: TObject; ACol,
  ARow: Integer; var Value: string; var Valid: Boolean);
begin
  AdvStringGrid1.Objects[ACol,ARow] := AdvStringGrid1.Combobox.Items.Objects[AdvStringGrid1.Combobox.ItemIndex];
end;
and later retrieve the object via AdvStringGrid1.Objects[Col,Row]: TObject;




TTMSFMXProgressBar:

How to change the color of the progressbar



The TTMSFMXProgressBar inherits from TProgressBar so you can style identical to TProgressBar. You can either change the hindicator or vindicator TRectangle (based on the orientation) in the stylebook, or programmatically In the OnApplyStyleLookup event.

Example:

procedure TForm1.FormCreate(Sender: TObject);
begin
  TMSFMXProgressBar1.Value := 75;
end;

procedure TForm1.TMSFMXProgressBar1ApplyStyleLookup(Sender: TObject);
var
  r: TRectangle;
begin
  r := TMSFMXProgressBar1.FindStyleResource('hindicator') as TRectangle;
  r.Fill.Color := claRed;
  r.Fill.Kind := TBrushKind.Solid;
end;



TTMSFMXEditBtn:

How to show a combox with TTMSFMXEditBtn linked to a TFDQuery dataset



You need to link the Text value as you would with a normal TEdit. You can then add a TListBox as dropdown control which is linked to the field of choice. This should work with any control (TListView, TGrid, ...).

Here you can download a sample that demonstrates this.



TTMSFMXCircularGauge:

Subclassing TTMSFMXCircularGauge



When subclassing TTMSFMXCircularGauge, make sure that in the new class, you override the protected method GetDefaultStyleLookupName to ensure your new gauge control uses the base class TTMSFMXCircularGauge default style resource. Additionally for this type of control, you also need to override the GetClassStyleName to return the correct default style. Below is a sample that demonstrates this:

type
TFMXWireCircularGauge = class(TTMSFMXCircularGauge)
  private
    { Private declarations }
  protected
    { Protected declarations }
   function GetDefaultStyleLookupName: string; override;
   function GetClassStyleName: String; override;
  public
    { Public declarations }
   procedure ApplyStyle; override;
  published
    { Published declarations }
  end;

...

{ TFMXWireCircularGauge }

procedure TFMXWireCircularGauge.ApplyStyle; begin
  inherited;

end;

function TFMXWireCircularGauge.GetClassStyleName: String; begin
  Result := ClassParent.ClassName + 'style';
  Delete(Result, 1, 1);
end;

function TFMXWireCircularGauge.GetDefaultStyleLookupName: string; begin
  Result := GetClassStyleName;
end;


TIWAdvWebGrid:

How to display the active row in a scrollable grid



If scrolling is enabled (by setting Scroll.Style to scAlways or scAuto) and Scroll.ScrollIntoView is True the TIWAdvWebGrid will automatically scroll to the row specified in the ActiveRow property.

TIWAdvWebGrid:

How to read/write the state of a checkbox



You can use RowSelect(RowIndex), which returns a boolean value, to know if a row with a column of type ctCheckBox is checked or not.

Example:
TIWAdvWebGrid1.RowSelect[0] := true;  


The ctCheckBox method can only be used for a single column. When multiple checkbox columns are required you can use the ctDynCheckBox ColumnType instead of ctCheckBox. You can read/write the state of a ctDynCheckBox columntype by using IWAdvWebGrid.DynEdits[ColumnIndex,RowIndex]. A value of ‘0’ will display an unchecked checkbox and a value of ‘-1’ will display a checked checkbox.

Example:
//Set checkbox in column 0 and row 1 to checked:
TIWAdvWebGrid1.DynEdits[0, 1] := '1';

//Set checkbox in column 1 and row 2 to checked:
TIWAdvWebGrid1.DynEdits[1, 2] := '1';

//Set checkbox in column 1 and row 3 to unchecked:
TIWAdvWebGrid1.DynEdits[1, 2] := '0';

If you would like to use the ctDynCheckBox column type, please note that by design there is no server event attached to this column type. To update the ctDynCheckBox values you’ll need, for example, an external button with a click event assigned. From the click event you can retrieve the DynEdits values from the AdvWebgrid and update the database manually.

TIWAdvWebGrid:

How to add an image (with text) to a cell



You can use HTML tags to add an image to a column of type ctNormal or simply add the image name + path for a Column of type ctImage.

Examples:

ctNormal column:

Add an image to a cell:
  TIWAdvWebGrid1.Cells[0,0] := '<img src="http://www.tmssoftware.com/site/img/tmslogo.png"  style="width:128px;height:50px;">';


Add an image & text to a cell:
TIWAdvWebGrid1.Cells[1,0] := '<img src="image.png"><br>row ' + IntToStr(RowIndex);


ctImage column:

  TIWAdvWebGrid1.Cells[2,0] := 'http://www.tmssoftware.com/site/img/tmslogo.png';


TMS Aurelius:

Composite keys



Aurelius fully supports tables that use composite keys. One of our goals was to provide fully flexibility and maximum possibility of using Aurelius with existing applications. If you already have a database model with composite keys that is running over many years with many customers, it’s fully understandble it’s hard to change that and you can use Aurelius with it, no problem.

But if you are designing a new application or have an opportunity to change that, we strongly advise you to do so. The reason is that it will increasing complexity and you will lose some Aurelius automatic features. Just as an example, when you do something like this in Aurelius:

Manager.SaveOrUpdate(Object);

It will automatically INSERT (Save) or UPDATE the record in database given the current state of Object. If the Object has an Id, it will be updated. Such mechanism is not possible with composite keys (or “None” generators) because even if you are inserting a new record, you must provide the Object with some of id fields already filled, so in this case Aurelius can’t tell if it must do a Save or Update.

As another consequence of this, cascades become also trickier. Suppose you have a complex object tree that you have several associated objects. When you persist the object, Aurelius will try (if you configured to do so by using SaveUpdate cascades) to also persist associated objects so you don’t need to do it manually for each of them. Such mechanism becomes also complicated with “None” generators because Aurelius can’t tell if it must save or update the objects, thus you would have to do it manually.

In conclusion, as previously said, Aurelius fully supports complex database structures (it can even use relationships that do not relates to primary keys, but unique keys, for example). However, the most “standard” (or simple) your structure is, the more automatic and neat features of Aurelius you can use. So please take that in consideration when designing your database with composite keys.


As always, we thank all users for the numerous inputs, feedback, comments and suggestions. This is an invaluable help to steer our developments here at TMS software. We continue to look forward to all your further communications to direct our team to provide you better tools and components for your needs.

Kind regards,
TMS software team
Email: info@tmssoftware.com
Web: http://www.tmssoftware.com
Support, FAQ & Manuals: http://www.tmssoftware.com/site/support.asp


Follow latest developments at tmssoftware.com



NOTICE: If you wish to unsubscribe from the TMS software Newsletter, please click here.