-
Content Count
920 -
Joined
-
Last visited
-
Days Won
56
Everything posted by pyscripter
-
create delphi4python at run time, extend demo sample 34
pyscripter replied to FranzB's topic in Python4Delphi
Regarding numpy on Linux if you use the default python 3 installation it would suffice to install numpy via pip: pip3 install numpy -
Just in case you have not seen it SamplingProfiler 64 – test version - DelphiTools, I mentioned earlier the updated instrumenting profiler ase379/gpprofile2017: Gpprof with unicode support and new features. (github.com). Between the two you can get the job done, but I admit being able to use VTune (also free) would be great.
-
The PythonVersions unit is of little value in Linux, where there is no Registry and no registered Python versions. You need to manually provide the DLLName and DLLPath. You can use some code that searches possible file locations. For example in the Mac you can do, something like: {$ifdef MACOS} for N:= 5 to 9 do begin S:= Format('/Library/Frameworks/Python.framework/Versions/3.%d/lib/libpython3.%d.dylib', [N, N]); if FileExists(S) then exit(S); end; {$endif} In Debian Linux you can search for file locations such as: /usr/lib/x86_64-linux-gnu/libpython3.7m.so /usr/lib/x86_64-linux-gnu/libpython3.7m.so.1 /usr/lib/x86_64-linux-gnu/libpython3.7m.so.1.0 but it may vary by python distribution.
-
Xdata Rest server request & Python4Delphi
pyscripter replied to J. Robroeks's topic in Python4Delphi
None of the python code is blocking other threads. But the following functions are blocking: PyGILState_Ensure PyEval_RestoreThread In other words you need to get and hold to the GIL to execute any python code. So take for example sleep. It works like windows sleep. But to let other threads to execute python code you need to use Py_Begin_Allow_Threads /Py_End_Allow_Threads before/after the sleep. Python deals with the threads it creates. (threading module). -
Delphi 10.4.2 is advertised to be "Remote desktop friendly". Does anyone know what it takes to make Delphi applications remote desktop friendly?
-
Xdata Rest server request & Python4Delphi
pyscripter replied to J. Robroeks's topic in Python4Delphi
In your code above you should destroy PY_SUBJECT before releasing the GIL Python has a lesser known feature called sub-interpreters, which allows you to use the interpreter from a clean state. This is what emNewInterpreter does. Normally I would not bother with that. The pattern you need to follow using the latest version of P4D: In your main thread to release the GIL after loading the Python dll: TPythonThread.Py_Begin_Allow_Threads (calls PyEval_SaveThread) In your Delphi threads including the main thread (or if you use ITask or TParallel) that execute python code (this is what TPythonThread does): fGILState := .PyGILState_Ensure; try Do python staff finally PyGILState_Release(fGILState); end; In your main thread before unlolading Python TPythonThread.Py_End_Allow_Threads (calls PyEval_RestoreThread) if you have a long running thread that does python stuff and you want allow other threads to do python stuff as well then the pattern is: fGILState := .PyGILState_Ensure; try Do python staff TPythonThread.Begin_Allow_Threads; try Other threads can run python code finally TPythonThread.End_ALlow_Threads; end; Do more python stuff. finally PyGILState_Release(fGILState); end; In PyScripter I have a utility function: type IPyEngineAndGIL = interface function GetPyEngine: TPythonEngine; function GetThreadState: PPyThreadState; property PythonEngine: TPythonEngine read GetPyEngine; property ThreadState: PPyThreadState read GetThreadState; end; function SafePyEngine: IPyEngineAndGIL; begin Result := TPyEngineAndGIL.Create end; type TPyEngineAndGIL = class(TInterfacedObject, IPyEngineAndGIL) fPythonEngine: TPythonEngine; fThreadState: PPyThreadState; fGILState: PyGILstate_STATE; private function GetPyEngine: TPythonEngine; function GetThreadState: PPyThreadState; public constructor Create; destructor Destroy; override; end; { TPyEngineAndGIL } constructor TPyEngineAndGIL.Create; begin inherited Create; fPythonEngine := GetPythonEngine; fGILState := fPythonEngine.PyGILState_Ensure; fThreadState := fPythonEngine.PyThreadState_Get; end; destructor TPyEngineAndGIL.Destroy; begin fPythonEngine.PyGILState_Release(fGILState); inherited; end; function TPyEngineAndGIL.GetPyEngine: TPythonEngine; begin Result := fPythonEngine; end; function TPyEngineAndGIL.GetThreadState: PPyThreadState; begin Result := fThreadState; end; which is used in the main or other threads as: var Py: IPyEngineAndGIL; begin Py := SafePyEngine; Py.Engine. whenever I need to execute Python code -
What we now need is a bug report at Embarcadero, with a detailed description of the issue reproduction steps and the potential fixes. @balabuevAre you planning to submit one?
-
Code queued with ForceQueue is executed in the main thread with the same mechanism as Thread.Synchronize and not with PostMessage.
-
@Fr0sT.BrutalSure, you could also optimize DoubleBuffering (if you do use DoubleBuffering). But @Stephen Ball's fix addresses crashes that may occur during connection and disconnection, not the general slowness in painting.
-
I guess the issue would still be present if you now replace the ListView with anything that has scrollbars including a treeview. Is that right?
-
How about this one? class procedure TStyleEngine.DoRemoveControl(Control: TWinControl); begin if not (csDestroying in Control.ComponentState) and (FControls <> nil) and FControls.ContainsKey(Control) then begin var Hook := FControls.Items[Control]; TThread.ForceQueue(nil, procedure begin Hook.Free; end); FControls.Remove(Control); end; end; There may be more efficient solutions, such as adding the hooks for deletion to a List and process that list on idle time or on Hook creation.
-
In light of @David Heffernan remarks here is a shorter version of @Stephen Ball code: type TForm1 = class(TForm) procedure CreateWnd; override; procedure WMWTSSessionChange (var Message: TMessage); message WM_WTSSESSION_CHANGE ; procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY; private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.WMDestroy(var Message: TWMDestroy); begin inherited; WTSUnRegisterSessionNotification(Handle); end; procedure TForm1.WMWTSSessionChange(var Message: TMessage); begin case Message.wParam of WTS_SESSION_LOCK, WTS_REMOTE_DISCONNECT: Application.UpdateMetricSettings := False; WTS_REMOTE_CONNECT, WTS_SESSION_UNLOCK: TThread.ForceQueue(nil, procedure begin Application.UpdateMetricSettings := True; end, 30000); end; end; procedure TForm1.CreateWnd; begin inherited; WTSRegisterSessionNotification(Handle, NOTIFY_FOR_THIS_SESSION); end; Instead of CreateWnd you could override the CreateWindowHandle method.
-
See DestroyWnd not called at destruction of WinControls - VCL - Delphi-PRAXiS [en]
-
Thanks! DestroyWnd is not called when the application exits. Is this an issue here? You could call the WTSUnRegisterSessionNotification at the WM_DESTROY handler instead.
-
@Stephen BallThank you very much! Is there a need to have a separate window to receive the notifications? Isn't the code below equivalent to yours? type TForm1 = class(TForm) procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); procedure WMWTSSessionChange (var Message: TMessage); message WM_WTSSESSION_CHANGE ; private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormDestroy(Sender: TObject); begin WTSUnRegisterSessionNotification(Handle); end; procedure TForm1.WMWTSSessionChange(var Message: TMessage); begin inherited; case Message.wParam of WTS_SESSION_LOCK, WTS_REMOTE_DISCONNECT: Application.UpdateMetricSettings := False; WTS_REMOTE_CONNECT, WTS_SESSION_UNLOCK: TThread.ForceQueue(nil, procedure begin Application.UpdateMetricSettings := True; end, 30000); end; end; procedure TForm1.FormCreate(Sender: TObject); begin WTSRegisterSessionNotification(Handle, NOTIFY_FOR_THIS_SESSION); end;
-
This is not true. StyleEngine.Destroys calls FreeControlHooks which destroys all remaining hooks. However what @Attila Kovacs suggests is problematic, since you keep accumulating unreleased hooks if the application creates and destroys styled controls.
-
Could you tell us how?
-
I did a bit of research to assess whether other parts of Vcl could be suffering from the same issue. The only controls that recreate themselves in response to the CM_STYLECHANGED message are the TListView and the ActionManager controls (ActionToolbar etc.). I think there are not scrollbars and the like there, but I wonder why there is a need to do that. So the issue may be confined to the ListView and if the call to RecreateWnd can be avoided that would be the simplest solution.
-
Update: This does not work well. One suggestion I have is the following: Change TStyleEngine.DoRemoveControl(Control: TWinControl) from: class procedure TStyleEngine.DoRemoveControl(Control: TWinControl); var I: Integer; LControl: TControl; begin if (FControls <> nil) and FControls.ContainsKey(Control) then begin for I := 0 to Control.ControlCount - 1 do begin LControl := Control.Controls[I]; if LControl is TWinControl then DoRemoveControl(TWinControl(LControl)); end; FControls.Items[Control].Free; FControls.Remove(Control); end; end; to class procedure TStyleEngine.DoRemoveControl(Control: TWinControl); var I: Integer; LControl: TControl; begin if not (csRecreating in Control.ControlState) and (FControls <> nil) and FControls.ContainsKey(Control) then begin for I := 0 to Control.ControlCount - 1 do begin LControl := Control.Controls[I]; if LControl is TWinControl then DoRemoveControl(TWinControl(LControl)); end; FControls.Items[Control].Free; FControls.Remove(Control); end; end; or even to: class procedure TStyleEngine.DoRemoveControl(Control: TWinControl); begin if not (csRecreating in Control.ControlState) and (FControls <> nil) and FControls.ContainsKey(Control) then begin FControls.Items[Control].Free; FControls.Remove(Control); end; end; There seems to be no reason to destroy the hook if the control is recreating. Also hooks of child controls would be removed when they get destroyed, so there is no need to do this in advance. Do you see anything wrong with the above? With the above change the test app runs fine and without memory leaks. And the change would save a lot of hook destruction and reconstruction. To test copy Vcl.Styles.pas, StyleAPI.inc and StyleUtils.inc to the project source directory, make the change and re-build the project.
-
We now understand the cause of this issue. Great work @balabuev. But now we need to come up with a good fix to propose to Embarcadero. My earlier question "Shouldn't the ListView TScrollWindows be above the ListView after it gets recreated?" still stands. If the order was not messed up, the error would not occur. Or can the recursive calling of DestroyWindow window be avoided without introducing other bugs? Although in the case of the ListView the RecreateWnd as a response ot CM_STYLECHANGED the call to RecreateWnd appears to be redundant, RecreateWnd happens often with many controls and for all sort of reasons (e.g. a property change). So Vcl should be able to handle such calls robustly.
-
You need to update to 10.4.1 or better to 10.4.2.
-
Shouldn't the ListView TScrollWindows be above the ListView after it gets recreated? This is what happens when it is originally created Why are they not on top? By the way readers of this thread may be interested in a related old post of mine:
-
Although Vcl.Styles is not mature. I would say it is usable. The Delphi IDE is a proof of that. I have been producing PyScripter with Vcl.Styles for the last five years, and I had no issues that could not be overcome. And now you can have per monitor aware, styled Delphi applications. And since this this discussion started about flicker, there are ways of working around that. The Delphi IDE and PyScripter have minimal flicker. The great thing about Vcl is that applications developed almost 20 years ago, can still work well and look modern, just by recompiling pretty much the same old code. I have mentioned this before, just compare to the Microsoft Desktop application landscape. A new framework is introduced every 3-4 years, mostly incompatible with the others: - Visual Basic with ActiveX controls - C++ with Windows API - WinForms - WPF - Silverlight - Xamarin - UWP - WinUI - MAUI - Project Reunion - etc. Where would you be if you invested in Visual Basic and ActiveX controls for example? Ironically, you can still use ActiveX controls in Delphi if you so wish.
-
See python4delphi/Tutorials/Webinar II at master · pyscripter/python4delphi (github.com) Both video and source code.
-
Looking forward to reading it!