Jump to content
Sign in to follow this  
FranzB

create delphi4python at run time

Recommended Posts

I have created the following simple  application which should run on WINDOWS and LINUX  using FMX framework and  creating  delphi4python components  on run time .

Why does this  demo code  not  show any output result  ? 

Most important line of code  is  this , or not ...?     PythonInOut.OnSendUniData :=  PythonInputOutputSendUniData;

 

I know  this source https://blogs.embarcadero.com/learn-how-to-dynamically-create-and-destroy-python4delphi-components-with-a-delphi-windows-app/

but I intend to create a minimum code sequence

 

 

 

type
  TForm1 = class(TForm)
    memoIn: TMemo;
    Splitter1: TSplitter;
    memoOut: TMemo;
    Panel1: TPanel;
    Button1: TButton;
    btnLoadScript: TButton;
    dlgOpen_pythonscript: TOpenDialog;
    btn_CreatePythonEnviroment: TButton;
    btn_FreePythonEnviroment: TButton;
    procedure Button1Click(Sender: TObject);
    procedure PythonInputOutputSendUniData(Sender: TObject; const Data: string);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnLoadScriptClick(Sender: TObject);
    procedure btn_CreatePythonEnviromentClick(Sender: TObject);
    procedure btn_FreePythonEnviromentClick(Sender: TObject);
  private
    { Private declarations }
    FOutputStream: TMemoryStream;
    FCriticalSection: TCriticalSection;
  public
    { Public declarations }

    PythonEngine: TPythonEngine;
    PythonInOut: TPythonInputOutput;

  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.btnLoadScriptClick(Sender: TObject);
begin
  if dlgOpen_pythonscript.Execute then
  begin
    memoIn.Lines.Clear;

    memoIn.Lines.LoadFromFile(dlgOpen_pythonscript.FileName)
  end;
end;

///
///   did not drop components on a  form , create components at run time ...
///
procedure TForm1.btn_CreatePythonEnviromentClick(Sender: TObject);

begin

  PythonEngine := TPythonEngine.Create(nil);

  PythonInOut := TPythonInputOutput.Create(nil);

  try

    PythonEngine.AutoLoad := true;

{$IFDEF LINUX}
    PythonEngine.DllName := 'libpython3.6m.so';
    PythonEngine.DllPath := '/usr/lib/x86_64-linux-gnu/';
{$ENDIF}
{$IFDEF MSWINDOWS}
    PythonEngine.DllName := 'python310.dll';
    PythonEngine.DllPath := '';
{$ENDIF}
    PythonEngine.AutoFinalize := true;
    PythonEngine.AutoLoad := true;
    PythonEngine.AutoUnload := true;
    PythonEngine.RedirectIO := true;
    PythonEngine.UseLastKnownVersion := true;
    PythonEngine.Loaddll;

    PythonEngine.IO :=  PythonInOut;

    PythonInOut.RawOutput := True;
    PythonInOut.OnSendUniData :=  PythonInputOutputSendUniData;



  except
    on E: Exception do
      writeln(E.ClassName, ': ', E.Message);

  end;
end;



procedure TForm1.Button1Click(Sender: TObject);
begin
  PythonEngine.ExecString(UTF8Encode(memoIn.Text));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FOutputStream := TMemoryStream.Create;
  FCriticalSection := TCriticalSection.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FOutputStream.Free;
  FCriticalSection.Free;
end;

procedure TForm1.PythonInputOutputSendUniData(Sender: TObject;
  const Data: string);
{
  FMX TMemo is slow when adding many lines one by one.
  To avoid this we accumulate output and print it in one go.
  The critical section allows for multiple threads to print.
  If you use this code then set PythonInputOuput.RawOutput to True

  A simpler solution would be to set RawOuput to False and then do

  MemoOut.Lines.Add(Data);
  MemoOut.GoToTextEnd;

  This should be good enough if python does not produce a massive
  amount of output.
}
Var
  ScheduleWrite: Boolean;
begin
  if Data = '' then
    Exit;

  FCriticalSection.Enter;
  try
    ScheduleWrite := FOutputStream.Size = 0;
    FOutputStream.Write(Data[1], Length(Data) * 2);

    if ScheduleWrite then

      TThread.ForceQueue(nil,
        procedure
        var
          WS: string;
        begin
          FCriticalSection.Enter;
          try
            if FOutputStream.Size > 0 then
            begin
              SetLength(WS, FOutputStream.Size div 2);
              FOutputStream.Position := 0;
              FOutputStream.Read(WS[1], Length(WS) * 2);
              FOutputStream.Size := 0;
              if (memoOut.Lines.Count > 0) and
                (memoOut.Lines[memoOut.Lines.Count - 1] <> '') then
                memoOut.Lines.Add('');
              memoOut.Text := memoOut.Text + WS;
              memoOut.GoToTextEnd;
            end;
          finally
            FCriticalSection.Leave;
          end;
        end);
  finally
    FCriticalSection.Leave;
  end;
end;

end.

 

Edited by FranzB

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
Sign in to follow this  

×