On February 14th Delphi will be 18. Looking back it sure came a long way from version 1. I remember when I first walked into a Compusa store and bought my first copy of Delphi. I was beside myself with excitement. Moving from Turbo Pascal to Delphi, moving from DOS to Windows development. That was a very challenging and interesting time indeed.
I am proud of have been a part (as a developer) of that journey. Being a Delphi developer wasn’t always easy. But I am very happy I stuck to my conviction that this is the best tool to develop in and didn’t stray away from it.
Exciting times are ahead, as exciting as picking up my very own copy of Delphi 1. I say that because the future looks very promising and exciting. Cross-platform is here and mobile development are just around the corner.
What better time to be a Delphi developer? I can proudly answer, now!
So raise your glasses and salute our dev tool! Happy Birthday and many more returns!
And thank you to all the people that made a positive difference in making Delphi what it is today!
In response to a QC report I wrote early last year I decided to implement a LoopCount property on the TFloatAnimation component.
Report No: 105140 Status: Open
Add a LoopCount property to the TAnimation class
TJSCustomLoopCountFloatAnimation = class(TFloatAnimation)
TAnimationLoopEvent = reference to procedure (Sender: TObject; const LoopNumber: Integer; var Cancel: Boolean);
procedure FirstFrame; override;
procedure DoLoop(var ACancel: Boolean); virtual;
procedure ProcessAnimation; override;
constructor Create(AOwner: TComponent); override;
property LoopCount: Integer read FLoopCount write FLoopCount default 3;
property OnLoop: TAnimationLoopEvent read FOnLoop write FOnLoop;
Nothing that interesting in the new descendant. New property called LoopCount to control the number of loops and a new event that gets triggered each time a loop completes.
The published component publishes the new property and event but also changes the default values for two existing properties. It makes sense to set Loop to true when the new class is for enhancing the looping ability and if you’re looping, generally AutoReverse will be set to true.
TJSLoopCountFloatAnimation = class(TJSCustomLoopCountFloatAnimation)
property AutoReverse default True;
property Loop default True;
I won’t post all of the code here because you can download from the link provided below, just a couple of snippets.
We need to override the FirstFrame method to initialise a couple of variables we use.
Checking to see if the LoopCount property is valid (raise an exception if it isn’t)
Initialise the variable to zero that counts the interactions
Make sure we are going to be checking the animation process for loops
Most of the work occurs in the overridden ProcessAnimation method.
if FCheckingLooping then
LType := LCtx.GetType(Self.ClassInfo);
if Assigned(LType) then
LField := LType.GetField('FTime');
if LField <> nil then
if LField.GetValue(Self).AsExtended = 0 then
LCancel := False;
if FLoopsComplete > 1 then
// The first time through, FTime is 0 so we need to offset this by
// adding 1 when checking for completion
if LCancel or (FLoopsComplete = LoopCount + 1) then
LField := LType.GetField('FRunning');
if LField <> nil then
Thanks to extended RTTI we can access a couple of private fields that we need to determine if a loop has been completed. This occurs when the FTime variable is zero. There is one issue with using this value and that is that the first “Loop” should be ignored since the first time ProcessAnimation is called FTime is zero so by the logic used, a loop has completed. This is why the DoLoop method is only called if the FLoopsComplete variable is greater than one.
Naturally it is possible to handle this one-off situation differently using a “First Time Through” variable but under the circumstances, I decided to go with the solution in place.
Once the LoopsComplete value is one greater than the LoopCount (refer to the above two paragraphs if you’ve already forgotten about why) the private field FRunning is set to False. Setting FRunning to false, stops the animation immediately.
Why not just call the public Stop method instead of going to the trouble of setting a private field? The answer to that is found in the ProcessTick method of the animation control (incidently, why isn’t this method virtual?).
ProcessAnimation; // <==== We set FRunning to false here
if not FRunning then
if Assigned(AniThread) then
By setting FRunning to false within our ProcessAnimation override, we are avoiding another frame being processed before the animation is stopped. This is because the Stop method calls ProcessAnimation and DoProcess as well.
You can download the component and a cheesy demo application from the link provided. There is no package for the component to install it into your IDE, this is left as an exercise for the reader :-).
Loop Animation Demo (short video – 39KB)
Download LoopCount Component and Demo
NOTE: Before downloading the source code you must agree to the license displayed below.
This space intentionally left blank…
When I read Marco Cantu's Post titled "Embarcadero Buys AnyDAC" I began to worry.Where I work we spent a great deal of time converting from the BDE to dbExpress. Granted we did it faster than we thought it would take, it's not something I am ready to do again. Having to switch from dbExpress to another Database Layer was really not going to be an option for us. So I spent some time really reading the documentation on AnyDAC.From what I have read this has turned from worry to exciting news, with a one thing that may need to be done.First off let me address my worry about dbExpress. AnyDAC is a library that can sit on top of dbExpress, ODBC or it's own drivers. AnyDAC can connect to dbExpress driver through a TADPhysTDBXDriverLink component.What is lacking that would need to developed. (Maybe already done since I have no code to look at yet, and I am just reading docs)Ability to have a TSQLConnection use an existing TADConnection class or vice versa.I basically think it would be great if AnyDAC existing connection could become an dbExpress Driver.I know enough about the dbExpress framework to know this is something that would be very possible to do. In the long run this would also allow Embarcadero to only have to support one set of drivers and not one for dbExpress and one for AnyDAC. If Embarcadero does something stupid and don't do this and just stop maintaining dbExpress Drivers without providing a bridge then I would have to stop upgrading Delphi versions, but I really don't see that happening. This would allow existing dbExpress applications to start using AnyDAC without having to have two connections to the database. Then I started looking at the features of AnyDAC and found several that are really appealing. Although I don't have a BDE application, I know several still doExisting BDE Applications have a Detailed Guide on conversion to AnyDac. With a step by step coverage on converting BDE Applications.BDE needs to go away, this really looks like a really good option for those applications.I primarily use Oracle but we also use Sybase, SQL Server, My SQL, SQLite and DB2. All have good support with AnyDAC with many other Databases supported.Sometimes I have to basically join results from two different databases. It usually results in some pretty ugly code. AnyDAC helps solve this problem by supporting Local SQL which allows you to execute SQL queries against any TDataSet descendants as the data source. Oracle Support includes support for more data types than the existing dbExpress Driver. TADMemTable is faster than TClientDataSet there was old blog entry on the comparison of speed between memory based datasets and show the difference for the various operations. Good support for low level trace/logging of what is going on at the API level.Currently has 100% of the source available I am hoping Embarcadero keeps that up. It's a big complaint of mine when it comes to dbExpress.Live Data Window Mode, appears to be something that could really help us with some performance on some of our search screens.Array DML, appears it may help us speed up some of our batch operations such as file importing.In addition I noticed that AnyDAC really has a good cross platform story. Which might be a huge thing for the Mobile editions of Delphi. Granted I think that connecting directly to a remote database via a mobile application is a security risk.Overall I think this will be a good thing, depending on the decisions made by Embarcadero that have yet to be made.
I am pleased to announce the cities and dates for this year's Delphi Developer Days tour. We will be in Chicago May 6th and 7th, Frankfurt on May 30th and 31st, and Amsterdam on June 3rd and 4th.Delphi Developer Days are intense, two-day events that blend the in-depth coverage of formal training with the atmosphere and networking opportunities of a small conference. Joining with me in offering this year's tour is renowned Delphi expert Bob Swart (Dr. Bob). Bob is an Embarcadero MVP, winner of the coveted Spirit of Delphi award, as well as a developer, consultant, and author. His skills and Delphi knowledge make him uniquely qualified to replace my previous Delphi Developer Days partner, Marco Cantù, who became the Delphi Product Manager this past fall. Delphi Developer Days includes joint sessions, presented by both Bob and me, as well as simultaneous tracks, where Bob and I break out into separate rooms to present focused topics. Like past Delphi Developer Days tours, we will be covering many of Delphi's newest features as well as topics that apply to older versions of Delphi. This year's offerings include database development, mobile applications, SOAP (Simple Object Access Protocol) and REST (REpresentational State Transfer), DataSnap, Windows services, debugging, migrating to FireMonkey, and the always popular Tips and Tricks session. Additional sessions cover threads and thread synchronization, browser-based clients, as well as gestures and touch. For a full list this year's sessions, visit www.DelphiDeveloperDays.com. Also making a return is the popular Delphi Developer Days course book. This extensive manual includes papers written by Bob and me and covers all of our Delphi Developer Day sessions. This means that while you'll have to select which talk to attend when Bob and I break out into our separate sessions, you will still receive the material, including source code, from all of our talks. Past year course books have run hundreds of pages in length, and have included more content than most books on software development. We expect this year's course book to be no different, and Bob and I are in currently in the process of writing it. In addition to our sessions, Delphi Developer Days includes a keynote presentation from an Embarcadero representative, and well as a different guest speaker in each city. We also include open Q&A sessions each day where you can ask questions about any Delphi-related topics. We also have a raffle at the close of the second day where you have an opportunity to win valuable prizes contributed by our many sponsors. All of our Delphi Developer Days 2013 locations are easy to get to. Our Chicago event is close to Chicago's O'Hare airport, and the hotel offers a free shuttle bus to and from that airport. Our Amsterdam location is across the street from Amsterdam's Central Station, and our Frankfurt location is one and a half kilometers (one mile) from Frankfurt's main train station (Frankfurt am Main Hauptbahnhof), from which you can take a taxi. There is also a city bus that runs from the train station and stops right in front of the hotel. Hotel locations, travel details, and more are available at www.DelphiDeveloperDays.com. Seating is limited to 42 attendees in each city. These limits ensure that attendees get an opportunity to interact with me and Bob, as well as network with each other. However, we sold out a number of cities last year, and anticipate that this will happen again this year. As a result, you should register early in order to ensure your spot in the city of your choice. You can also earn a discount if you register early. There are additional discounts for previous Delphi Developer Days attendees, as well as for companies that register three or more employees.Bob and I, as well as Delphi Developer Days coordinator Loy Anderson, are very excited about this year's tour. We think we've put together an exceptional program, and we hope to see you there. For more information, and to register, please visit www.DelphiDeveloperDays.com.
I recently had to localize a FireMonkey application and for that I aimed to use the TLang component. With TLang you can define a collection of native strings to be localized and the corresponding translations to a particular language. To my surprise the component was allowing to store a maximum of 17 translations for the whole application. So, what about the other strings that need localization?It seems there’s a regression issue from Delphi XE2 to Delphi XE3 that is preventing TLang to store more than 17 translations. You can even find an entry for this in Embarcadero Quality Central, for which no workaround or fix has been provided up to this date.I found a programmatic workaround for this issue. Basically, the native strings and the translations could be loaded from text files in which each line will have the form:NativeString1=Translation1NativeString2=Translation2NativeString3=Translation3…………NativeStringN=TranslationNYou will need one file containing the native strings and the translations per language. These files can contain as many lines as you which (certainly more than 17). In order to load those files into an existing TLang component you can use the function below:procedure LoadTranslationsFromFile(aLangCode: string; aFileName: string; aLang: TLang);var Translations: TStrings;begin if (aLangCode <> '') and (FileExists(aFileName)) and (Assigned(aLang)) then begin Translations:= TStringList.Create; Translations.LoadFromFile(aFileName); aLang.Resources.AddObject(aLangCode, Translations); end;end;For an example of how to use such function see below:procedure TForm1.Button1Click(Sender: TObject);begin LoadTranslationsFromFile('ES', 'C:\Temp\Lang_Test_ES.txt', Lang1); LoadTranslationsFromFile('EN', 'C:\Temp\Lang_Test_EN.txt', Lang1);end; Hopefully this bug will be fixed in the near future; but meanwhile you can use this workaround to handle more than 17 translations with the TLang component.CodeProject
Currently in the Delphi XE3 release there is a bug in the OnExit processing of TMemo and TEdit (possibly others) controls.
If you make a change in a TEdit or TMemo control and then exit the control, after the OnExit event is called, another OnChange event is called. This shouldn’t happen.
This doesn’t occur in the VCL framework and shouldn’t happen in FireMonkey.
The fix for the TEdit cause is pretty simple. Since the FNeedChange field in TCustomEdit is protected we can use a class cracker to fix it. You could put the fix into either a new control or in either an OnExit or OnChange handler in your application.
TEditClass = class(TEdit);
procedure Form1.OnExit(Sender: TObject);
TEditClass(Edit1).FNeedChange := False;
It’s interesting to note for TEdit, FNeedChange is protected. This is because in the TCustomEditBox descendant (used by TSpinBox and TNumberBox controls), the FNeedChange field is set to False after the overriden Change method is called. Perhaps this should have triggered the developer making that change, to actually fix the issue in the ancester class.
The fix for TMemo is more interesting because unlike the TCustomEdit class, FNeedChange is private. Thankfully extended RTTI comes into play.
I put this code where the memo content was saved to disk, you could put the code in the same spot in your applications (if applicable), or place it in either OnChange or OnExit events.
// save your memo contents
LInst := LCtx.GetType(Memo1.ClassType).AsInstance;
LField := LInst.GetField('FNeedChange');
if LField <> nil then
If your save is triggered by the user selecting a control that takes focus from the memo, the OnExit event will trigger before executing the fix above. Under these circumstances, moving the fix to the OnExit event of the memo is advised.
Another TMemo Issue
The OnChange event is only triggered after typing two characters in a TMemo, the first character typed into the memo doesn’t trigger the OnChange event.