The idea of this article is to help you to control both how the data is displayed
in and what the user can type in a data-aware component by using EditMask,
DisplayFormat, the OnGetText and OnSetText event handlers.
To expose it i will use as an example a TDBGrid, but this you can apply to any db
visual component.
Let's consider a TDBGrid displaying only 3 fields:
- AName: string;
- MyTime : TDateTime;
- AltDate : TDateTime;
what they are for is of no interest for us now. But let's consider we want
following:
1) Name has to be written and displayed only in uppercase
2) MyTime has to be written and displayed in format 'hh:nn', and ignore the date
contained in the TDateTime.
3) AltDate has to be written and displayed in format ddmmm (like for example 01Jan
for the 1st January) Not only that, but the month has to be written and displayed
in uppercase and it can be only a date between January and April. Tricky, isn't it?
OK, let's see each case:
CASE 1) Seems quite easy. You could use a mask of the style
'!>llllllllllllllllll'
where > theoretically forces the characters behind it to be uppercase and 'l'
permits but not requires a alphabetical character in its place.
But that forces you to establish a max length of the name. What if you want it to
have as many as 255 characters? You'd need to assign a mask with 255 'l'. Besides,
the '>' does not always work well...
An alternative would be to use the OnSetText event handler. This event fires
whenever the user tries to set the Text property in a TField. You can actually use
it to change the text that will be passed to the TField. Like this:
1 procedure TForm1.UppercaseSetText(Sender: TField; const Text: string);
2 begin
3 Sender.AsString := UpperCase(Text);
4 end;
5
6 //Of course you have to assign the event handler like this:
7
8 DBGrid1.Fields[0].OnSetText := UpperCaseSetText; //where Fields[0] is AName
CASE 2) in this case you've got a TDateTime to be displayed and written as 'hh:nn'
How to do it? A TField has an EditMask, but not a DisplayFormat. You need to cast
it to a TDateTimeField, which actually has it. Then you could assign both like this:
9 TDateTimeField(DBGridSeries.Fields[1]).DisplayFormat:= 'hh:nn';
10 TDateTimeField(DBGridSeries.Fields[1]).EditMask := '!00:00'; //where Fields[1] is
11 MyTime
CASE 3) Finally we got to the real tricky case.
For this we'll need some support functions which i will show but won't discuss
here. These are following:
12 function DateToFormatDDMMM(date: TDateTime): string; //for example
13 converts 01-01-2005 to 01JAN
14 function FormatDDMMMToDate(date: string): TDateTime; //for example converts 01JAN
15 to 01-01-yyyy where year //is not important right now but could be
16 calculated
17
18 {Then you could use OnGetText to force the field to display it the way you want. As
19 you are using it, you don't need DisplayFormat. In this case, perhaps we could have
20 used it to obtain a similar result, but without uppercase.}
21
22 procedure TForm1.DDMMMGetText(Sender: TField; var Text: string; DisplayText:
23 Boolean);
24 begin
25 Text := UpperCase(DateToFormatDDMMM(Sender.AsDateTime));
26 end;
27
28 {Using OnSetText again combined with EditMask, you could force the user to write
29 only a date in format ddmmm with the month being between January and April, like
30 this:}
31
32 procedure TForm1.DDMMMSetText(Sender: TField; const Text: string);
33 var
34 auxDate: TDateTime;
35 Month : word;
36 begin
37 auxDate := FormatDDMMMToDate(Text);
38 Month := MonthOf(auxDate); //returns a number between 1 and 12 representing the
39 month of the year
40 if Month < 5 then
41 Sender.AsDateTime := auxDate
42 else
43 Sender.Clear; //if it does not match then for example we apply the value null
44 end;
The EditMask would look like '!00LLL', where 0 means you need to put a number there and L means you need to put a alphabetical character in it
|