Wie Property Editor erzeugen?

Rund um die LCL und andere Komponenten
Antworten
wennerer
Beiträge: 239
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 19.3 Cinnamon, Lazarus Stable 2.0.10 r63673M FPC 3.2.0
CPU-Target: x86_64-linux-gtk2

Wie Property Editor erzeugen?

Beitrag von wennerer »

Hallo an Alle,
ich versuche mich daran in einer Komponente einen Property Editor zu erzeugen um eine PNG mittels Objekt Inspektor zu laden. Vorgegangen bin ich nach folgendem Wiki Artikel:
https://wiki.freepascal.org/How_To_Writ ... ty_editors
Ich bin nun soweit das ich beim Klicken in den OI in der Edit Procedure des Editors lande. Dort öffne ich einen Dialog um eine PNG zu wählen. Leider begreife ich nicht wie ich nun die PNG an die Set-Procedure der Komponente übergeben muss. Ich hab auch nichts zu den Befehlen "GetObjectValue" und "SetPtrValue" gefunden um deren Funktion zu ergründen.

Hier mal einer meiner erfolglosen Versuche, ich würde mich sehr freuen wenn mir jemand sagen könnte was ich da ändern muss:

Code: Alles auswählen

unit EditTest;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
  PropEdits;
  //Neue Anforderung IDEIntf

type

  { TPNGProperty }

  TPNGProperty = class (TClassPropertyEditor)
  public
   procedure Edit; Override;
   function  GetValue: string;Override;
   function  GetAttributes: TPropertyAttributes; Override;

  end;


type

  { TEditTest }

  TEditTest = class(TCustomControl)
  private
    FPNG: TPortableNetworkGraphic;
    procedure SetPNG(AValue: TPortableNetworkGraphic);

  protected

  public
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
   procedure Paint; override;
  published
   property PNG : TPortableNetworkGraphic read FPNG write SetPNG;
  end;

procedure Register;

implementation

procedure Register;
begin
  {$I edittest_icon.lrs}
  RegisterComponents('Standard',[TEditTest]);
  RegisterPropertyEditor(TypeInfo(TPortableNetworkGraphic),nil,'PNG',TPNGProperty);
end;

{ TPNGProperty }

procedure TPNGProperty.Edit;
var OpenDialog : TOpenDialog;
    TmpPng     : TPortableNetworkGraphic;
    TmpEditTest: TEditTest;
begin
  //inherited Edit;
  //showmessage('Edit');
  try
   TmpEditTest := TEditTest.Create(nil);
    //showmessage('1');
   TmpEditTest := TEditTest(GetObjectValue(TEditTest));
    //showmessage('2');
   TmpPNG      := TPortableNetworkGraphic.Create;
    //showmessage('3');
   OpenDialog  := TOpenDialog.Create(nil);
    //showmessage('4');
   if OpenDialog.Execute then
   TmpPNG.LoadFromFile(OpenDialog.FileName);
    //showmessage('5');
   TmpEditTest.FPNG.Assign(TmpPNG);
   SetPtrValue(TmpEditTest.PNG);

  finally
   OpenDialog.Free;
   TmpPng.Free;
   TmpEditTest.Free;
  end;
end;

function TPNGProperty.GetValue: string;
begin
  //Result:=inherited GetValue;
  result := 'TPortableNetworkGraphic';
end;

function TPNGProperty.GetAttributes: TPropertyAttributes;
begin
  //Result:=inherited GetAttributes;
  Result := [paMultiSelect, paDialog];
end;

{ TEditTest }

procedure TEditTest.SetPNG(AValue: TPortableNetworkGraphic);
begin
  if FPNG=AValue then Exit;
  FPNG.Assign(aValue);
  //showmessage('SetPng');
  Invalidate;
end;

constructor TEditTest.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  width  := 40;
  height := 40;
  FPNG   := TPortableNetworkGraphic.Create;
end;

destructor TEditTest.Destroy;
begin
  inherited Destroy;
  FPNG.Free;
end;

procedure TEditTest.Paint;
begin
  inherited Paint;
  canvas.Brush.Color:= clwhite;
  canvas.FillRect(0,0,width,height);
  canvas.Draw(0,0,FPNG);
end;

end.
Viele Grüße
Bernd
Dateianhänge
EditorTest.zip
(68.44 KiB) 33-mal heruntergeladen

Sieben
Beiträge: 94
Registriert: Mo 24. Aug 2020, 14:16
OS, Lazarus, FPC: Ubuntu Xenial 32, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: i386

Re: Wie Property Editor erzeugen?

Beitrag von Sieben »

Schau dir doch mal die Datei graphpropedits.pas in /components/ideintf an, darin TGraphicPropertyEditor und TPicturePropertyEditor. Vermutlich wäre es auch am einfachsten, von dort abzuleiten und auch das übliche Form zu benutzen (graphicpropedit.pas/lfm).

wp_xyz
Beiträge: 3462
Registriert: Fr 8. Apr 2011, 09:01

Re: Wie Property Editor erzeugen?

Beitrag von wp_xyz »

Ich habe mich vor einiger Zeit schon mal da reingewühlt, muss aber sagen, dass ich das alles wieder vergessen habe.

Also, was ich machen würde, ist das: Gibt es eine Komponente und eine Eigenschaft, die so ähnlich sind wie deine? Ich denke, du möchtest ein Icon auswählen für deinen Doppel-Button. Da ist z.B. TImage.Picture ganz ähnlich. Also würde ich nachsehen (in einer der *Edits-Units in (lazarus)/components/ideintf), wie der Property-Editor für TPicture gemacht ist. Wenn du die Dateinamen in diesem Verzeichnis durchrollst, dann siehst du "graphpropedits.pas" - klingt vielversprechend! In die IDE laden und ans Ende scrollen - da stehen die Registrierungsanweisungen. Unter anderem mit diesem:

Code: Alles auswählen

  RegisterPropertyEditor(ClassTypeInfo(TGraphic), nil,'',TGraphicPropertyEditor);
  RegisterPropertyEditor(ClassTypeInfo(TPicture), nil,'',TPicturePropertyEditor); 
Das heißt: für die Eigenschaft TPicture ist TPicturePropertyEditor zuständig -- da könntest du spicken.

Noch interessanter ist die Zeile darüber: Für alle Properties, die von TGraphic abgeleitet sind (also TBitmap, TIcon, aber auch TPortableNetworkGraphic) gibt es schon einen fertigen PropertyEditor: TGraphicPropertyEditor (von dem sogar TPicturePropertyEditor abgeleitet ist). Daher behaupte ich mal, wenn du deine Komponente installiert hast, müssten im Objekt-Inspektor neben der Property PNG automatisch die '...' auftauchen, so dass der richtige Property-Editor geöffnet wird.

P.S. Sieben war schneller...

Nochmal P.S.
Habe gerade deine Komponente installiert und vorher den Komponenten-Editor auskommentiert, und siehe da: ja -- neben dem PNG sind im Objektinspektor die '...', und diese öffnen den Standard-Imageeditor.

Eigentlich war das schon alles - nichts machen ("Die meisten Aufgaben erledigen sich von selbst, indem nach nichts macht"). falls du aber nicht damit zufrieden bist, dass der Standard-ImageEditor alle registrierten Bild-Typen laden kann, also nicht nur png-Dateien, dann musst du doch eine TPNGPropertyEditor schreiben. Den leitest du aber von TGraphicPropertyEditor ab, so dass du schon das Grundgerüst hast. Die musst eigentlich nur die Methode Edit neu schreiben, in der ein Formular erzeugt wird - es kann alles so bleiben wie bisher, es müssen nur die anderen Dateitypen ausgeblendet werden.

Da auch Icons Transparenz haben, ist es allerdings etwas ungeschickt, sich nur auf png zu versteifen.
Zuletzt geändert von wp_xyz am Do 8. Okt 2020, 22:13, insgesamt 3-mal geändert.

Sieben
Beiträge: 94
Registriert: Mo 24. Aug 2020, 14:16
OS, Lazarus, FPC: Ubuntu Xenial 32, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: i386

Re: Wie Property Editor erzeugen?

Beitrag von Sieben »

Zum Thema Aufbau von Packages, die IDEIntf verwenden habe ich übrigens hier:

https://forum.lazarus.freepascal.org/in ... 642.0.html

noch wertvolle Tips erhalten. 'Runtime Only' für die eigentlichen Komponenten scheint allerdings nicht zu klappen, da das DesignTime-Package das Runtime auch mit in die IDE ziehen will. Ansonsten habe ich jetzt die Komponenten mit der entsprechenden lpk in einem Verzeichnis, und den ganzen Register-Kram mit entsprechender lpk in einem Unterverzeichnis desselben, was gut zu klappen scheint.

Sieben
Beiträge: 94
Registriert: Mo 24. Aug 2020, 14:16
OS, Lazarus, FPC: Ubuntu Xenial 32, Lazarus 2.0.10, FPC 3.2.0
CPU-Target: i386

Re: Wie Property Editor erzeugen?

Beitrag von Sieben »

P.S. Sieben war schneller...
Du dafür gründlicher. That said, es gibt Neues da oben... ^^^

wennerer
Beiträge: 239
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 19.3 Cinnamon, Lazarus Stable 2.0.10 r63673M FPC 3.2.0
CPU-Target: x86_64-linux-gtk2

Re: Wie Property Editor erzeugen?

Beitrag von wennerer »

Vielen Dank an euch beide!
Ich konnte jetzt den Code so umstellen das die PNG an die Komponente übergeben wird. Ob ich letztlich den Standard Editor verwende oder was eigenes probiere weiß ich noch nicht, aber ich kann ja mal etwas damit herumspielen.
Falls sich Jemand für mein minimal Ergebnis interessiert hier ist es:

Code: Alles auswählen

unit EditTest;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
  PropEdits, GraphPropEdits;
  //Neue Anforderung IDEIntf

type

  { TPNGProperty }

  TPNGProperty = class (TGraphicPropertyEditor)
  public
   procedure Edit; Override;
  end;


type

  { TEditTest }

  TEditTest = class(TCustomControl)
  private
    FPNG: TPortableNetworkGraphic;
    procedure SetPNG(AValue: TPortableNetworkGraphic);

  protected

  public
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
   procedure Paint; override;
  published
   property PNG : TPortableNetworkGraphic read FPNG write SetPNG;
  end;

procedure Register;

implementation

procedure Register;
begin
  {$I edittest_icon.lrs}
  RegisterComponents('Standard',[TEditTest]);
  RegisterPropertyEditor(ClassTypeInfo(TPortableNetworkGraphic),nil,'PNG',TPNGProperty);
end;

{ TPNGProperty }

procedure TPNGProperty.Edit;
var TmpPng   : TPortableNetworkGraphic;
    OpenDialog : TOpenDialog;
 begin
  TmpPng     := TPortableNetworkGraphic(GetObjectValue(TPortableNetworkGraphic));
  try
   OpenDialog   := TOpenDialog.Create(nil);
   TmpPng := TPortableNetworkGraphic.Create;
   if OpenDialog.Execute then
   TmpPng.LoadFromFile(OpenDialog.FileName);
   SetPtrValue(TmpPng);
  finally
   TmpPng.Free;
   OpenDialog.Free;
  end;
end;

procedure TEditTest.SetPNG(AValue: TPortableNetworkGraphic);
begin
  if FPNG=AValue then Exit;
  FPNG.Assign(aValue);
  Invalidate;
end;

constructor TEditTest.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  width  := 40;
  height := 40;
  FPNG   := TPortableNetworkGraphic.Create;
end;

destructor TEditTest.Destroy;
begin
  inherited Destroy;
  FPNG.Free;
end;

procedure TEditTest.Paint;
begin
  inherited Paint;
  canvas.Brush.Color:= clwhite;
  canvas.FillRect(0,0,width,height);
  canvas.Draw(0,0,FPNG);
end;

end.
Viele Grüße
Bernd

Antworten