Question

I am using python4delphi. How can I return an object from a wrapped Delphi class function?

Code Snippet:

I have a simple Delphi Class that I wrapped to Python Script, right?

TSimple = Class
Private
  function getvar1:string;
Public    
Published
  property var1:string read getVar1;
  function getObj:TSimple;
end;
... 
function TSimple.getVar1:string;
begin
  result:='hello';
end;
function TSimple.getObj:TSimple;
begin
  result:=self;
end;

I made the TPySimple like the demo32 to give class access to the Python code. My Python module name is test.

TPySimple = class(TPyDelphiPersistent)
  // Constructors & Destructors
  constructor Create( APythonType : TPythonType ); override;
  constructor CreateWith( PythonType : TPythonType; args : PPyObject ); override;
  // Basic services
  function  Repr : PPyObject; override;

  class function  DelphiObjectClass : TClass; override;
end;
...

{ TPySimple }

constructor TPySimple.Create(APythonType: TPythonType);
begin
  inherited;
  // we need to set DelphiObject property
  DelphiObject := TSimple.Create;
  with TSimple(DelphiObject) do begin
  end;
  Owned := True; // We own the objects we create
end;

constructor TPySimple.CreateWith(PythonType: TPythonType; args: PPyObject);
begin
  inherited;
  with GetPythonEngine, DelphiObject as TSimple do
    begin
      if PyArg_ParseTuple( args, ':CreateSimple' ) = 0 then
        Exit;
    end;
end;

class function TPySimple.DelphiObjectClass: TClass;
begin
  Result := TSimple;
end;

function TPySimple.Repr: PPyObject;
begin
  with GetPythonEngine, DelphiObject as TSimple do
    Result := VariantAsPyObject(Format('',[]));
    // or Result := PyString_FromString( PAnsiChar(Format('()',[])) );
end;

And now the python code:

import test

a = test.Simple()
# try access the property var1 and everything is right
print a.var1
# work's, but..
b = a.getObj();
# raise a exception that not find any attributes named getObj.
# if the function returns a string for example, it's work.
Était-ce utile?

La solution

According to the OP he's found the answer here: http://code.google.com/p/python4delphi/issues/detail?id=17

(A copy-paste for reference)

Hi,

I've a suggestion - make exposing Delphi objects to python painless by utilizing the new RTTI (runtime type information) feature in D2010 (and above).

Currently exposing a class to the hosted Python code needs to you to write too much code (check demo06), I guess if we take advantage of the new RTTI feature in the newer versions of Delphi, the process can be improved a lot.

For example, check out the Delphi chromium embedded project, all you have to do to expose the interface of any Delphi class to the JavaScript environment, is to register the class:

// this is your class exposed to JS 
  Test = class 
    class procedure doit(const v: string); 
  end; 

initialization 
// Register your class 
  TCefRTTIExtension.Register('app', Test);

// and in JavaScript code to call that class above:
app.doit(''foo'')', '', 0); 

Cool! Isn't it?

The above code was extracted from: http://groups.google.com/group/delphichromiumembedded/browse_thread/thread/1793e7ca66012f0c/8ab31a5ecdb6bf48?lnk=gst&q=JavaScript+return+#

Some intro about RTTI introduced since D2010: http://robstechcorner.blogspot.com/2009/09/delphi-2010-rtti-basics.html

Autres conseils

I have run into the same problem while using DelphiWrapper.

First, enable RTTI using {$METHODINFO ON} will prevent exception:

raise a exception that not find any attributes named getObj.

Write TSimple class like this:

{$METHODINFO ON}
TSimple = Class
Private
  function getvar1:string;
Public    
Published
  property var1:string read getVar1;
  function getObj:TSimple;
end;
{$METHODINFO OFF}

Now getObj function returns a value -- an Integer!!

I'll show you guys what I did. I modified Demo32:

Unit1.pas:

TPoint = class(TPersistent)
private
  fx, fy : Integer;
  fName : String;
public
  constructor Create();
  procedure OffsetBy( dx, dy : integer );
  function MySelf: TPoint;  //**access self using function**
published
  property x : integer read fx write fx;
  property y : integer read fy write fy;
  property Name : string read fName write fName;
  property MySelf2: TPoint read MySelf; //**access self using property**
end;

Python code in Memo1.Lines:

import spam

p = spam.Point(2, 5)

b = p.MySelf()  //**using function**
print 'Using MySelf: ', type(b), b
c = p.MySelf2   //**using property**
print 'Using MySelf2: ', type(c), c

Then it gives a result like this:

Using MySelf:  <type 'int'> 31957664
Using MySelf2:  <type 'Point'> (2, 5)

The function returns an int, that's wired. Maybe it's a pointer to a TPoint object incorrectly wrapped by DelphiWrapper.

Finally I found a compromise way in Demo8 using "AddMethod". Not beautiful at all!! But it works.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top