Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 03/01/23 in all areas

  1. Lars Fosdal

    D 11.3 Word occurrences marking - colour setting

    @Vandrovnik - Tools | Options | User Interface | Editor - Don't highlight keywords - is checked by default. Also, Highlight words setting offers None, When selected, By cursor. I prefer By cursor.
  2. Lars Fosdal

    Delphi 11.3 is available now!

    I have the new version in a VM until I am satisfied that it won't cause me problems. Only then do I upgrade my "production enviroments".
  3. Vandrovnik

    D 11.3 Word occurrences marking - colour setting

    Thank you! I completly missed this! (It applies even to .sql files, where I would like to highlight NULL, etc.)
  4. Dalija Prasnikar

    Delphi 11.1 with TidThreadComponent and TThread.Synchronize

    This can also be easily solved if you either disable timer while you are updating UI and enable it back when you are finished. Alternative solution is adding some boolean flag and simply skipping UI update if previous update is still running.
  5. Lars Fosdal

    Delphi 11.1 with TidThreadComponent and TThread.Synchronize

    Not if you use a thread safe queue and the access to the data that needs to be updated are protected with f.x. a critical section, or you only access data that you know will not be touched by other threads. Lets say you have a 500ms timer. If you have activities on the TCPClient that receive data every 50 ms - the UI would still only refresh only every 500 ms The only time you would get an issue with performance in the UI, is if the render takes longer than the timer - but you would not lose any data - and assuming the render contains all the most recent data - it would all be displayed, albeit at your fixed timer frequency. In most cases, throttling the UI updates to refresh less often than the actual data refresh-rate will not be an issue. If your TCPClient thread consumes all your CPU - you have a very different problem. The only way it would be a problem, is if you use UI elements as data storage, instead of having an underlying structure as you should. Divide and conquer. Separate your UI from your business logic.
  6. David Heffernan

    Delphi 11.3 is available now!

    I need to do work before I can do that. It's really frustrating that I cannot have 11.2 and 11.3 installed on the same machine.
  7. Dalija Prasnikar

    Stack Overflow error

    You get this error because you are trying to open project from recent files which links directly to .dproj file. If you open it through File -> Open and open .dpr then dproj will be recreated. Anyway, deleting dproj file, while it can help in certain scenarios is not the best course of action, especially for cross-platform FMX projects as you will lose all custom setup required for those projects, but that depends on how complicated your setup is. If your dproj file is corrupted in some way and it cannot be loaded, then creating brand new project with same name and configuring it from scratch, is better option as autogenerating can cause you other troubles down the road because auto-generation does not properly configure and add all platforms.
  8. Lars Fosdal

    Delphi 11.1 with TidThreadComponent and TThread.Synchronize

    I really REALLY dislike Synchronize. It is a pitfall of pitfalls. IMO, a better approach is: In your thread, send a signal when there is something that needs to be refreshed. That signal can be a queue, and you may want to include info about the type of content change if the UI should do a selective refresh Decide how often the UI should refresh and make a timer in the UI that checks the queue if something should be refreshed You still need to protect access to elements shared by the UI thread and the background threads - but at least you will have FULL control over what the UI draws and when.
  9. Glenn Dufke

    Delphi 11.3 is available now!

    To fix the incorrectly positioned toolbar, do the following: Close the IDE Open registry editor Navigate to HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\22.0 Delete the Toolbar node Start the IDE again and it is now reset to default position and scaling.
  10. I've attached a pretty old unit with numerous functions for managing semi-transparent VCL.Graphics.TBitmap controls. However, unless your graphics needs are minimal, I strongly recommend you consider using an open source graphics library. Two graphics libraries for Delphi I can recommend: Graphics32: Multiple developers contributed over the last 20yrs and is widely used. Image32: Recently developed by me. IMHO it's a lot simpler than Graphics32 while almost as fully featured. AlphaBitmaps.pas
  11. Brian Evans

    A gem from the past (Goto)

    If the code still makes sense to you years latter and you can follow it without difficulty then there should be no complaints. Applying a rule or guideline too rigidly before the skill or knowledge to do so has been acquired often makes things worse. In your example learning how to use continue; or break; to control the flow of a for loop would be best but applying a no goto rule and using multiple cascading IF's around a large blocks of code could be worse than just using a goto. The top hall of shame code I have ever seen was due to developers rigidly applying rules before the skill and knowledge to do so was acquired. It made the code more complex and a lot harder to follow to the point is was often easier to just re-write it from scratch.
  12. Remy Lebeau

    Problem closing forms..

    Show() is non-blocking, so your example would reach myForm.Free() before the Form's window is actually shown to the user. It is perfectly safe to use caFree with a modal Form. The Form object remains alive until after ShowModal() exits and control returns to the main message loop, THEN the Form is destroyed. If you want to get results from the Form, you just have to do so immediately after ShowModal() exits, which is the best time to get the results anyway. If you need the results at a later time, save them somewhere that you can get them back when needed. So, you would either: -auto-create a Form and then Show()/Hide() it when needed. Let the TApplication handle destroying the Form during app shutdown. - Create() and Show() the Form, then Free() it when you don't need it anymore, or use OnClose to caFree it. - Create() and ShowModal() the Form, and then Free() it (directly or via caFree) after ShowModal() has exited.
  13. Anders Melander

    Problem closing forms..

    Indeed. Here's the Delphi 1 version: destructor TComponent.Destroy; begin Destroying; DestroyComponents; if FOwner <> nil then FOwner.RemoveComponent(Self); DisposeStr(FName); end; It's been a while since I looked through the Delphi 1 sources. Classes.pas is only 3916 lines long. It's just sooo cute
  14. Remy Lebeau

    Problem closing forms..

    If it is owned, it is destroyed when its Owner is destroyed. Otherwise, it is leaked and not destroyed at all. When the process exits, the OS will reclaim the leaked memory. Using Action=caFree in the OnClose event is the correct way to do that. Whether or not the Form has an Owner is irrelevant. An owned object can be destroyed at any time, even before its Owner is destroyed. If the object is destroyed first, it will simply remove itself from its Owner so that that Owner does not try to destroy it again.
  15. Remy Lebeau

    Problem closing forms..

    Setting Action=caFree in the OnClose event is a DEFERRED destruction. It does not free the Form right away, it postpones the actual destruction until control flow returns to the calling thread's message loop, THEN the Form is freed when it is safe to do so (ie, no other messages are being processed). So it doesn't matter if the Form is owned or not. If the Form is owned, and the Owner destroys the Form before the caFree request is processed, then the request will simply get ignored since there is nothing to Free anymore.
  16. Minimalist implementation of SmartPointers based on a old post by Barry Kelly comparable to the Spring4D one in performance. type TObjectHandle<T: class> = class(TInterfacedObject, TFunc<T>) private FValue: T; public constructor Create(AValue: T); destructor Destroy; override; function Invoke: T; end; TSmartPointer = record class function Make<T: class>(AValue: T): TFunc<T>; static; end; constructor TObjectHandle<T>.Create(AValue: T); begin FValue := AValue; end; destructor TObjectHandle<T>.Destroy; begin FValue.Free; end; function TObjectHandle<T>.Invoke: T; begin Result := FValue; end; { TSmartPointer } class function TSmartPointer.Make<T>(AValue: T): TFunc<T>; begin Result := TObjectHandle<T>.Create(AValue); end; Used as in: var Bob := TSmartPointer.Make(TTalking.Create('Bob'))(); or var Bob := TSmartPointer.Make(TTalking.Create('Bob'));
  17. His legacy lives on through people like me using his code...
  18. Heh, I actually donated that SafeGuard code to JCL many years ago. They modified the name a little, but not the concept. It works, but I am not sure if all guarded objects will be released on an exception. You'll have to test that. The advantage is indeed that you don't have to cast or anything. You use the original object you created. Yesterday, I even wrote a better approach, using records an implicit and explict casts. That one is certain to work and does not need a cast and the pointer can be used as if it were the actual object (by implicit cast). type IObjectGuard<T: class> = interface function Value: T; end; TObjectGuard<T: class> = class(TInterfacedObject, IObjectGuard<T>) private FValue: T; public constructor Create(Obj: T); destructor Destroy; override; function Value: T; end; SmartPtr<T: class> = record private FGuard: IObjectGuard<T>; public class operator Explicit(const Obj: T): SmartPtr<T>; class operator Implicit(const Ptr: SmartPtr<T>): T; end; { TObjectGuard<T> } constructor TObjectGuard<T>.Create(Obj: T); begin FValue := Obj; end; destructor TObjectGuard<T>.Destroy; begin FValue.Free; inherited; end; function TObjectGuard<T>.Value: T; begin Result := FValue; end; { SmartPtr<T> } class operator SmartPtr<T>.Explicit(const Obj: T): SmartPtr<T>; begin Result.FGuard := TObjectGuard<T>.Create(Obj); end; class operator SmartPtr<T>.Implicit(const Ptr: SmartPtr<T>): T; begin if Ptr.FGuard <> nil then Result := Ptr.FGuard.Value else Result := nil; end; And it can be used like: var Bob, Fred, Jack: TTalking; begin Bob := SmartPtr<TTalking>(TTalking.Create('Bob')); Fred := SmartPtr<TTalking>(TTalking.Create('Fred')); Jack := SmartPtr<TTalking>(TTalking.Create('Jack')); Fred.Talk; Bob.Talk; raise Exception.Create('Error Message'); Jack.Talk; Writeln('This is the end of the routine'); end; As you can see, this also creates guards. They do work, even with the Exception. All are freed when the exception occurs.
  19. Why not directly make it `using` and replace the `begin` `end` with `{ }` ? :)
  20. I ran a test in Rio and it works quite well: type TTestObj = class public constructor Create; destructor Destroy; override; end; constructor TTestObj.Create; begin inherited Create; Writeln('TTestObj.Create'); end; destructor TTestObj.Destroy; begin Writeln('TTestObj.Destroy'); inherited; end; procedure Test; begin Writeln('Test started'); begin var obj := Shared.Make(TTestObj.Create)(); Writeln('obj = ', obj.ClassName); Writeln('End of nested scope'); end; Writeln('Test completed'); end; Output: Test started TTestObj.Create obj = TTestObj End of nested scope Test completed TTestObj.Destroy Inline var object is not destroyed at the end of scope, but at the end of the method. Still, that's something I more or less expected. Other than that, the code works fine. For the record, this can also be achieved with the "traditional" syntax. Delphi will kindly keep the interface alive until the end of the method: procedure Test; var obj: TTestObj; begin Writeln('Test started'); obj := Shared.Make(TTestObj.Create)(); Writeln('obj = ', obj.ClassName); Writeln('Test completed'); end; And there's also a bit slower but shorter variation to create a shared object: Shared<TTestObj>.Make() Just saying 😉
  21. @pyscripter You don't need a temp variable at all: procedure MeasureSpring; var i: Integer; begin with Shared.Make(TStringList.Create)() do for i := 1 to ADD_COUNT do Add(i.ToString); end; Just ... with ... brrrr, terrible. This may also work (didn't test): procedure MeasureSpring; begin // something ... begin var s := Shared.Make(TStringList.Create)(); for var i := 1 to ADD_COUNT do s.Add(i.ToString); end; // something ... end; I would really like Embarcadero to enhance `with` block in that direction, so I could write: procedure MeasureSpring; begin with var s := Shared.Make(TStringList.Create)() do for var i := 1 to ADD_COUNT do s.Add(i.ToString); end; This should compile to the same code as my second example. (Except that at the moment it is not support.)
  22. As pointed out In another post by @Primož Gabrijelčič, in Delphi Rio you can just write: var s := Shared.Make(TStringList.Create); What an amazing hack Shared is! Also impressive type inference from Delphi.
  23. The ISafeGuard approach is not a smartpointer but creating a scope to some resource. There is a important difference: a smart pointer combines the resource and its lifetime management into one entity. Also the record based approach is the most naive one - while Spring4D offers this one as well it has a more advanced one. As for performance: measure it yourself: program MeasureIt; {$APPTYPE CONSOLE} uses Spring, Diagnostics, Classes, SysUtils, JclSysUtils; const ADD_COUNT = 10; CREATE_COUNT = 100000; procedure MeasureSpring; var s: IShared<TStringList>; i: Integer; begin s := Shared.Make(TStringList.Create); for i := 1 to ADD_COUNT do s.Add(i.ToString); end; procedure MeasureJcl; var s: TStringList; g: ISafeGuard; i: Integer; begin s := TStringList.Create; Guard(s, g); for i := 1 to ADD_COUNT do s.Add(i.ToString); end; procedure MeasureClassic; var s: TStringList; i: Integer; begin s := TStringList.Create; try for i := 1 to ADD_COUNT do s.Add(i.ToString); finally s.Free; end; end; procedure Main; var sw: TStopwatch; i: Integer; begin sw := TStopwatch.StartNew; for i := 1 to CREATE_COUNT do MeasureSpring; Writeln(sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for i := 1 to CREATE_COUNT do MeasureJcl; Writeln(sw.ElapsedMilliseconds); sw := TStopwatch.StartNew; for i := 1 to CREATE_COUNT do MeasureClassic; Writeln(sw.ElapsedMilliseconds); end; begin Main; Readln; end. The implementation in Spring 1.2.2 (currently released version) uses very optimized code for the smart pointer itself avoiding the overhead of an object allocation and all the code associated with it but only allocates a 12 Byte (32bit) block with the IMT. Since IShared<T> is not a regular interface but an anonymous method you can directly access the members of the underlying type. Yes, there is a method call every time but as you can measure that does not cause any significant overhead (unless you call .Add a million times). And even then the actual work being performed totally outweighs the smart pointer overhead
×