-
Content Count
2771 -
Joined
-
Last visited
-
Days Won
147
Everything posted by Anders Melander
-
Custom Component : onDestroy delphi creates endless error messages
Anders Melander replied to gioma's topic in VCL
So evidently there's another problem with your code. You can start by showing us the call stack (click the Details button). -
Custom Component : onDestroy delphi creates endless error messages
Anders Melander replied to gioma's topic in VCL
Don't insert tabs in your source. Don't use [weak] Use the notification mechanism built into TComponent: type TComponentA = class(TComponent, IComponentAl) private FComponentB: TComponentB; private procedure SetComponentB(const Value: TComponentB); protected procedure Notification(AComponent: TComponent; Operation: TOperation); override; published property ComponentB: TComponentB read FComponentB write SetComponentB; end; procedure TComponentA.SetComponentB(const Value: TComponentB); begin if (FComponentB <> nil) then FComponentB.RemoveFreeNotification(Self); FComponentB := Value; if (FComponentB <> nil) then FComponentB.AddFreeNotification(Self); end; procedure TComponentA.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if (AComponent = FComponentB) and (Operation = opRemove) then FComponentB := nil; end; -
Looking for small (vector) drawing component/library
Anders Melander replied to omnibrain's topic in Delphi Third-Party
https://torry.net/pages.php?id=112#939914 It probably doesn't work with the current version of Graphics32, because the GR32 polygon classes has been redesigned since it was written, but it will probably work with the version of Graphics32 available on the same page at torry.net That's correct. It's abandonware but that's not been a problem for me in the one project were it's used since it's a fairly small library and the functionality is limited. AFAIR it took me about an hours to integrate it into the application where it's used but of course I already knew Graphics32 so that helped a lot. Let me know if you want to see the source of the unit using it. To each their own - but I think I could have typed 200 lines of code in the time it has taken me to locate the library and write this message 🙂 -
Looking for small (vector) drawing component/library
Anders Melander replied to omnibrain's topic in Delphi Third-Party
Unless you're working on a 1970s vector monitor all vectors eventually ends up as raster graphics... Graphics32 has a pretty extensive (and fast) vector layer. Image32 is the same in that regard; A vector layer on top of a raster layer. I would have thought that GR32_Objects would fit the bill but it seems like the couple of hundred lines of code required to implement a complete object based vector drawing application is too large an effort. -
Looking for small (vector) drawing component/library
Anders Melander replied to omnibrain's topic in Delphi Third-Party
-
I found a copy in one of my old projects. Attached. But... Instead of using 25 year old, undocumented, and probably superseded APIs it might be a better idea to use something like WMI. There are lots of libraries that makes use of WMI easy from Delphi. This one for example: https://bitbucket.org/anders_melander/windows-management-wrappers/src/master/Source/amWindowsManagementInstrumentation.pas NTUnits100.zip NTLowLevel100.zip
-
FreeAndNil() - The Great Delphi Developer Debate
Anders Melander replied to AlexBelo's topic in Tips / Blogs / Tutorials / Videos
Law of Triviality. Every body's got an opinion about the bike shed but do we really need a video and an endless thread about it? -
Stack Overflow Developer Survey 2022 Results
Anders Melander replied to Uwe Raabe's topic in Tips / Blogs / Tutorials / Videos
On a positive note: 11,156 dreaded Python while only 797 dreaded Delphi... From that we can conclude that Python is almost 14 times more unpopular than Delphi! Woohoo! -
2022 StackOverflow dev survey - salary results
Anders Melander replied to Darian Miller's topic in Tips / Blogs / Tutorials / Videos
...and PowerShell pays 15% better than C, C++ and C#... Yeah, right - but then again, you'd have to throw really big bucks at me to get me to touch that crap. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Excellent question 🙂 First of all I would recommend that you use the TField.DisplayLabel property instead of the column Caption property unless you have a good reason not to. If you use TField.DisplayLabel then all columns that are bound to that field will automatically use that value as their caption and as a bonus you will only have to translate that value one place. The reason you're not seeing the Caption property of the TcxGrid*Column components is that the value isn't stored in the DFM and BTM can only see the properties that are stored in the DFM... Now, why isn't it stored? Well, the value has most likely been omitted from the DFM because it's the same as the FieldName. If you look at the TcxCustomGridTableItem.Caption property you will see that it has a stored directive. The stored directive controls if the property is stored in the DFM. In this case it will be stored if you have specified an explicit value and this value is different from the default value. So what is the default value? In this case the default value comes from the DisplayLabel property of the TDataSet field you have bound the column to. Again, if you haven't specified an explicit TField.DisplayLabel then the value of DefaultLabel defaults to TField.FieldName, in which case that value is also omitted from the DFM. Now you might think that the solution is to just specify an explicit Caption or DisplayLabel and that will probably work in most cases. However it will not work in the cases where this value is the same as the FieldName, because then the default rule will again cause it to be omitted from the DFM since it isn't needed. The solution is to "synthesize" the properties that have been omitted. By synthesize them I mean inject the "missing" properties into the translation project as if they were present in the DFM. If you go into the BTM settings there's an option to have BTM synthesize missing properties for you: The way it works is that when BTM reads the forms of the source application (e.g. during an Update), it runs the synthesize rules against each component that it find in the form. If a rule determines that a property is missing then a property is injected into the project with the specified name and value. I believe the above screenshot shows the default rule (preinstalled, but disabled by default): Type mask: ^T([A-Z][a-z]+)+Field$ A regular expression matching a component type. In this case the expression will match the different TField components (TIntegerField, TStringField, etc). Property name: DisplayLabel A property name. If this property is missing then it will be created in the translation project. Property value: @FieldName The value to assign the property. This can be an explicit value or the value of another property. In this case the @ specifies that we want the value of another property, namely the FieldName property. So let's say your application had a DFM with the following: ... object MyQuery: TFDQuery SQL.Strings = ('select name from users') object MyQueryUserName: TStringField FieldName = 'name' Size = 50 end end ... with the synthesize rules enabled BTM would import the above as if it looked like this: ... object MyQuery: TFDQuery SQL.Strings = ('select name from users') object MyQueryUserName: TStringField FieldName = 'name' DisplayLabel = 'name' Size = 50 end end ... Synthesized properties can be identified in the grid by their color (I believe the light green is the default - it can be customized): One thing to be aware of is that the synthesize option currently is an application level setting. This means that if you only enable it on one system and then update the project on another then the synthesized properties will be marked "Unused" which means that they will be removed if you Purge the project. I'll be fixing that "real soon now". If you run BTM in portable mode and include the portable config file in your version control (which I would recommend), then the above should not become a problem. Speaking from experience :-/ If you prefer to do the translation on the TcxGrid*Column level then you can use the following rule: Type mask: ^TcxGrid[a-zA-Z]*Column$ Property name: Caption Property value: @DataBinding.FieldName It seems there is a minor bug with adding synthesize rules so after adding the rule you should restart BTM and everything should be fine. I'll look into that. Fixed (but not yet built and uploaded). -
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
From our POW there are primarily two reason to pay maintenance on a product (any product): If you need access to the latest version regularly, the yearly subscription fee is cheaper than paying for a new license each time. Support the supplier financially so they are able to keep the product alive. Since DevExpress seems to have done "the right thing" here, we're not about to punish them for that. Yes, we can expect lower output from them for a while while they get a new team up to speed, but unless development complete stalls, for an extended period of time, we can live with that. With regard to the mentioned limit on support I think it's entirely reasonable. That was not our problem. Our problem was more pertaining to the perceived increasingly non-committal responses we got when we raised issues regarding deficiencies in the products. Now that I know the state of things it makes much better sense. -
I think they will relocate FYI:
-
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
Since I brought up DevExpress' association with Russia in this thread I think it's only fair that I share the response I just got from DevExpress on the matter. I sent the following to Julian Bucknall (DevExpress CTO) earlier today: and I just got the following response (emphasis mine) from Ray Navasarkian (DevExpress CEO): So I guess that puts that topic to rest for my part. I too would have liked a roadmap and I can't quite understand why they can't produce something, but apparently that's just the way it is. Indeed! -
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
There's a difference between someone spying on me for their own gains and someone trying to harm me just because they're angry at everybody else. I'm not that concerned about the former. -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
Some of the code I'm currently maintaining ironically has widespread use of dynamic arrays of very large records. Ironically because it was done to avoid the overhead of lists of objects in order to improve performance. Instead it now struggles with the overhead of dynamic array reallocation and records being copied back and forth. I'm slowly refactoring it to use lists and objects but meanwhile I'm using the approach you're suggesting (minus the copy/paste bug 🙂), so this: type THumongousRec = record Foo: integer; ... end; THugeArray = array of THumongousRec; TMyClass = class private FData: THugeArray; protected function GetData(Index: integer): THumongousRec; procedure SetData(Index: integer; const Value: THumongousRec); public property Data[Index: integer]: THumongousRec read GetData write SetData; end; function TMyClass.GetData(Index: integer): THumongousRec; begin Result := FData[Index]; end; procedure TMyClassSetData(Index: integer; const Value: THumongousRec); begin FData[Index] := Value; end; begin var Data := MyClass.Data[0]; Data.Foo := 1; MyClass.Data[0] := Data; end; becomes this: type THumongousRec = record Foo: integer; ... end; PHumongousRec = ^THumongousRec; THugeArray = array of THumongousRec; TMyClass = class private ...same as before... protected ...same as before... function GetPData(Index: integer): PHumongousRec; public ...same as before... property PData[Index: integer]: PHumongousRec read GetPData; end; function TMyClass.GetPData(Index: integer): PHumongousRec; begin Result := @FData[Index]; end; begin MyClass.PData[0].Foo := 1; end; Of course this only works when the property setter doesn't have side effects. -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
True, if you have to implement an interface declared by someone else - but since you don't have to actually declare the property in your implementation there's zero difference from your perspective between an interface with and one without property declarations. Anyway, to each their own, free world and all. IMO both approaches are just fine. -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
Nope: type IFoo = interface function GetBar: IBar; procedure SetBar(const Value: IBar); property Bar: IBar read GetBar write SetBar; end; TFoo = class(..., IFoo) private function GetBar: IBar; procedure SetBar(const Value: IBar); // Look ma, No property! end; begin var Foo: IFoo := TFoo.Create; var Bar := Foo.Bar; end; Sure, but I don't see the problem; Don't use them if you don't like them. You will still need the getters and setters so there's not much saved by omitting the property declaration and you lose the meta information that the property communicates. I too would wish the the getters and setters could be hidden from the public API of the interface (like I wish that the private part could be hidden from class declarations) but I guess that we have their history (as COM interfaces) to thank for that. Since I need both COM and non-COM interfaces and a new breed of interfaces would just be a mess I can live with the annoyances the versatility brings with it. -
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
Sure - And the quality of soft- and hardware from behind the Iron Curtain reflected that fact. Let's say, for the sake of argument, that you represented a professional western software company. Would you accept a dependency on a library such as DevExpress (which is far from cheap), knowing that it was produced using pirated tools on a pirated OS, by developers which may or may not have your best interests in mind? I would not. Apart from the moral and business aspects there's also one of security. I know a few Russian developers which I fully trust because I know them both professionally and socially but from what I've heard from them I can't assume that all modern, educated Russians are like that. Some of their former colleagues would be happy to see the west go up in flames. -
Do you need an ARM64 compiler for Windows?
Anders Melander replied to Lars Fosdal's topic in Cross-platform
Since Russia no longer has (legal) access to moderne computer technology I wouldn't expect much - for the next decade or so. -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
So use a function instead but I can't see how that would improve anything for you. A property better expresses the intent. For interfaces properties are purely syntactic sugar so you really don't have to use them if you prefer not to. You can just call the getters or setters directly. How is that a pain? -
Left side cannot be assigned to
Anders Melander replied to AlanScottAgain's topic in RTL and Delphi Object Pascal
Bold statement, given the fact that they were one of the language features, if not the feature, that made Delphi possible in the first place. If you need to pass them as var or out parameters then I would say that there's something wrong with your design but without a concrete example it's hard to say what. Code completion: Ditto. If you need to modify a property, which isn't writable, then there's something wrong with your design or with the class design. Many other languages doesn't have objects, interfaces, exception handling, etc. Pretty irrelevant. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Nice. I believe you can just use the FindDragTarget VCL function to find the control under the cursor. The current algorithm looks for an exact match on the control name and then iterates backward (i.e. negative row index increment) from the least property until it finds a visible property. It does not consider the Status of the property since it doesn't know what you're doing or why you want to select the item. I'd like to keep it that way. If you filter the Status column to exclude "Don't translate" then these properties will not be selected and it will behave like you want. Since you're not interested in the "Don't translate" items anyway there's no point in displaying them. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
@KHJ Fixed and new version uploaded. Thanks for the patience. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Ah... That was the missing piece. Reproduced! -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
I'm stumped. I don't believe the EXE-file is the problem because I can't reproduce with the one you sent me. Which version of Windows are you on? I know which change probably caused this. Previously, after the resource scan, I discarded modules (i.e. forms) that had no translatable items (i.e. components/properties). Now I keep them. However that doesn't explain why the modules aren't being discarded during the resource scan since they are not DFM resources. The first thing I do when I examine a RCDATA resource item is to check if the resource starts with "TPF0" which is the binary DFM signature. If the signature isn't present then the module type is set to "other" and the module is discarded. If I load your project, containing the BB modules, and then do an update the BB modules are immediately marked as missing since BTM considers these modules as not being present in the EXE (which is correct).