TDateTimePicker získal vlastnosť Format niekde medzi verziami Delphi 5 a Delphi 6. Presná hranica verzie je málokedy zdokumentovaná tak, aby sa jej dalo veriť, a keď na ňu narazíte, kompilátor vám jednoducho povie, že identifikátor neexistuje. Riadok, ktorý sa skompiluje a funguje na každom novšom Delphi, ktorý máte, na tom starom zlyhá potichu alebo úplne, v závislosti od štruktúry projektu
Základným ovládacím prvkom je spoločný ovládací prvok Windows DATETIMEPICK_CLASS z knižnice comctl32.dll, a ten vždy prijímal reťazec formátu prostredníctvom správy DTM_SETFORMAT. VCL v Delphi túto správu v novších verziách obaľuje do vlastnosti Format. V Delphi 5 posielate správu vy sami prostredníctvom makra DateTime_SetFormat deklarovaného v CommCtrl
Vzor podmieneného kompilovania
Štandardným prístupom je blok podmieneného kompilátora viazaný na symbol verzie. Delphi 5 definuje VER130; môžete ho testovať priamo, alebo definovať vlastný symbol D5 v nastaveniach projektu, aby bola značka vetvy čitateľnejšia naprieč celou bázou kódu. Nech už je to akokoľvek, vetva Delphi 5 volá DateTime_SetFormat s handlom ovládacieho prvku; každá iná vetva priraďuje túto vlastnosť:
{$IFDEF D5}
DateTime_SetFormat(DateTimePicker1.Handle, PChar('MM/dd/yyyy'));
{$ELSE}
DateTimePicker1.Format := 'MM/dd/yyyy';
{$ENDIF}
Pridajte CommCtrl do klauzuly uses pre jednotku, ktorá obsahuje vetvu pre Delphi 5. Nie je potrebné ho pridávať bezpodmienečne; ak preferujete udržiavanie ohraničenej závislosti, obaľte položku uses do rovnakej podmienky:
uses
...,
{$IFDEF D5}
CommCtrl,
{$ENDIF}
...;
Syntax reťazca formátu
Reťazec formátu poslaný do DateTime_SetFormat sa riadi formátom Windows date-time picker a nie tokenmi FormatDateTime z Delphi. Vyzerajú podobne, ale nie sú vzájomne zameniteľné. Windows používa d pre deň v mesiaci (bez úvodnej nuly), dd pre deň doplnený nulou, M pre číslo mesiaca, MM pre mesiac doplnený nulou, yy pre dvojciferný rok a yyyy pre štvorciferný rok. Časové polia používajú h/hh pre 12-hodinový formát hodín, H/HH pre 24-hodinový formát, m/mm pre minúty, s/ss pre sekundy. Literálny text sa v reťazci formátu vkladá do jednoduchých úvodzoviek, takže 'dd/MM/yyyy' je už samo o sebe správne, ale 'dd '<literál>' MM' by si vyžadovalo vnorené páry jednoduchých úvodzoviek
Na rozdiel od toho, Delphi FormatDateTime používa d/dd/ddd/dddd pre formáty dní s inou sémantikou, a m pre mesiac (nie M). Ak prekopírujete reťazec formátu z volania FormatDateTime a odovzdáte ho priamo do DateTime_SetFormat, polia pre mesiac a minútu budú na výstupe pravdepodobne vymenené. Píšte reťazec formátu ovládacieho prvku od nuly na základe dokumentácie Windows, namiesto jeho konverzie z formátu Delphi
Regionálne nastavenia a globálny ShortDateFormat
Zmena globálnej premennej Delphi ShortDateFormat neovplyvní už vytvorený prvok TDateTimePicker. Ovládací prvok pre výber dátumu a času načítava regionálne nastavenia z Windows v čase vytvorenia a následne sa vykresľuje podľa správ, ktoré dostáva, nie na základe globálnych premenných Delphi RTL. To znamená, že nastavenie ShortDateFormat v FormCreate nezmení to, čo ovládací prvok zobrazuje. Budete potrebovať DateTime_SetFormat (alebo vlastnosť Format v novšom Delphi) na prepísanie vlastného formátovacieho reťazca ovládacieho prvku po vytvorení handlu
V prípade medzinárodne nasadených aplikácií testujte formátovací reťazec na stroji s iným ako americkým regionálnym nastavením. Windows môže prepísať prázdny alebo nulový formátovací reťazec predvoleným nastavením podľa miestnych noriem, avšak explicitný neprázdny reťazec celkom nahrádza regionálne nastavenie. To je zvyčajne to, čo chcete, no znamená to aj to, že štandard zameraný na USA, akým je napríklad 'MM/dd/yyyy', sa zobrazí v pôvodnej podobe aj používateľom, ktorí podľa konvencie očakávajú dd/MM/yyyy. Ak je prvok zameraný skôr na používateľa, než by išlo o číre vstupné dátové pole, uvažujte nad ponechaním jeho predvolenej hodnoty (presuňte nil smerom k DateTime_SetFormat), aby tak automaticky reagoval na danú lokalizáciu samotného používateľa
Opätovné vytvorenie handlu
Nastavenie formátu náleží handlu okna, a nie nejakému VCL poľu daného objektu. Pokiaľ je handle ovládacieho prvku zničený a následne vytvorený znova – čo VCL dokáže, keď napríklad počas behu preradíte ovládací prvok inému rodičovi alebo zmeníte určité vlastnosti štýlu – formát sa vráti na predvolenú hodnotu systému Windows. Bezpečným miestom pre aplikáciu DateTime_SetFormat je handler, ktorý sa spúšťa po vytvorení handlu: prepíšte CreateWnd v odvodenej triede a zavolajte ho tam, alebo ho aplikujte v udalosti OnEnter či OnShow až potom, ako potvrdíte, že je daný handle živý. Nastaviť ho raz vo FormCreate je častokrát dostačujúce v prípade jednoduchých formulárov, nie je to však spoľahlivé, ak formulár vykonáva dynamické prepínanie štýlov alebo mení rodiča ovládacích prvkov
Zhodné pravidlo sa uplatňuje na VCL vlastnosť Format pri novších verziách Delphi; vnútorne si privoláva ten istý odkaz Windows a je vystavená rovnakému životnému cyklu prislúchajúcemu handlu. Ten rozdiel tkvie v tom, že setter VCL vlastnosti najskôr overuje, či je handle pridelený pred volaním, a zároveň formát opätovne s ohľadom na CreateWnd automaticky pridá. Prvotné volanie DateTime_SetFormat nemá zavedenú žiadnu podobnú ochranu, následkom čoho musí vetva Delphi 5 preukázať podstatne väčšiu svedomitosť pri procese samotného spúšťania
Odstránenie obchádzky (workaround)
Keď projekt upustí od podpory Delphi 5, blok podmienky sa stane mŕtvou váhou. Odstráňte vetvu {$IFDEF D5} a ohraničený import CommCtrl, ponechajúc len priame priradenie vlastnosti Format. Ponechajte odstránenie v jedinom commite, aby sa dalo ľahko identifikovať v prípade, ak sa na kompilátore, ktorý ste netestovali, niečo nečakane pokazí. Samotný reťazec formátu ostáva identický, v procese sa mení výlučne jeho doručovací mechanizmus