Jump to content

Dalija Prasnikar

  • Content Count

  • Joined

  • Last visited

  • Days Won


Dalija Prasnikar last won the day on July 19

Dalija Prasnikar had the most liked content!

Community Reputation

735 Excellent


Technical Information

  • Delphi-Version
    Delphi 10.4 Sydney

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Dalija Prasnikar

    TListView filled by Thread = Freeze

    Maybe this has been source of trouble in the past, but TThread destructor terminates thread and waits for it at least since Delphi 7. Under some circumstances code might require explicit termination and waiting before calling destructor. For instance if destructor is overridden and can destroy fields that are used by the thread, but if the order of destruction is important, I would still prefer code that handles proper shutdown sequence inside such overridden TThread class than handling it from the outside code. When it is handled from the outside there is always greater possibility that someone will forget to explicitly terminate and wait.
  2. Dalija Prasnikar

    TListView filled by Thread = Freeze

    Animation is not working because thread is doing very little work besides queuing work to the main thread. This gives very little chance to the main thread to do anything besides processing the queued work and repaint animation. This is matter of timing so it is not surprising that you have different behavior on different platforms. You can either use ProcessMessages to force main thread message processing and repainting the animation, or you can put thread to sleep for short period of time. However, sleeping will slow down the whole process, so you don't want to call it at every iteration. Following code works without issues. There are some additional notes, some already mentioned by @Remy Lebeau First, I have changed StopThread procedure to just call FreeAndNil(FMyThread) - freeing the thread will also call Terminate and WaitFor - this is why it causes the deadlock is you are using Synchronize. Niling the thread is there so you can click the button again otherwise you would leak the thread. If the thread is already running you will not be able to start the thread again, but you will be able to do so after the first thread is finished. NotifyComplete procedure will also call StopThread to release the thread because it makes no sense to keep dead thread around. Calling TThread.Queue(TThread.CurrentThread will discard any queued events after the thread is dead. In this example it is important to do so, because form is closing any we don't want to run any already queued events after form is released as this would cause AV. If there is something that needs to be always executed then such code should be in OnTerminate event. When it comes to anonymous method variable capture, they will be captured and their lifetime will be extended, but that only means variable will be accessible, but does not guarantee that the content (object) will be alive, you can only safely use variables of value types and managed types. For others, you need to be sure that they will be alive as long as anonymous method is running. In this case ListView1 and Button2 will not be alive when the form is closed. procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin StopThread; end; procedure TForm1.StopThread; begin FreeAndNil(FMyThread); end; procedure TForm1.NotifyComplete; begin AniIndicator1.Visible := False; AniIndicator1.Enabled := False; ListView1.EndUpdate; ListView1.Enabled := true; StopThread; end; procedure TForm1.Button2Click(Sender: TObject); begin if Assigned(FMyThread) then Exit; AniIndicator1.Visible := True; AniIndicator1.Enabled := True; ListView1.Enabled:=false; ListView1.BeginUpdate; FMyThread:=TThread.CreateAnonymousThread(procedure () var I: Integer; Total: Integer; begin Total := 0; for I := 1 to MaxValue do begin TThread.Queue(TThread.CurrentThread, procedure () begin ListView1.Items.Add.Text := 'Th: ' + I.ToString; Button2.text:= i.tostring; end); if Application.Terminated then begin break; end else begin if i mod 10 = 0 then Sleep(1); end; end; TThread.Queue(TThread.CurrentThread, procedure() begin ListView1.Items.Add.Text := 'Thread: ' + Total.ToString; NotifyComplete; end); end); FMyThread.FreeOnTerminate := False; FMyThread.Start; end;
  3. Dalija Prasnikar

    TListView filled by Thread = Freeze

    You have problems because you are not changing your original code with just replacing Synchronize with Queue. In previous code you had Synchronize inside loop and now you have loop inside Queue. Go back to your original code and just use Queue instead of Synchronize.
  4. Dalija Prasnikar

    TListView filled by Thread = Freeze

    Now you have completely removed threads. I meant like this: in places where you are calling TThread.Synchronize you should use TThread.Queue FMyThread:=TThread.CreateAnonymousThread(procedure () begin ... TThread.Queue(TThread.CurrentThread, procedure () begin ... end); ... end; TThread.Queue(TThread.CurrentThread, procedure () begin ... end); end);
  5. Dalija Prasnikar

    TListView filled by Thread = Freeze

    You have a deadlock. Waiting for background thread in main thread that uses Synchronize is recipe for disaster. Namely, when you start waiting you are blocking main thread until thread is finished, but when thread encounters Synchronize it will try to execute that code in the context of the main thread, but since main thread is on hold at that time Synchronize will never be able to run and finish. You should use TThread.Queue instead.
  6. Dalija Prasnikar

    AllocHwnd + TTimer = lag?

    Processing messages for whole application happens in one place. WM_TIMER is low priority message and it will be dispatched only after all higher priority messages are dispatched. The fact that WM_TIMER messages are not being processed fast enough means that you application is either flooded with messages or is doing to much work in main thread, including code called with TThread.Synchronize and TThread.Queue. Changing from TPanel to TObject with allocated handle should not have any impact on processing speed. Also using WM_TIMER for progress is usually poor approach, it is better that you send status from the thread when you have some significant change to show. Additionally, if you are sending messages from OnTerminate event then you don't need to wait on thread (also freeing the thread will also wait). It is hard to say more without having reproducible example.
  7. 1. You add your own icons of appropriate sizes 2. Yes, you add additional icons in Project > deployment 3. Modifying manifest.xml is probably not even needed. AFAIK only difference between Android Studio manifest and Delphi manifest is in android:RoundIcon declaration and as far as I know round icon is not mandatory. However, you can also add that one just in case. Problem with Android is that there is plethora of devices with customized OS-es and some may require round icon for better UX.
  8. There is no need to uncheck those. Actually, those are still needed for supporting older Androids (unless you set minimum API to 26) Procedure would be - fill all icons you can through Project > Options > Application > Icons, then only add additional icons that cannot be set through Delphi. There is open issue requesting support for adaptive icons https://quality.embarcadero.com/browse/RSP-21335 and I attached zip with default icons resources created by Android Studio new project template. This makes it easier to see which icons need to be added manually and how they should look like.
  9. Dalija Prasnikar

    Delphi compatibility with Windows 11?

    Windows XP, Vista and Windows 7 had round corners... I guess that will not be an issue 😃
  10. Dalija Prasnikar

    Delphi compatibility with Windows 11?

    Define compatibility... Delphi applications work, IDE works... MS has good track record in providing backward compatibility for existing applications. Minor tweaking to embrace new OS features are always possible. You can find more information here: https://blogs.embarcadero.com/windows-11-a-beautiful-meteor-will-wipe-out-the-dinosaurs/
  11. You need to create vector icons (adaptive icons), and you will need to add those additional files to deployment manually. You can find more about icons formats and deployment folders at https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive
  12. Dalija Prasnikar

    Binary size, how-to make it smaller?

    Because enhanced RTTI is now turned on for RTL/VCL with rather poor default (and of course, FMX, but FMX was never without it) and that RTTI prevents removing unused things with linker. So any class you touch or is touched by other code, will be almost completely included in executable. Unused classes are not included. Default visibility for methods is public and published, for fields private, protected, public, published and for properties public, published. There is also WEAKLINKRTTI directive, that enables linker to eliminate unused symbols with RTTI, but it is not turned on in core Delphi frameworks. http://docwiki.embarcadero.com/RADStudio/Sydney/en/WEAKLINKRTTI_directive_(Delphi)
  13. Dalija Prasnikar

    When will be binding to Swift libraries possible ?

    If the Swift framework does not support any explicit interop, it could be possibly wrapped and consumed through Objective-C library that can then be imported in Delphi https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c If you need support for Swift frameworks now, this sounds like most viable option.
  14. Dalija Prasnikar

    When will be binding to Swift libraries possible ?

    There is QP report for that https://quality.embarcadero.com/browse/RSP-22944 When will importing Swift frameworks be available, the is only that Embarcadero can tell. From what I can see, such Swift framework would have to be compiled in interop mode and Expose its API. Delphi is capable of importing Objective-C framework, so it is possible that @objc mode would suffice. If not there is unofficial @cdecl support, for Swift side. https://forums.swift.org/t/best-way-to-call-a-swift-function-from-c/9829 This is not something I had need to explore, so this is all the information I can give.
  15. Dalija Prasnikar

    Out parameter is read before set

    It is valid alert. You need to initialize out parameters before they are used. Only managed out types will be automatically initialized. When you mark parameter as out, you are saying I will properly initialize that variable (setting to nil is also proper initialization in this context) If you don't initialize that parameter inside the method, then this is a bug and your method signature is telling a lie. If you want to initialize variables outside the method, then you should use var parameter. The fact that Delphi automatically initializes only managed out types, is just implementation detail of the compiler. In theory it is behavior that may change, most likely it will not, but out parameter is meant for output, compiler is free to discard its value in the function prologue.