Jump to content

Anders Melander

  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by Anders Melander

  1. Anders Melander

    Do you need an ARM64 compiler for Windows?

    Sure, but that's hardly worth USD 600/year. Most of the stuff on that list is just repackaging of their existing features. Pfft!
  2. Anders Melander

    Are the jcl and jvcl libraries still alive?

    Fork the repository. Create a branch on your fork. Apply the changes to your branch. Push the changes to your fork. Create a pull request to have your branch merged into the original repository.
  3. Anders Melander

    High DPI & anchoring in Delphi 11

    Do you have AutoSize=True on the labels?
  4. Anders Melander

    Package SynEdit library as Dll

    You can create a run-time package containing synedit (a run-time package is a DLL) and link against that but one way or the other you are going to create a dependency on synedit and compiling it directly into your project is the the option that will give you the least problems.
  5. Not very shocking if you understood what was going on. When you install a component your code will be run as a part of the IDE process. If your component code goes into an endless loop then you will have hung the IDE. Nothing surprising there. So is Delphi. I'm assuming you're a hobbyist because otherwise VS isn't free AFAIK.
  6. No you don't. I understand why you used it but there are always better ways to solve a problem than using [weak]. Contrary to what the documentation states [weak] isn't named named after the type of reference. It's named after the design skills of people who choose to use it to manage references. ­čÖé
  7. Anders Melander

    Format source with tabs

    P.S. Tabs are Evil!
  8. Anders Melander

    Interfaces - Time to face my ignorance.

    Why? What problem are you trying to solve? While I'm definitely a proponent of interfaces at a higher level, at low level they often just obfuscate the code. Apart from that I think your solution has a number of "smells": Why is the TDrawingObject´╗┐.ObjectType writable? Does the ObjectType really need to change after construction? Why is TDrawingObject´╗┐.DrawingObjectsList writable? Who owns the list? (might have been covered before. TL;DR) Instead of exposing the whole TObjectList<> class, expose only the relevant parts (Add, Remove, Enumerator). See: Why is TDrawingObjectsList.OwnsObjects part of the API? Isn't the ownership an implementation detail?
  9. So evidently there's another problem with your code. You can start by showing us the call stack (click the Details button).
  10. 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;
  11. Anders Melander

    Looking for small (vector) drawing component/library

    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 ­čÖé
  12. Anders Melander

    Looking for small (vector) drawing component/library

    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_Obj´╗┐ects 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.
  13. Anders Melander

    NT API components

    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
  14. 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?
  15. 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!
  16. 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.
  17. Better Translation Manager https://bitbucket.org/anders_melander/better-translation-manager The Better Translation Manager (BTM) is a replacement for the Delphi Translation Manager a.k.a. the Integrated Translation Environment (ITE) and External Translation Manager (ETM). Why is it better? Well, for one thing, it's free but more important; It actually works - unlike the ITE/ETM. Why? The standard Translation Manager that ships with Delphi today was originally an individual product known as the Borland Translation Suite. With Delphi 5 it became a part of the enterprise edition. The Borland Translation Suite showed great promise but unfortunately it never evolved from its roots as an external tool and has always been hampered by severe bugs that made it completely unusable in practice. As a result nobody uses it. This can be witnessed by the plethora of homegrown and commercial alternatives. The great benefit of the standard translation system is that it just works (this is the system itself I'm talking about, not the tools. The tools suck). Apart from the requirement that you must use resourcestrings you don't need to do anything special when writing your code. At run time you just place the compiled resource modules in the same folder as your application and the Delphi Run Time Library automatically takes care of loading and using the translations based on the current Windows user interface language. Anyway, since Embarcadero has now finally admitted that they are never going to fix the Delphi Translation Manager and instead recommend that we find alternative solutions, I decided that it was time I solved this little problem once and for all. The core functionality of the Better Translation Manager was written in two weeks during my summer vacation in Italy 2019. Amazing what you can do with a little pasta! Features Does not require any changes to the source code of the application being translated. Works with the existing standard Delphi localization system. Translates resourcestrings and all strings in forms regardless of any 3rd party components used. Works on compiled application. Source code is never used. Generates localized binary resource modules (resource DLLs). Does not use an external compiler. Can import existing translations from compiled application and resource modules or from XLIFF localization source files (dfn, rcn files). Read and save TMX and TBX translation memory files. Import Translation Memory from TMX (Translation Memory eXchange), TBX (TermBase eXchange), Microsoft Glossary and CSV. Machine Translation using Translation Memory, Microsoft Translation Service or Microsoft Terminology Service. Forms, Components, Types and Values that should be ignored can be specified in a Stop List. Translations are Spell Checked. Validation Rules to catch common translation mistakes. Supports Right To Left (RTL) editing based on translation language. Translation project is stored in a single XML file. Command line interface for use in automated build systems. Fast! Refreshing a large project typically takes less than a second vs. many minutes with the ITE/ETM. Supports all Unicode versions of Delphi (i.e. Delphi 9 and later). Resource modules contain the version resource of the source application. What it doesn't do There's one task that BTM, by design, doesn't attempt to solve: Localizing the placement and size of controls. Since it has been my experience that it is a far better idea to design the user interface in such a way that the layout automatically accommodates changes in font- and text size and shorter/longer texts due to translation, I decided from the start that I would not be supporting localization of size and position of controls. This also relieved me of having to create a run time form designer, supporting 3rd party controls visually (something that nobody so far has managed to find a foolproof solution to) and deciding what individual properties constitutes size/position values. Instead I just localize all string values - and only string values. But wait... There's More! Yup, you not only get this little wonder for free. You get the full source code too. Grab it at the repository linked at top. More details at the repository. Enjoy / Anders Melander
  18. 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).
  19. 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.
  20. Anders Melander

    Developer Express gave up on FMX

    I think they will relocate FYI:
  21. 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!
  22. 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.
  23. 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.
  24. 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.