Tehnički članak

TDateTimePicker format u Delphiju 5: DateTime_SetFormat

TDateTimePicker je dobio Format svojstvo negdje između Delphija 5 i Delphija 6. Granica točne verzije rijetko je dokumentirana na način kojem možete vjerovati, a kada naiđete na nju, kompajler vam jednostavno kaže da identifikator (identifier) ne postoji. Linija koda koja se kompajlira i radi na svakom novijem Delphiju na starom nečujno otkazuje ili se potpuno ruši, ovisno o tome kako je projekt strukturiran

Osnovna kontrola je Windows DATETIMEPICK_CLASS zajednička kontrola (common control) iz comctl32.dll, i uvijek je prihvaćala niz za formatiranje (format string) kroz poruku DTM_SETFORMAT. VCL u Delphiju omotava tu poruku u Format svojstvo u novijim verzijama. U Delphiju 5, sami šaljete poruku putem DateTime_SetFormat makro omotača deklariranog u CommCtrl

Obrazac uvjetnog kompajliranja (conditional compilation)

Standardni pristup je uvjetni blok kompajliranja ključan na simbolu verzije. Delphi 5 definira VER130; možete testirati izravno na njemu ili definirati vlastiti D5 simbol u opcijama projekta kako biste oznaku grane učinili čitljivijom u bazi koda (codebase). U svakom slučaju, grana za Delphi 5 poziva DateTime_SetFormat s kontrolnom ručkom (control handle); svaka druga grana dodjeljuje to svojstvo:

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

Dodajte CommCtrl u klauzulu uses za jedinicu (unit) koja sadrži granu Delphija 5. Nema potrebe da ga dodajete bezuvjetno; ako više volite zadržati ovisnost u dometu, omotajte unos uses u isti uvjet:

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

Sintaksa niza za formatiranje (Format string)

Niz za formatiranje (format string) proslijeđen funkciji DateTime_SetFormat prati format Windows odabirača datuma i vremena, a ne oznake FormatDateTime iz Delphija. Ta dva formata izgledaju slično, ali nisu međusobno zamjenjivi. Windows koristi d za dan u mjesecu (bez vodeće nule), dd za dan popunjen nulom, M za broj mjeseca, MM za mjesec popunjen nulom, yy za dvoznamenkastu godinu i yyyy za četveroznamenkastu godinu. Vremenska polja koriste h/hh za 12-satni format, H/HH za 24-satni format, m/mm za minute, s/ss za sekunde. Doslovni tekst ide unutar jednostrukih navodnika unutar niza za formatiranje, tako da je 'dd/MM/yyyy' već točan, ali 'dd '<literal>' MM' bi zahtijevao ugrađene parove jednostrukih navodnika

FormatDateTime u Delphiju, za razliku od toga, koristi d/dd/ddd/dddd za oblike dana s različitom semantikom i m za mjesec (a ne M). Ako kopirate niz za formatiranje iz FormatDateTime poziva i predate ga izravno u DateTime_SetFormat, polja za mjesec i minutu će se vjerojatno zamijeniti u izlazu. Napišite niz za formatiranje kontrole iz početka prema Windows dokumentaciji, a ne pretvaranjem iz Delphi formata

Regionalne postavke i globalni ShortDateFormat

Promjena Delphijeve globalne varijable ShortDateFormat ne utječe na već stvoreni TDateTimePicker. Odabirač čita regionalne postavke iz sustava Windows u vrijeme izrade i nakon toga iscrtava u skladu s porukama koje prima, a ne s globalnim Delphi RTL-om. To znači da postavljanje ShortDateFormat u FormCreate neće promijeniti ono što kontrola prikazuje. Trebate DateTime_SetFormat (ili Format svojstvo na novijem Delphiju) za nadjačavanje vlastitog niza formata kontrole nakon što postoji ručka

Za aplikacije koje su postavljene na međunarodnoj razini (internationally), testirajte niz za formatiranje na računalu s regionalnom postavkom koja nije SAD. Windows može prebrisati prazan (blank) ili nil niz za formatiranje sa zadanom lokalnom (locale) vrijednošću, ali eksplicitni niz koji nije null u potpunosti zamjenjuje regionalnu postavku. To je obično ono što želite, ali znači da će se uzorak koji je usredotočen na SAD kao što je 'MM/dd/yyyy' pojaviti onakav kakav jest korisnicima koji konvencionalno očekuju dd/MM/yyyy. Ako je odabirač datuma okrenut prema korisniku (user-facing), a ne čisto polje za unos podataka, razmislite o tome da prepustite zadanu postavku kontrole (proslijedite nil funkciji DateTime_SetFormat) kako bi se automatski pratilo korisnikov lokalitet

Ponovno stvaranje ručke (Handle recreation)

Postavka formata pripada ručki prozora (window handle), a ne bilo kojem VCL objektnom polju. Ako je ručka kontrole uništena i ponovno kreirana, što VCL može učiniti kada premjestite kontrolu u novog roditelja (reparent) ili promijenite određena svojstva stila (style properties) tijekom izvođenja programa, format se vraća na zadani u sustavu Windows. Sigurno mjesto za primjenu DateTime_SetFormat je u rukovatelju događajima (handler) koji se pokreće nakon izrade ručke: premostite (override) CreateWnd u klasi potomka (descendant class) i pozovite je tamo, ili primijenite ju u OnEnter ili OnShow događaju tek nakon što potvrdite da je ručka aktivna. Postavljanje samo jednom u FormCreate često je dovoljno za jednostavne forme, ali nije pouzdano ako forma obavlja dinamičko prebacivanje stila ili mijenjanje roditelja kontrole

Isto ograničenje vrijedi i za VCL svojstvo Format u novijim verzijama Delphija; interno poziva istu Windows poruku i suočava se s istim životnim ciklusom ručke (handle lifecycle). Razlika je u tome što VCL postavljač svojstva (property setter) provjerava je li ručka dodijeljena (allocated) prije pozivanja i automatski ponovno primjenjuje format na CreateWnd. Sirovi DateTime_SetFormat poziv nema takvu zaštitu, stoga grana Delphi 5 treba biti pažljivija o tome kada se izvodi

Uklanjanje zaobilaznog rješenja (workaround)

Kada projekt odbaci podršku za Delphi 5, uvjetni blok postaje mrtvi teret. Uklonite {$IFDEF D5} granu i CommCtrl import koji pripada obimu, ostavljajući samo izravno pridruživanje svojstva Format. Držite uklanjanje u jednom urezivanju (commit) tako da ga je lako identificirati ako se nešto neočekivano pokvari na kompajleru koji niste testirali. Sam niz za formatiranje ostaje isti; mijenja se samo mehanizam isporuke