TMSSoftware.com is offering an inside look into the coming version of FNC UI in form of a Beta version for all registered customers.
After presenting a Ribbon component with version 2.0 — i.e. you can use the same component in VCL, FMX, LCL for all targets that Delphi offers — the next version will introduce a Table View control that became famous with iOS. A table view is the basis for any listing of values with hierarchical navigation in iOS. Having the same component available in desktop environments as well, will increase usability of your applications immensely.
Have a look at my detailed tutorial for the new component that will be part of FNC UI 2.1:
This is one of the topics that sadly shows up mostly at run-time when you already deployed the app to your customers.
We all have our development machine. Our application works just fine. And then we deploy to the customer and the customer says that he gets an error that “12,5 is not a valid float value”.
Why is it
12,5 you wonder… on your system it is always
12.5 and works just fine.
Well, different regions different ways to write a number. In Europe most countries use “,” (comma) as a decimal separator and “.” as a thousand separator. In the United States of America it is exactly vice versa.
It gets even more complicated if you have to read a number from a string that is produced by a device that always formats numbers a certain way no matter what and you have to make sure that your application is able to interpret these numbers.
There is always lots of information on the web when it comes to Delphi and its functions. In order to convert a string to a float value you use
StrToFloat . Sadly, most of the information is outdated. Recent versions of Delphi use an approach that has been established by Java and .NET and has found its way into the Delphi RTL.
Here’s how Delphi tries to parse a string into a float: Delphi uses the local regional settings of the user profile the application runs in. This means if your application runs on a US-based system without any individual changes the decimal separator most likely will be “.”. If your application is run on a system in Germany, Delphi will use “,” as a decimal separator.
How you say what Delphi shall use: Let me just start with this. I have seen so many strange things to solvet his issue, it made me dizzy sometimes. There’s people rewriting registry settings to get it done and trying to load different regional configurations using the Win API… the sky seems to be the limit.
However, the solution is so easy if you have a look at the different fingerprints of the
There is the option to specify a setting of type
TFormatSettings as the second parameter for the parse operation. And that is already the solution.
TFormatSettings is a record that is designed to hold regional settings of all sorts. Date and Time formats, day names, number formats — all you need.
And if you look at the source….
/// This is a candidate to be removed or left to store the Locale that created the FormatSettings.
/// Creates a TFormatSettings record with current default values provided
…you even get information what different methods can be used to fill the record with data.
If you know that your external device will deliver measurement data in US format all the time, i.e. with ‘.’ as a decimal separator and you want to make sure that Delphi knows it you need to create TFormatSettings either with a US-locale or you can also create one based on your system and set the delimiter manually. You have the option.
Here we create the record for US settings:
LFormat is of type
TFormatSettings . Mind that it does not have to be released as it is a record and not an object instance; even though the method is called create it is not a constructor that is called.
Alternatively, you can say:
So, whenever you encounter a string that has “12.5” as a number it will be able to parse that number no matter on what system your application runs.
Once you know that you have
TFormatSettings at your disposal it becomes really easy.
I already posted about how easy it is to add markers to a map using
TMSWebGMaps in a VCL Forms Application. However, the documentation is rather slim on how to focus the map on all the markers added. You might find the method
MapZoomTo sooner or later. This method expects the bounds to be specified and for that you may use
Map.Markers.Bounds which will yield the bounds encompassing all the markers that have been added to the map.
The approach is very logical and — as always — if you know which method and propery to use it makes very much sense and it is easy to remember. Just finding it for the first time is always a challenge.
Looking at the following code snippet that iterates over a data set and adds exactly one marker for every record, we can also see the call to
MapZoomTo at the end. Accoding to the documentation and also to what I just wrote, this should work:
To be blunt: Depending on the internet connection available it won’t work. Especially if you make the call to
MapZoomTo right after the start of the application, the call will lead to nothing. It will simply be ignored by the Google API. You always have to remember that any call to the WebGMaps framework will lead to some sort of interaction with the Google API sooner or later. If that API is not able to receive the call or has not processed all the previous calls, the call will be ignored and not queued.
The solution is again rather simple, but you need to know the fact that the map control has to be ready to be zoomed or panned. It is ready right after the download has completed. Thus, we can use the event called
OnMapDownloadDidFinish would have been a much better name) of the map control:
The instance to
Map and also
Map.Markers.Bounds can be called at any time after the markers have been added. As the map is owned by the form, this requires no additional variables etc. Putting the call to zoom into the event makes certain that the control is ready.
In order to not miss these things, TMS offers a FAQ for all their components. You can find the FAQ for the VCL mapping component here. Furthermore, you also find a solution how to zoom in on all the markers.
Finally, be sure to subscribe to their newsletter. It contains valuable technical information for all products and is released frequently.
As mentioned, I am in the process of preparing a video tutorial about FNC controls. The next video will be about TTMSFNCGrid, a bindable and datasource capable datagrid that will behave the same way in any framework and any platform.
The amount of properties, methods and events is immense and thus you can only get to know the control by using it in your projects. One of these projects involved dislaying additional information for the user that is based on the columns displayed in the grid.
I will simplify my actual example as such:
In the grid we allow the user to enter a start date and an end date for a project in the first two columns of each row. The third column will display the number of days between these dates. Pretty simple task, but no grid in this would has predefined calculations like this.
We have several approaches in Delphi. One approach would be to create an TFDMemTable with two fields and an additional calculated field for the number of days. This dataset can then be bound to the grid.
However, this is a simple example and for a real-life project we might not want to change our datasets for a visual finesse.
Thus, we simply want to use the grid control to display that info for us, but we are not interested in persisting this information or use it anywhere else.
After having created a VCL Forms Application I dropped a TTMSFNCGrid on the form and defined the number of Columns (
ColumnCount ) and Rows (
RowCount ) using their respective properties. I also set
1 . Set
In order to add rows, I add a button of type
The form should look something like this:
You might add anchors and other eye candy as you please.
Next, we have to allow for the user to add rows to the grid. For this, we need to implement the GridCanAppendRow-event:
Pretty simple, as we want to allow a row to be added without any restrictions. Of course, you could limit the number of total rows by stating:
This will allow for 20 user-rows to be added. In case you ever add a footer you need to consider that row as well.
The button does the actual adding of the row:
// append a row
Unlike the VCL a change of rows does not delete the content of the grid. The FNC grid is pretty smart and notices that you simply want to add a row and keeps the data in place.
If you ran the example right now, you would already be able to enter data and add rows. However, there is absolutely no user comfort entering the data. Also the difference in days is not being calculated.
Double-click the grid and amend some properties for the columns:
We select the
etDatePicker for the columns the user enters the dates into. Furthermore, we can set
true for the calculated column.
In order for the user to be able to navigate the grid nicely we set some additional keyboard options. We want to the user be able to press enter to go to the next column and add a row in case the last column of the row has been reached. Furthermore, we want the user to be able to use Tab to navigate between the columns:
For this we have the properties
Grid.Keyboard.TabKeyHandling as seen in the screenshot above.
The only thing missing is the calculation. The grid offers the event