Thema: Delphi FireMonkey Erfahrungen

Einzelnen Beitrag anzeigen

neo4a

Registriert seit: 22. Jan 2007
Ort: Ingolstadt
362 Beiträge
 
Delphi XE2 Architect
 
#1

FireMonkey Erfahrungen

  Alt 25. Aug 2011, 09:28
... gibt es ja keine offiziellen. Und so sehr ich den Delphi-Mitarbeitern ihre Einführungsshow gönne, umso ärgerlicher machen mich diese albernen und substanzlosen "Blog-Posts" zum Thema wie zuletzt hier.

Als bekennender UX-Anhänger möchte ich meinen Programmen immer bestmögliche GUI spendieren. So habe ich zuletzt die SmoothComponents von TMS geprüft und deren letzte Version enthält ja auch eine sehr interessante iOS-TileList. Aber ich vermute, dass es schon seinen Grund hat, weshalb die nicht als Exe in den Demos auftaucht: Die Performance (auf meinem I5-System bei 1900x1200 Auflösung) ist einfach nur schlecht.

Ich habe mich vor 2-3 Jahren schon mit vgScene und DxScene beschäftigt und bin seinerzeit mit der etwas eigenwilligen IDE- Integration und zahlreichen Bugs nicht zurecht gekommen. Nachdem nun (Achtung: Gaanz!Neue!Info!) FireMonkey darauf basiert, habe ich mir die letzte Version unter XE installiert und mich nochmals intensiv damit beschäftigt. Fazit: Klasse.

Was aber allem die Krone aufsetzt: Ich habe eine vgScene-Demo auf meinem ca. 12 Jahren alten 1GHz, 256 MB, 14" Siemens-Notebook getestet und bin begeistert, wie smooth (nicht im Sinne von TMS) das alles selbst dort läuft. Das ist wirklich eine gute Basis für eine auch aufwändige GUI.

Die IDE-Integration von vgScene ist nach wie vor sehr gewöhnungsbedürftig, aber nachdem ich mir angewöhnt habe, nur noch abgeleitete Komponenten und Controls zu benutzen, passiert bei mir ohnehin alles "zu Fuß" und abseits des Delphi-IDE-Form-Designers.

Das Konzept von FireMonkey/vgScene ist - verglichen mit der VCL - sehr vielversprechend. Man kann hier nicht nur wild Elemente (Controls, Animationen, Effekte etc.) im XML-Style komponieren, sondern auch die Eigenschaften ganz simpel überladen, indem man eine beliebige Definition zuweist. Das bedeutet praktisch, das man im Inspektor oder Code nur eine (1!) Eigenschaft (Name der Definition) zuweist, und damit das komplette Verhalten eines Controls umstellt.

Als Beispiel poste ich hier den Source zur im Anhang verfügbaren Exe-Demo. Dort erzeuge ich zur Laufzeit die 4 animierten Buttons, indem ich dem statischen TvgBitmapButton noch 3 Animationen unterordne, die in vorgegebener Zeit (Duration) eine Parent-Eigenschaft (PropertyName) von einem auf den anderen Wert verändert (Start-, StopValue).

Diese 3 Animationen werden in DoHoover gestartet und laufen gleichzeitig ab (im Gegensatz z.B. zu den Transitions von Billenium Effects):

Die PNGs sind nur einmal in einer TvgImageList abelegt und werden durch die BitmapSize-Animation FBmpSizeOut von 64 auf 120 px (und zurück) in 200 ms gezoomed, wobei der Button vergrößert FWidthOut, FPaddingOut und gleichzeitig auch die Größe des Container-Controls verändert wird (4. Animation definiert im DFM), was die LeftAligned-Buttons animiert bewegen lässt.

Das alles ist zwar eine neue Dimension bei der Gestaltung und Programmierung, aber wirklich leicht zu durchschauen und anzupassen. Man kann praktisch im VCL-Style beginnen und je nach Befarf beliebig komplexer werden. (Von den "Dreingaben" MacOs, iOs etc. ganz zu schweigen.)

Delphi-Quellcode:
unit Unit8;

interface

uses
  SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, vg_scene, vg_objects, vg_effects, vg_layouts, vg_ani,
  vg_controls, ImgList, vg_actions;

type
  TSelectedEvent = procedure (aHoover : Boolean = True) of object;

  TMySelectBtn = class(TvgBitmapButton)
  private
    FSelecting : Boolean;
    FSelected : Boolean;
    FSelectEvent : TSelectedEvent;
    FResetEvent : TNotifyEvent;
    FPaddingOut : TvgRectAnimation;
    FWidthOut : TvgFloatAnimation;
    FBmpSizeOut : TvgFloatAnimation;
    procedure DoOnClick(aSender : TObject);
    procedure DoPaddingAnimation;
    procedure DoWidthAnimation;
    procedure DoBmpSizeAnimation;
    procedure SetHoover(const Value: Boolean);
    procedure DoSelect;
  public
    constructor Create(aOwner : TComponent; aParent : TvgObject); reintroduce;

    property SelectEvent : TSelectedEvent read FSelectEvent write FSelectEvent;
    property ResetEvent : TNotifyEvent read FResetEvent write FResetEvent;
    property Selected : Boolean read FSelected write SetHoover;
  end;

  TForm8 = class(TForm)
    vgScene1 : TvgScene;
    Root1 : TvgBackground;
    Rectangle1 : TvgRectangle;
    Rectangle2 : TvgRectangle;
    Rectangle3 : TvgRectangle;
    Image1 : TvgImage;
    Text1 : TvgText;
    Text2 : TvgText;
    Layout1 : TvgLayout;
    Layout2 : TvgLayout;
    Layout3 : TvgLayout;
    Rectangle5 : TvgRectangle;
    Text3 : TvgText;
    Text4 : TvgText;
    Text5 : TvgText;
    Text6 : TvgText;
    vgResources1 : TvgResources;
    Container : TvgLayout;
    containerOut : TvgFloatAnimation;
    Resources1 : TvgResources;
    BitmapButton1 : TvgBitmapButton;
    vgImageList2 : TvgImageList;
    procedure DoContainerAnimation(aIsButtonSelected : Boolean = True);
    procedure DoReset(aSender : TObject);
  private
    BtnYellow : TMySelectBtn;
    BtnBlue : TMySelectBtn;
    BtnGreen : TMySelectBtn;
    BtnRed : TMySelectBtn;
  public
    constructor Create(aOwner : TComponent); override;
    procedure ResetAllButtons;
  end;

var
  Form8: TForm8;

implementation

{$R *.dfm}

procedure TForm8.ResetAllButtons;
/// Im Setter der Property wird die Animation ausgelöst.
begin
  BtnGreen.Selected := False;
  BtnRed.Selected := False;
  BtnBlue.Selected := False;
  BtnYellow.Selected := False;
  Container.Width := 450;
end;

procedure TForm8.DoContainerAnimation(aIsButtonSelected: Boolean);
/// Diese Animation macht den Container breiter, so das ein
/// (breiter) Selected-Button hineipasst. Da alle Nuttons Left-Aligned sind
/// gibt es einen schönen Verschiebe- Effekt.
begin
  containerOut.Inverse := not aIsButtonSelected;
  containerOut.Start;
end;

constructor TForm8.Create(aOwner : TComponent);
/// 4 Buttons für unseren Container, denen mitgegeben wird
/// welche Prozedur beim Resetten und Selected aufzurufen ist.
begin
  inherited;
  BtnYellow := TMySelectBtn.Create(Self, Container);
  if vgImageList2.Count > 0 then
    BtnYellow.Bitmap := vgImageList2.Images[0];
  BtnYellow.Text := 'Yellow';
  BtnYellow.SelectEvent := DoContainerAnimation;
  BtnYellow.ResetEvent := DoReset;

  BtnBlue := TMySelectBtn.Create(Self, Container);
  if vgImageList2.Count > 1 then
    BtnBlue.Bitmap := vgImageList2.Images[1];
  BtnBlue.Text := 'Blue';
  BtnBlue.SelectEvent := DoContainerAnimation;
  BtnBlue.ResetEvent := DoReset;

  BtnGreen := TMySelectBtn.Create(Self, Container);
  if vgImageList2.Count > 2 then
    BtnGreen.Bitmap := vgImageList2.Images[2];
  BtnGreen.Text := 'Green';
  BtnGreen.SelectEvent := DoContainerAnimation;
  BtnGreen.ResetEvent := DoReset;

  BtnRed := TMySelectBtn.Create(Self, Container);
  if vgImageList2.Count > 3 then
    BtnRed.Bitmap := vgImageList2.Images[3];
  BtnRed.Text := 'Red';
  BtnRed.SelectEvent := DoContainerAnimation;
  BtnRed.ResetEvent := DoReset;

end;

procedure TForm8.DoReset(aSender: TObject);
/// Zurück auf Anfang.
begin
  ResetAllButtons;
end;

{ TMySelectBtn }

constructor TMySelectBtn.Create(aOwner : TComponent; aParent : TvgObject);
begin
  inherited Create(aOwner);
  FSelected := False;
  Parent := aParent;
  Position.X := 1000; // entspricht Left
  Align := vaLeft;
  Resource := 'acroButton'; // Definition im DFM
  Width := 110;
  BitmapLayout := vgGlyphTop;
  BitmapSize := 64;
  BitmapPadding := 13;
  Font.Size := 14;
  OnClick := DoOnClick;

  // 1. Animation für das "Oversizen"
  FPaddingOut := TvgRectAnimation.Create(aOwner);
  FPaddingOut.Parent := Self;
  FPaddingOut.PropertyName := 'Padding';
  FPaddingOut.Duration := 0.2;
  FPaddingOut.StartValue := TvgBounds.Create(vgRect(0, 0, 0, 0));
  FPaddingOut.StopValue := TvgBounds.Create(vgRect(0, -60, 0, -30));

  // 2. Animation für das Vergrößern/Verkleiner beim Selektieren/Klicken
  FWidthOut := TvgFloatAnimation.Create(aOwner);
  FWidthOut.Parent := Self;
  FWidthOut.PropertyName := 'Width';
  FWidthOut.Duration := 0.2;
  FWidthOut.StartValue := 110;
  FWidthOut.StopValue := 260;

  // 3. Animation für das Zoomen der Button-Grafik
  FBmpSizeOut := TvgFloatAnimation.Create(aOwner);
  FBmpSizeOut.Parent := Self;
  FBmpSizeOut.PropertyName := 'BitmapSize';
  FBmpSizeOut.Duration := 0.2;
  FBmpSizeOut.StartValue := 64;
  FBmpSizeOut.StopValue := 120;
end;

procedure TMySelectBtn.DoSelect;
/// Gleichzeitiges Starten der Animationen, dadurch ist die Reihenfolge egal.
begin
  if FSelecting then
    Exit;
  FSelecting := True;
  try
    FSelected := not FSelected;
    if Assigned(FResetEvent) then
      FResetEvent(Self);
      DoPaddingAnimation;
      DoWidthAnimation;
      DoBmpSizeAnimation;
      if Assigned(FSelectEvent) then
        FSelectEvent(FSelected);
  finally
    FSelecting := False;
  end;
end;

procedure TMySelectBtn.DoOnClick(aSender: TObject);
begin
  DoSelect;
end;

procedure TMySelectBtn.DoPaddingAnimation;
begin
  FPaddingOut.Inverse := not FSelected;
  FPaddingOut.Start;
end;

procedure TMySelectBtn.SetHoover(const Value: Boolean);
begin
  if FSelected <> Value then
    DoSelect;
end;

procedure TMySelectBtn.DoWidthAnimation;
begin
  FWidthOut.Inverse := not FSelected;
  FWidthOut.Start;
end;

procedure TMySelectBtn.DoBmpSizeAnimation;
begin
  FBmpSizeOut.Inverse := not FSelected;
  FBmpSizeOut.Start;
end;

end.
Die Begeisterung der Delphi-Mannen ist für mich unbedingt nachvollziehbar.
Miniaturansicht angehängter Grafiken
vgscenedemo.png  
Angehängte Dateien
Dateityp: rar vgSceneDemo.rar (724,4 KB, 150x aufgerufen)
Andreas

Geändert von neo4a (25. Aug 2011 um 13:59 Uhr) Grund: Anhänge hinzugefügt, Refactoring
  Mit Zitat antworten Zitat