Teknisk artikel

TDateTimePicker-format i Delphi 5: DateTime_SetFormat

TDateTimePicker fik en Format-egenskab et sted mellem Delphi 5 og Delphi 6. Den nøjagtige versionsgrænse er sjældent dokumenteret på en måde, du kan stole på, og når du rammer den, fortæller compileren dig simpelthen, at identifikatoren ikke findes. Den linje, der kompilerer og fungerer på enhver nyere Delphi, du har, fejler stille eller direkte på den gamle, afhængigt af hvordan projektet er struktureret

Den underliggende kontrol er Windows DATETIMEPICK_CLASS fælles kontrol fra comctl32.dll, og den har altid accepteret en formatstreng via DTM_SETFORMAT-meddelelsen. Delphis VCL indpakker den meddelelse i Format-egenskaben i nyere versioner. I Delphi 5 sender du selv meddelelsen via DateTime_SetFormat-makro-wrapperen erklæret i CommCtrl

Det betingede kompileringsmønster

Standardtilgangen er en compilerbetinget blok knyttet til et versionssymbol. Delphi 5 definerer VER130; du kan teste mod det direkte eller definere dit eget D5-symbol i projektindstillingerne for at gøre grenetiketten mere læsbar på tværs af kodebasen. Uanset hvad kalder Delphi 5-grenen DateTime_SetFormat med kontrolhåndtaget; hver anden gren tildeler egenskaben:

{$IFDEF D5}
  DateTime_SetFormat(DateTimePicker1.Handle, PChar('MM/dd/yyyy'));
{$ELSE}
  DateTimePicker1.Format := 'MM/dd/yyyy';
{$ENDIF}

Tilføj CommCtrl til uses-klausulen for den enhed, der indeholder Delphi 5-grenen. Der er ingen grund til at tilføje den ubetinget; hvis du foretrækker at holde afhængigheden afgrænset, skal du indpakke uses-posten i den samme betingelse:

uses
  ...,
{$IFDEF D5}
  CommCtrl,
{$ENDIF}
  ...;

Syntaks for formatstreng

Formatstrengen, der sendes til DateTime_SetFormat, følger Windows' dato/klokkeslæt-vælgerformat, ikke Delphis FormatDateTime-tokens. De to ser ens ud, men kan ikke udskiftes. Windows bruger d for dag-i-måneden (intet foranstillet nul), dd for nul-udfyldt dag, M for månedsnummer, MM for nul-udfyldt måned, yy for tocifret år og yyyy for firecifret år. Tidsfelter bruger h/hh for 12-timers timer, H/HH for 24-timers, m/mm for minutter, s/ss for sekunder. Bogstavelig tekst skrives i enkelte anførselstegn inde i formatstrengen, så 'dd/MM/yyyy' er allerede korrekt, men 'dd '<literal>' MM' ville kræve indlejrede par af enkelte anførselstegn

Delphis FormatDateTime bruger derimod d/dd/ddd/dddd for dagsformer med forskellig semantik, og m for måned (ikke M). Hvis du kopierer en formatstreng fra et FormatDateTime-kald og giver den direkte til DateTime_SetFormat, vil måneds- og minut-felter sandsynligvis blive byttet om i outputtet. Skriv kontrollens formatstreng fra bunden ud fra Windows-dokumentationen i stedet for at konvertere fra et Delphi-format

Regionale indstillinger og den globale ShortDateFormat

Ændring af Delphis globale ShortDateFormat-variabel påvirker ikke en TDateTimePicker, der allerede er oprettet. Vælgeren læser regionale indstillinger fra Windows på oprettelsestidspunktet og gengiver derefter i henhold til de meddelelser, den modtager, ikke Delphi RTL-globalerne. Det betyder, at indstilling af ShortDateFormat i FormCreate ikke ændrer, hvad kontrollen viser. Du skal bruge DateTime_SetFormat (eller Format-egenskaben i nyere Delphi) for at tilsidesætte kontrollens egen formatstreng, efter at håndtaget findes

For applikationer, der implementeres internationalt, skal du teste formatstrengen på en maskine med en ikke-amerikansk regional indstilling. Windows kan tilsidesætte en tom eller nul-formatstreng med lokalitetens standard, men en eksplicit ikke-nul-streng tilsidesætter den regionale indstilling fuldstændigt. Det er normalt det, du ønsker, men det betyder, at et amerikansk centreret mønster som 'MM/dd/yyyy' vises som det er for brugere, der forventer dd/MM/yyyy af konvention. Hvis datovælgeren er brugerrettet snarere end et rent dataindtastningsfelt, kan du overveje at lade kontrollen være standard (send nil til DateTime_SetFormat), så den automatisk følger brugerens lokalitet

Genskabelse af håndtag

Formatindstillingen tilhører vindueshåndtaget, ikke noget VCL-objektfelt. Hvis kontrollens håndtag ødelægges og genskabes, hvilket VCL kan gøre, når du ændrer overordnet for en kontrol eller ændrer visse stilegenskaber på kørselstidspunktet, vender formatet tilbage til Windows-standarden. Det sikre sted at anvende DateTime_SetFormat er i en hændelseshåndtering, der kører efter oprettelse af håndtaget: tilsidesæt CreateWnd i en nedarvet klasse og kald den der, eller anvend den i OnEnter- eller OnShow-hændelsen, men først efter bekræftelse af, at håndtaget er aktivt. At indstille den én gang i FormCreate er ofte tilstrækkeligt for enkle formularer, men det er ikke pålideligt, hvis formularen foretager dynamisk stilskift eller omorganisering af kontroller

Den samme begrænsning gælder for VCL-egenskaben Format i nyere Delphi-versioner; internt kalder den den samme Windows-meddelelse og står over for den samme håndtags-livscyklus. Forskellen er, at VCL-egenskabs-setteren kontrollerer, om håndtaget er tildelt, før den kalder videre, og anvender formatet automatisk igen på CreateWnd. Det rå DateTime_SetFormat-kald har ingen sådan beskyttelse, så Delphi 5-grenen skal være mere bevidst om, hvornår det kører

Fjernelse af workaround

Når et projekt dropper Delphi 5-understøttelse, bliver den betingede blok til dødvægt. Fjern {$IFDEF D5}-grenen og den afgrænsede CommCtrl-import, og efterlad kun den direkte tildeling af Format-egenskaben. Hold fjernelsen i ét enkelt commit, så det er let at identificere, hvis noget uventet går i stykker på en compiler, du ikke testede. Selve formatstrengen forbliver den samme; kun leveringsmekanismen ændres