Jump to content
eivindbakkestuen

CreateComponent() equivalent for non-component classes?

Recommended Posts

Using the WrapDelphi and associated classes,

 

I have probably missed it, but I couldn't see an equivalent to the CreateComponent() method to create non-TComponent descendant classes, eg TStringList etc which I needed for things in the .PY script below. Is there an existing way of creating such classes on the fly in the .PY script?


 

  ...

  db = CreateComponent("TnxDatabase", None)

  sl = TStringList (?)

  db.GetTableList(sl)

  print(*sl)

  ...

 

I added the following method and registered it, and now I can do sl = CreateClass("TStringList", None) and it works. If there's no such built in method, feel free to assimilate this method into the WrapDelphi unit. 🙂

 


 


function TPyDelphiWrapper.CreateClass(pself, args: PPyObject): PPyObject;
//  Exposed function at the Module level
//  CreateClass(ClassName, Owner)
var
  KlassName : PAnsiChar;
  _obj : PPyObject;
  Klass : TClass;
  _comp : TObject;
  TheClass : TObject;
  Ownership : TObjectOwnership;
begin
  Result := nil;
  CheckEngine;
  with Engine do begin
    if PyArg_ParseTuple( args, 'sO:CreateDelphiClass', @KlassName, @_obj ) <> 0 then begin
      try
        Klass := GetClass(string(KlassName));
      except
        Klass := nil;
      end;
      if (Klass = nil) or not Klass.InheritsFrom(TObject) then begin
        PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(
          Format(rs_ErrInvalidArgs, ['CreateClass', rs_InvalidClass]))));
        Exit;
      end;

      TheClass := TClass(Klass).Create;
      Ownership := soOwned;
      Result := Self.Wrap(TheClass, Ownership);
    end else
      PyErr_SetString(PyExc_TypeError^, PAnsiChar(EncodeString(
        Format(rs_ErrInvalidArgs, ['CreateClass', '']))));
  end;
end;

 

Share this post


Link to post

The recommended way to expose classes is to use  TPyClassWrapper<T: class>.

 

If for example you have a class TMyClass you want to expose to python, you can use the above from unit wrappers as follows:

PyDelphiWrapper1.RegisterDelphiWrapper(TPyClassWrapper<TMyClass>);

or at runtime (e.g. inside the FormCreate handler:

PyDelphiWrapper1.RegisterDelphiWrapper(TPyClassWrapper<TMyClass>).Initialize;

If you want your class to capable of being instantiated from python then do:

    TMyClassWrapper = class(TPyClassWrapper<TMyClass>)
      constructor CreateWith(APythonType: TPythonType; args, kwds: PPyObject); overload; override;
    end;

    constuctor TMyClassWrapper.CreateWith(APythonType: TPythonType; args, kwds: PPyObject);
    begin
      Create(APythonType);
      DelphiObject := TMyClass.Create;
    end;

and in the FormCreate handler:

    PyDelphiWrapper1.RegisterDelphiWrapper(TMyClassWrapper).Initialize;

In your python script you can then create instances using the pythonic

from delphi_module import MyClass
obj = MyClass()

With TStringList is a bit more complicated since the superclass TStrings has already been exposed.   To maintain the TStrings functionality you need to do the following:

type
  TStringListWrapper = class(TPyDelphiStrings)
  private
    function GetDelphiObject: TStringList;
    procedure SetDelphiObject(const Value: TStringList);
  public
    constructor CreateWith(APythonType: TPythonType; args, kwds: PPyObject); overload; override;
    class function  DelphiObjectClass : TClass; override;
    class procedure RegisterMethods( PythonType : TPythonType ); override;
    class procedure RegisterGetSets( PythonType : TPythonType ); override;
    // Properties
    property DelphiObject: TStringList read GetDelphiObject write SetDelphiObject;
  end;

class function TStringListWrapper.DelphiObjectClass: TClass;
begin
  Result := TStringList;
end;

function TStringListWrapper.GetDelphiObject: TStringList;
begin
  Result := inherited DelphiObject as TStringList;
end;

class procedure TStringListWrapper.RegisterGetSets(PythonType: TPythonType);
begin
  // Do not call inherited
end;

class procedure TStringListWrapper.RegisterMethods(PythonType: TPythonType);
begin
  // Do not call inherited
end;

procedure TStringListWrapper.SetDelphiObject(const Value: TStringList);
begin
  inherited DelphiObject := Value;
end;

constructor TStringListWrapper.CreateWith(APythonType: TPythonType; args, kwds: PPyObject);
begin
  Create(APythonType);
  DelphiObject := TStringList.Create;
end;

and in the FormCreate handler:

  PyDelphiWrapper1.RegisterDelphiWrapper(TStringListWrapper).Initialize;

You can then use it in your python scripts as follows:

from delphi_module import StringList
sl = StringList()
sl.Add("abc")
print(sl[0])

 

 

Edited by pyscripter

Share this post


Link to post

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

×