Jump to content

Anders Melander

  • Content Count

  • Joined

  • Last visited

  • Days Won


Anders Melander last won the day on June 22

Anders Melander had the most liked content!

Community Reputation

1113 Excellent


Technical Information

  • Delphi-Version
    Delphi 11 Alexandria

Recent Profile Visitors

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

  1. 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?
  2. 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!
  3. Anders Melander

    2022 StackOverflow dev survey - salary results

    ...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.
  4. Anders Melander

    ANN: Better Translation Manager released

    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).
  5. Anders Melander

    Do you need an ARM64 compiler for Windows?

    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.
  6. Anders Melander

    Developer Express gave up on FMX

    I think they will relocate FYI:
  7. Anders Melander

    Do you need an ARM64 compiler for Windows?

    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!
  8. Anders Melander

    Do you need an ARM64 compiler for Windows?

    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.
  9. Anders Melander

    Left side cannot be assigned to

    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.
  10. Anders Melander

    Left side cannot be assigned to

    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.
  11. Anders Melander

    Left side cannot be assigned to

    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.
  12. Anders Melander

    Do you need an ARM64 compiler for Windows?

    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.
  13. Anders Melander

    Do you need an ARM64 compiler for Windows?

    Since Russia no longer has (legal) access to moderne computer technology I wouldn't expect much - for the next decade or so.
  14. Anders Melander

    Left side cannot be assigned to

    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?
  15. Anders Melander

    Left side cannot be assigned to

    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.