Delphi FormatFloat and Format functions - delphi

I have an application where users can set how values are displayed. The users enter a formatting string and the component uses FormatFloat to display the value.
But now we are using a new third-party component which formats values using the Format function and of course none of our user formats work as the Format & FormatFloat functions use a different syntax.
So does anyone know of a way of converting between the two? Or maybe someone has code to do it?
Thanks,
AJ

Though the format strings for FormatFloat can be more or less transformed to ones for Format, you may only get real similarity for positive values. The Format method simply doesn't offer enough flexibility to incorperate the features and fine-grained control that the format strings for the FormatFloat method offers.
For example, the FormatFloat method allows for three different formats for positive, negative and zero values. Also, the FormatFloat format strings allow for string literals, e.g. '#,##0.00;;Zero'; (which means that zero values are printed as "Zero").
To get something similar using the Format function, you yourself would need to do all the grunt work that FormatFloat is doing for you through the format string.
So, although I am as opposed to changing third party control's sources as I am opposed to changing the vcl sources, I am with David on this one: find a way to make the third party control use the FormatFloat function. Preferably through a custom descendant or through an interposer class (also known as an interceptor class), but if that fails, by all means change the third party control's source. Just make sure that you mark the changed sections properly so you can easily redo it when switching to a new version of that control.

Far and away the simplest solution will be to take the source of the 3rd party component (you should only consider using 3rd party Delphi components that come with source) and modify it to call FormatFloat rather than Format.

Related

How to implement a json decoder which doesn't convert numerics to double?

When I call json.decode on financial data returned from a server, I would like to either convert my numerics to decimal (pub.dev package) (or even leave them as strings so I can manually do that later). Everything else I would like to be converted as normal
There's a reviver callback which is passed to _parseJson(), but I can't find the implementation of this external function to study.
Update:
Looks like reviver() is too late: basic conversion has already happened by here and doubles get passed in. Is there any alternative callback that can be used?
I'd use the jsontool package (disclaimer: I wrote it, so obviously that's what I'd turn to first).
It's a low-level JSON processor which allows you (and requires you) to take control of the processing.
It has an example where it parses numbers into BigInts. You could probably adapt that to use Decimal instead.

Delphi, using numbers in edits

I was wondering if there is a component like the 'edit', but just for numbers so I can use the .value function in my code.
My textbook says I must make a program, that when the user enters a number and clicks the execute button, the results of the functions must be determined.
The functions are: Trunc, round, frac, sqr and sqrt.
I have to enter the value into, what looks like an 'edit', but whenever I use the .value in my code, it gives me an error saying :Undeclared identifier: 'value'. Although it works when I use a 'SpinEdit'.
Forgive me for being really thick, I do have a severe chest and sinus infection with a fairly bad fever, so my mind is somewhere else at the moment.
Thanks!
Oh, and by the way, I have also used the 'MaskEdit' component but it still gives me the same error
For an edit control there is no property named Value, which is what the compiler is telling your. For an edit control the property you need is Text. That's a string containing the contents of the edit control. You'll need to use StrToFloat or TryStrToFloat to convert to a real type.
You can use a masked edit if you like, and validate the input on entry. The TMaskEdit control derives from TCustomEdit, and again the property used for accessing its content is Text and of type string.
Personally I don't like that because I don't think it gives the clearest feedback to users. It's also hard to write a mask for a general floating point value. Myself, I would validate at the point where the program needs to convert from string to real.
Well, since you asked if there is an edit like component for that, I use TMS AdvEdit. It does a very decent job handling integers and floats. If you can afford it, it's really useful.
It has .FloatValue and .IntValue properties for reading and writing the value, and an EditType that specifies what kind of input is accepted.

Overriding the system Date Format

In my application I am reading from one database and writing to a second. The app is quick and dirty so I am reading / writing using AsString on both the FieldByName and ParamByName of the queries.
This works for all my use cases apart from where the data type is Date or DateTime
As far as I can tell FieldByName.AsString uses the system ShortDateTime format to return dates as (in my case) dd/mm/yyyy. The database expects the date to be written in as yyyy-mm-dd
According to Delphi Basics I should be able to set ShortDateFormat to what I need, but it appears that in XE5 this is no longer the case (correct?)
Further digging on here returns these two questions that use TFormatSettings to override the local settings. However, both of these use the resulting FormatSettings in StrToDate and FormatDateTime directly.
So two questions
1) Can I tell my application to override the System ShortDateFormat?
2) If so, How (I have a Plan B if not)?
The use of a global variable for the date and time formats was a mistake committed long ago by the original RTL designers. Functions that rely on the global format settings, like the single parameter StrToDate are retained for backwards compatibility, but you should not be using them.
For conversions between date/time and string you should:
Initialise a TFormatSettings instance with your date format.
Call the two parameter StrToDate, passing your TFormatSettings to convert from a string to a date.
Call FormatDateTime overload that accepts a TFormatSettings when converting in the other direction.
Now, to the main thrust of your question. You should not be using strings at all for your dates and times in the scenario you describe. Use AsDateTime rather than AsString. If you happen to have a database column that does store a date/time as a string, then you'll should use the TFormatSettings based conversion functions to work around that design fault.
If you are absolutely dead set on doing this all with strings, and I cannot persuade you otherwise, then you need to use FormatSettings.ShortDateFormat from SysUtils to control your short date formatting.

Delphi: compare properties between two components

I'd like to compare the "state" of two components, say Comp1: TSomeComponent and Comp2: TSomeComponent, i.e. I want to compare the values of all the published properties of the two components. Some of the properties are indexed, like the TListBox.Items property. Is there an easy way to do this? Do I have to invoke some iterating RTTI code?
An easy way would be to serialize them both with WriteComponent and compare the resulting strings. Note, however, that this would compare only published, not public, properties. But that is what you say you need, so...
Note that this would make, say, the order of the indexed properties significant. That may or may not be what you want.
Unfortunately, there's no simple compare function in Delphi as far as I know. (I've stopped at D2007.) You could add a method "Compare" to the base class and build the comparison of all fields inside this method. (It should accept one parameter of the same base class.) With D2007 you could build this as a helper class, but you still need to specify the fields.
Other classes could be inherited from this base class and override the base Compare method.
The use of RTTI will make it easier to compare fields of classes from different types but it's complex and error-prone. It will require a lot of testing with all kinds of different classes.
A trick I use (but I would like to have something like this integrated in the IDE) is to copy the dfm part related to the 2 components (using ALT+F12) to access dfm and then I paste the 2 components in NotePad++ and I use the Compare Plugin to compare the 2.
It gives a nice visual output, but this takes more time than selecting more components in the IDE (even from different windows) and then Compare them with a compare tool built in in the IDE.

Faster CompareText implementation for D2009

I'm extensively using hash map data structures in my program. I'm using a hash map implementation by Barry Kelly posted on the Codegear forums. That implementation internally uses RTL's CompareText function. Profiling made me realize that A LOT of time is spent in SysUtils CompareText function.
I had a look at the
Fastcode site
and found some faster implementations of CompareText. Unfortunately they seem not to work for D2009 and its unicode strings.
Now for the question: Is there a similar faster version that supports D2009 strings? The CompareText functions seems to be called a lot when using hash maps (at least in the implemenation I'm currently using), so little performance improvements could really make a difference. Or should the implementations presented there also work for unicode strings?
Many of the FastCode functions will probably compile and appear to work just fine in Delphi 2009, but they won't be right for all input. The ones that are implemented in assembler will fail because they assume characters are just one byte each. The ones implemented in Delphi will fare a little better, but they'll still return incorrect results sometimes because the old CompareText's notion of "case-insensitive" is based on ASCII whereas the new one should be based on Unicode. The rules for which characters are considered the same save for case are much different for Unicode from how they are for ASCII.
Andreas says in a comment below that Unicode CompareText still uses the ASCII case-comparison rules, so a number of the FastCode functions should work fine. Just look them over before using them to make sure they're not making any character-size assumptions. I seem to recall that some FastCode functions were incorporated into the Delphi RTL already. I have no idea whether CompareText was one of them.
If you're calling CompareText a lot in a hash table, then that suggests your hash table isn't doing a very good job. CompareText should only get called when the hash of the thing you're searching for designated a non-empty bucket in the hash table. From there, a hash table will often use a linear search to find the right item in the bucket, and it will call CompareText for every item during that search. I don't know whether that's how the one you're using works.
You might solve this by using a different hash function that distributes its results more evenly over the available buckets. If your buckets are already evenly filled, then you may need more buckets (and then make sure the hash function still distributes evenly over that number as well).
If the hash-map class you're using is based on TBucketList, then there is room for improvement in the bucket storage. That class doesn't calculate a hash on the entire input. It uses the input only to determine the bucket to use. If the class would also keep track of the full hash computed for a string, then comparisons during the linear search could go much faster. Just compare the hashes, and only compare the strings when the hashes match completely. (For a 256-bucket bucket-list, the largest supported size, only one byte of the input determines the bucket, and the rest of the bytes are ignored.) I've written about TBucketList here before.

Resources