Jump to content

DennisTW

Members
  • Content Count

    12
  • Joined

  • Last visited

Posts posted by DennisTW


  1. Clicking mainform won't bring it in front of SubForm
    The following behaviour is different from Lazarus.
    procedure TForm1.BtnShowFormClick(Sender: TObject);
    begin
      SubForm := TForm.Create(Owner);
      SubForm.Show;//this will make SubForm appear in front of the current Form1.
          //Even if I click on Main Form1, it won't bring Form1 in front of SubForm again.
          //what should I do to bring Form1 in front of SubForm again?
          //I already tried bringtofront and sendtoback
    end;


  2. from the demo, (PyArg_ParseTuple( args, 'Lii',@psort, @i, @j) <> 0) defines a procedure of (handle, i, j : integer).

        function TThreadSortForm.Module_Swap( pself, args : PPyObject ) : PPyObject; cdecl;
        var
          psort: NativeInt;
          i, j: Integer;
        begin
          with GetPythonEngine do
          begin
            if (PyErr_Occurred() = nil) and
        {$IFDEF CPU64BITS}
              (PyArg_ParseTuple( args, 'Lii',@psort, @i, @j) <> 0)
        {$ELSE}
              (PyArg_ParseTuple( args, 'iii',@psort, @i, @j) <> 0)
        {$ENDIF}
            then
            begin
              TSortThread(psort).VisualSwap(i,j);
              Result := ReturnNone;
            end else
              Result := nil;
          end;
        end;
        
    How do I define a function (TheKey, TheValue : String) : String;
    I cannot find the definitions of the second parameter of PyArg_ParseTuple .


  3. 3 hours ago, SwiftExpat said:

    First note Dalija's response above about the TMemo.

     

    Your memory leak will be solved by calling finalize on modDBFiredac before you call free.

     

    If you are going to use python on a thread replace TPythonGUIInputOutput with TPythonInputOutput and consider using DEB to send messages to the main thread, it handles the sync.

    Excuse me. What is DEB?  I googled but can't find it. 


  4. 3 hours ago, Dalija Prasnikar said:

    I don't use Python4Delphi so I cannot accurately tell what can and what cannot be done with it in context of threads. 

     

    But there is one thing definitely wrong in your code and that is constructing TMemo in the context of the background thread. VCL controls can only ever be used from the main thread. Because how that memo control is connected to the Python engine sounds like it is TComponent based. Just being TComponent based does not necessarily mean that it cannot be used in the background threads, but in such cases all related components must belong to the same thread. 

     

    If we know that TMemo must be used in the main thread, then if you connect it to the Python engine implies that such configured Python engine also must be constructed and used from the main thread.

     

    Just because you managed to "make it work" without obvious error (if you ignore the leak), does not mean that this kind of setup actually works.

    Thanks for your advice.


  5. After debugging, I traced the problem to the Py_Finalize inside the procedure TPythonEngine.Finalize.

    Calling Py_Finalize will freeze the program.

    And   Py_Finalize                 := Import('Py_Finalize'); so, the problem is within the dll.

     

    If I skip calling Py_Finalize, there will be a small memory leak of 89 - 104 bytes of Unknown x 1


  6. Have you found the solution?

    I seem to have found the solution.  I created the pythonengine and pythonmodule etc in a background thread

            procedure TQuoteThread._CreatePython(TheNil: TObject);
            begin
              RichEdit1 := TMemo.Create(nil);

              PythonGUIInputOutput := TPythonGUIInputOutput.Create(nil);
              PythonGUIInputOutput.UnicodeIO := true;
              PythonGUIInputOutput.Output := RichEdit1;

              modDBFireDac := TPythonModule.Create(nil);
              modDBFireDac.OnInitialization := modDBFireDacInitialization;
              modDBFireDac.ModuleName := 'DBFireDac';

              PyDelphiWrapper := TPyDelphiWrapper.Create(nil);

              PythonEngine := TPythonEngine.Create(nil); // 4.17
              PythonEngine.IO := PythonGUIInputOutput;

              modDBFireDac.Engine := PythonEngine;
              PyDelphiWrapper.Engine := PythonEngine;

              PythonEngine.LoadDll;

     

                pyObj := PyDelphiWrapper.Wrap(self); // 4.15
                with GetPythonEngine do
                begin
                  // Define a new variable "T" in the DB module
                  //4.37 modDBFireDac.SetVar('MainForm', pyObj);
                  modDBFireDac.SetVar('BackgroundThread', pyObj); //4.37
                  Py_XDecRef(pyObj);
                  // Excecute the script
                  ExecStrings(aLines);
                end;                                

            end;
                     

     

    Then in the python script, it assigned the delphi thread to a python object

          delphithread = DBFireDac.BackgroundThread
    

    When I need to pass output to Delphi, from within python script, I simply call the delphi thread method

       delphithread.AddLine(text)
    

    In Delphi, the Delphi Thread method use TThread.ForceQueue to call a Form Method which add the output text to a TStringList

    procedure TQuoteThread.AddLine(TheLine: String);
    var
      aObj: TStringObj;
    begin
      if (TheLine <> '') and Assigned(UIEvent_PrintLine) then
      begin
        TThread.ForceQueue(nil,
          procedure
          begin
            aObj := TStringObj.CreateWith(TheLine);
            UIEvent_PrintLine(aObj);
            FreeAndNil(aObj);
          end, 1);


      end;
    end;

    • Thanks 1

  7. I seem to have successfully created PythonEngine inside a thread:

              RichEdit1 := TMemo.Create(nil);

              PythonGUIInputOutput := TPythonGUIInputOutput.Create(nil);
              PythonGUIInputOutput.UnicodeIO := true;
              PythonGUIInputOutput.Output := RichEdit1;

              modDBFireDac := TPythonModule.Create(nil);
              modDBFireDac.OnInitialization := modDBFireDacInitialization;
              modDBFireDac.ModuleName := 'DBFireDac';

              PyDelphiWrapper := TPyDelphiWrapper.Create(nil);

              PythonEngine := TPythonEngine.Create(nil); // 4.17
              PythonEngine.IO := PythonGUIInputOutput;

              modDBFireDac.Engine := PythonEngine;
              PyDelphiWrapper.Engine := PythonEngine;

              PythonEngine.LoadDll;
              
    However, when I tried to unload and free the pythonengine inside the same background thread later, it hanged at PythonEngine.Free:
              FreeAndNil(PyDelphiWrapper);
              FreeAndNil(modDBFireDac);
              FreeAndNil(PythonGUIInputOutput);
              FreeAndNil(RichEdit1);
              if PythonEngine <> nil then begin
                 PythonEngine.UnloadDll;
                 PythonEngine.Free;//  program hanged here!!!!
                 PythonEngine := nil;
              end;
              
    If I don't PythonEngine.Free, Delphi will report memory leak.
    What should I do?

     


  8. Since I need to run Python4Delphi in a separate thread. I first try to modify demo01 of Python4Delphi to  create TPythonEngine and TPythonGUIInputOutput at run time instead of design time.

    procedure TForm1.FormCreate(Sender: TObject);
    begin


      PythonGUIInputOutput1:= TPythonGUIInputOutput.Create(self);
      PythonGUIInputOutput1.Name := 'PythonGUIInputOutput1';
      PythonGUIInputOutput1.Output := Memo2;

      PythonEngine1 := TPythonEngine.Create(self);
      PythonEngine1.Name := 'PythonEngine1';
      PythonEngine1.IO := PythonGUIInputOutput1;
    end;

     

    However, when I run the demo01.exe now, it pops up the error "Python is not properly initialized"!!!

     

    How do fix it?

    My eventual goal is to create TPythonEngine , TPythonGUIInputOutput and other python4delphi components in a separate thread at run time, so as to make python run in its own thread.

    Please kindly help.

     


  9. Python4Delphi demo33 (the multi-thread example) (https://blogs.embarcadero.com/learn-how-to-stop-a-thread-inside-python-in-a-delphi-windows-app/) is not working under Delphi 11.1 and Python 3.10.5 (64-bit).  When debugged, the function TThreadSortForm.SortModule_GetValue( pself, args : PPyObject ) : PPyObject; cdecl;
     throws the exception : "OverflowError: Python int too large to convert to C long".    
    I don't understand why as the values of arrays are very small ( below 170).

     

    Please help.  I need to call Python in multithread.

×