Recent

Author Topic: Custom property changes not in executable  (Read 3580 times)

criageek

  • Jr. Member
  • **
  • Posts: 79
Custom property changes not in executable
« on: October 25, 2014, 02:54:54 am »
I have a custom component that has a custom property that itself is an object (descended from TComponent).  I've managed to create a property editor for this new property and everything seems to work properly when setting property values at design time.  Changes in either the Object Inspector, or in my property editor are displayed correctly in the Object inspector.  However, when I run my app changes to the property values are not reflected in the  executable.  Here is the code for ecerything...the custom property, the property editor, and the custom component.  What am I doing wrong?

unit MyCustomComponent;

//{$mode objfpc}{$H+}
{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, StdCtrls, PropEdits, Forms, Buttons, Spin, Dialogs,
  Controls;

Type
  TMyCustomProperty = Class(TComponent)
  Private
    FMyInteger: Integer;
    FMyString: String;
    Procedure SetMyInteger(pMyInteger: Integer);
    Procedure SetMyString(pMyString: String);
  Public
    Constructor Create(AOwner: TComponent); Override;
    Destructor Destroy;
    Procedure Copy(pMyCustomProperty: TMyCustomProperty);
  Published
    Property MyInteger: Integer read FMyInteger
                               write SetMyInteger;
    Property MyString: String read FMyString
                             write SetMyString;
  end;


{ TMyCustomPropertyPropertyEditor }
  TMyCustomPropertyPropertyEditor = class(TClassPropertyEditor)
  public
    procedure Edit; override;
    function GetAttributes: TPropertyAttributes; override;
  end;

{ TfrmMyCustomPropertyPropertyEditor }
  TfrmMyCustomPropertyPropertyEditor = class(TForm)
    bitOK: TBitBtn;
    bitCancel: TBitBtn;
    txtString: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    speInteger: TSpinEdit;
    Procedure FormCreate(Sender: TObject);
    procedure speIntegerChange(Sender: TObject);
    procedure txtStringChange(Sender: TObject);
  private
    { private declarations }
    FMyCustomProperty: TMyCustomProperty;
    FMyCustomPropertyOrig: TMyCustomProperty;
    Procedure SetMyCustomProperty(Value: TMyCustomProperty);
  public
    { public declarations }
    function Execute: Boolean;

    Property MyCustomProperty: TMyCustomProperty read FMyCustomProperty
                                                write SetMyCustomProperty;
  end;

  TMyCustomComponent = class(TEdit)
  private
    { Private declarations }
    FMyInteger: Integer;
    FMyString: String;
    FMyCustomProperty: TMyCustomProperty;
    Procedure DoubleClick(Sender: TObject);
  protected
    { Protected declarations }
  public
    { Public declarations }
    Constructor Create(AOwner: TComponent); Override;
    Destructor Destroy; Override;
  published
    { Published declarations }
    Property MyCustomProperty: TMyCustomProperty read FMyCustomProperty
                                                write FMyCustomProperty;
    Property MyInteger: Integer read FMyInteger
                               write FMyInteger;
    Property MyString: String read FMyString
                             write FMyString;

  end;

procedure Register;

var
  frmMyCustomPropertyPropertyEditor: TfrmMyCustomPropertyPropertyEditor;

implementation

{$R mycustompropertypropedit.lfm}

function TMyCustomPropertyPropertyEditor.GetAttributes: TPropertyAttributes;
begin
  Result := [paDialog, paSubProperties];
end; {GetAttributes}

procedure TMyCustomPropertyPropertyEditor.Edit;
var
  lvDialog: TfrmMyCustomPropertyPropertyEditor;
begin
  lvDialog := TfrmMyCustomPropertyPropertyEditor.Create(nil);
  try
    lvDialog.MyCustomProperty := TMyCustomProperty(GetOrdValue);
    if lvDialog.Execute then
      Begin
        SetOrdValue(longint(lvDialog.MyCustomProperty));
      end;
  finally
    lvDialog.Free;
  end;
end;

Procedure TfrmMyCustomPropertyPropertyEditor.FormCreate(Sender: TObject);
Begin
  If FMyCustomPropertyOrig = Nil Then
    Begin
      FMyCustomPropertyOrig := TMyCustomProperty.Create(Self);
    end;
end;

procedure TfrmMyCustomPropertyPropertyEditor.speIntegerChange(Sender: TObject);
begin
  FMyCustomProperty.MyInteger := speInteger.Value;
end;

procedure TfrmMyCustomPropertyPropertyEditor.txtStringChange(Sender: TObject);
begin
  FMyCustomProperty.MyString := txtString.Text;
end;

Procedure TfrmMyCustomPropertyPropertyEditor.SetMyCustomProperty(Value: TMyCustomProperty);
Begin
  FMyCustomPropertyOrig.Copy(Value);
  FMyCustomProperty := Value;
  speInteger.Value := FMyCustomProperty.MyInteger;
  txtString.Text := FMyCustomProperty.MyString;
end;

function TfrmMyCustomPropertyPropertyEditor.Execute: Boolean;
Var
  lvModalResult: TModalResult;
begin
  lvModalResult := ShowModal;
  If lvModalResult <> mrOK Then
     FMyCustomProperty.Copy(FMyCustomPropertyOrig);
  Result := (lvModalResult = mrOK);
end;

Procedure TMyCustomProperty.SetMyInteger(pMyInteger: Integer);
Begin
  If pMyInteger <> FMyInteger Then
    Begin
      FMyInteger := pMyInteger;
    end;
end;

Procedure TMyCustomProperty.SetMyString(pMyString: String);
Begin
  If pMyString <> FMyString Then
    Begin
      FMyString := pMyString;
    end;
end;

Procedure TMyCustomProperty.Copy(pMyCustomProperty: TMyCustomProperty);
Begin
  FMyInteger := pMyCustomProperty.MyInteger;
  FMyString := pMyCustomProperty.MyString;
end;

Constructor TMyCustomProperty.Create(AOwner: TComponent);
Begin
  Inherited Create(AOwner);
end;

Destructor TMyCustomProperty.Destroy;
Begin
  Inherited Destroy;
end;

Procedure TMyCustomComponent.DoubleClick(Sender: TObject);
Begin
  Text := IntToStr(FMyInteger) + ';  ' + FMyString;
end;

Constructor TMyCustomComponent.Create(AOwner: TComponent);
Begin
  FMyCustomProperty := TMyCustomProperty.Create(Self);
  FMyCustomProperty.MyInteger := 7;
  FMyCustomProperty.MyString := 'Test';
  Inherited Create(AOwner);
  OnDblClick := DoubleClick;
end;

Destructor TMyCustomComponent.Destroy;
Begin
  FMyCustomProperty.Free;
  Inherited Destroy;
end;

procedure Register;
begin
  RegisterComponents('RD Controls',[TMyCustomComponent]);
  RegisterPropertyEditor(TypeInfo(TMyCustomProperty), nil, '', TMyCustomPropertyPropertyEditor);
end;

end.

criageek

  • Jr. Member
  • **
  • Posts: 79
Re: Custom property changes not in executable
« Reply #1 on: October 25, 2014, 03:04:24 am »
Also, when I close the project and re-open it, changes to the property values are not retained.

Rich

criageek

  • Jr. Member
  • **
  • Posts: 79
Re: Custom property changes not in executable
« Reply #2 on: October 25, 2014, 03:54:28 am »
Just realized I may have confused things a bit.  My custom property component (TMyCustomProperty) includes fields FMyInteger and FMyString.  I also added fields FMyInteger and FMyString directly into TMyCustomComponent in order to do some testing.  Changes to these fields ARE reflected in the executable, but not changes to the FMyInteger and FMyString fields in the custom property TMyCustomProperty.  Hope this makes sense.

Rich

criageek

  • Jr. Member
  • **
  • Posts: 79
Re: Custom property changes not in executable
« Reply #3 on: October 29, 2014, 06:40:21 pm »
I'm going to bump this once to see if I can get any help.  I've also attached the lfm file for the property editor dialog in case anyone want to try this themselves.

Rich

Never

  • Sr. Member
  • ****
  • Posts: 409
  • OS:Win7 64bit / Lazarus 1.4
Re: Custom property changes not in executable
« Reply #4 on: October 29, 2014, 06:48:02 pm »
hello
there is a very instructive article in wiki [Author: minesadorada]
[ http://wiki.freepascal.org/Lazarus_Nongraphical_Visual_Component_Example_Code ]
helped me a lot i belive will help you too
Νέπε Λάζαρε λάγγεψων οξωκά ο φίλοσ'ς αραεύσε

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Custom property changes not in executable
« Reply #5 on: October 29, 2014, 08:29:53 pm »
I've never tried to do what you want to do here, but my guess is that (since the streaming mechanism knows nothing about your TMyCustomProperty) that you will need to get your custom component property editor to descend from TPersistentPropertyEditor, and then override GetValue and SetValue to guide the component streaming process along the path you need to get your custom subproperties saved and subsequently read.

Two other points:
 - TMyCustomProperty's destructor needs "override;" added
 - the convention is to name class complete-data-copy methods "Assign" (not Copy). Other developers will understand immediately what an Assign method is supposed to do when they browse your code.

 

TinyPortal © 2005-2018