Technical Article

Format TDateTimePicker v Delphi 5: DateTime_SetFormat

TDateTimePicker je dobil lastnost Format nekje med različicama Delphi 5 in Delphi 6. Točna meja različice je redko zanesljivo dokumentirana, in ko naletite nanjo, vam prevajalnik preprosto javi, da identifikator ne obstaja. Vrstica, ki se prevede in deluje v vsaki novejši različici Delphija, v stari različici tiho ali popolnoma odpove, odvisno od strukture projekta.

Osnovna kontrola je pogosta kontrola Windows DATETIMEPICK_CLASS iz knjižnice comctl32.dll, ki je vedno sprejemala zapis formata prek sporočila DTM_SETFORMAT. Delphi VCL to sporočilo v novejših različicah ovije v lastnost Format. V različici Delphi 5 sporočilo pošljete sami prek makro ovijalnika DateTime_SetFormat, ki je deklariran v enoti CommCtrl.

Vzorec pogojnega prevajanja

Standardni pristop je pogojni prevajalni blok, vezan na simbol različice. Delphi 5 definira VER130; lahko ga preverite neposredno ali pa definirate lasten simbol D5 v možnostih projekta za boljšo berljivost kode. V vsakem primeru veja za Delphi 5 kliče DateTime_SetFormat z ročico kontrole; vse ostale veje pa dodelijo vrednost lastnosti:

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

Dodajte CommCtrl v stavek uses za enoto, ki vsebuje vejo za Delphi 5. Ni je treba dodati brezpogojno; če želite ohraniti odvisnost omejeno, ovijte vnos uses v enak pogoj:

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

Sintaksa nizov zapisov formata

Zapis formata, ki ga posredujete funkciji DateTime_SetFormat, sledi obliki izbirnika datuma in časa Windows, ne žetonom FormatDateTime iz Delphija. Obliki sta si podobni, vendar nista zamenljivi. Windows uporablja d za dan v mesecu (brez vodilne ničle), dd za dan z vodilno ničlo, M za številko meseca, MM za mesec z vodilno ničlo, yy za dvomestno letnico in yyyy za štirimestno letnico. Polja za čas uporabljajo h/hh za 12-urni zapis, H/HH za 24-urni zapis, m/mm za minute in s/ss za sekunde. Dobesedno besedilo (literal) gre znotraj niza formata v enojne narekovaje, zato je 'dd/MM/yyyy' že pravilno, medtem ko bi 'dd '<literal>' MM' zahteval gnezdene pare enojnih narekovajev.

Delphijev FormatDateTime nasprotno uporablja d/dd/ddd/dddd za oblike dneva z drugačno semantiko in m za mesec (ne M). Če kopirate niz formata iz klica FormatDateTime in ga predate neposredno DateTime_SetFormat, bosta polji za mesec in minute v izhodu verjetno zamenjani. Niz formata za kontrolo napišite na novo glede na dokumentacijo Windows in ga ne pretvarjajte iz Delphijevega formata.

Regionalne nastavitve in globalni ShortDateFormat

Spreminjanje Delphijeve globalne spremenljivke ShortDateFormat ne vpliva na že ustvarjen TDateTimePicker. Izbirnik ob ustvarjanju prebere regionalne nastavitve iz sistema Windows in se nato izrisuje glede na prejeta sporočila ter ne sledi globalnim spremenljivkam Delphi RTL. To pomeni, da nastavitev ShortDateFormat v FormCreate ne bo spremenila prikaza kontrole. Za preglasitev privzetega niza formata po tem, ko ročica (handle) že obstaja, morate uporabiti DateTime_SetFormat (ali lastnost Format v novejšem Delphiju).

Za aplikacije, ki so nameščene na mednarodnem trgu, preizkusite niz formata na računalniku z neameriškimi regionalnimi nastavitvami. Windows lahko prazen ali nil niz formata nadomesti s privzeto lokalno nastavitvijo, vendar izrecno določen niz formata popolnoma preglasi regionalno nastavitev. To je običajno tisto, kar želite, vendar to pomeni, da se bo vzorec, osredotočen na ZDA, kot je 'MM/dd/yyyy', prijazno prikazal nespremenjen tudi za uporabnike, ki po konvenciji pričakujejo dd/MM/yyyy. Če je izbirnik datuma namenjen neposredno uporabnikom in ne gre za goli vnos podatkov, razmislite o privzeti nastavitvi kontrole (predajte nil v DateTime_SetFormat), da bo samodejno sledila uporabnikovim lokalnim nastavitvam.

Ponovno ustvarjanje ročice (Handle recreation)

Nastavitev formata pripada ročici okna (window handle) in ne polju objekta VCL. Če se ročica kontrole uniči in znova ustvari, kar lahko VCL stori pri spremembi starševskega okna kontrole ali spreminjanju določenih slogovnih lastnosti med delovanjem, se format vrne na privzete nastavitve Windows. Varno mesto za uporabo DateTime_SetFormat je v upravljalniku, ki se zažene po ustvarjanivanju ročice: prepišite CreateWnd v dednem razredu in ga pokličite tam, ali pa ga uveljavite v dogodku OnEnter or OnShow šele po potrditvi, da je ročica aktivna. Enkratna nastavitev v FormCreate pogosto zadotuje za preproste obrazce, vendar ni zanesljiva, če obrazec dinamično spreminja sloge ali starševstvo kontrol.

Enaka omejitev velja za lastnost VCL Format v novejših različicah Delphija; interno uporablja isto sporočilo Windows in se sooča z enakim življenjskim ciklom ročice. Razlika je v tem, da nastavljalnik lastnosti VCL pred klicem preveri, ali je ročica dodeljena, in samodejno znova uveljavi format ob klicu CreateWnd. Neposredni klic DateTime_SetFormat nima takšne zaščite, zato mora biti veja za Delphi 5 bolj premišljena glede trenutka izvedbe.

Odstranitev začasne rešitve

Ko projekt opusti podporo za Delphi 5, postane pogojni blok odveč. Odstranite vejo {$IFDEF D5} in omejen uvoz CommCtrl ter pustite le neposredno dodelitev lastnosti Format. Odstranitev opravite v enem samem commitu, da jo boste lažje prepoznali, če se na nepreizkušenem prevajalniku kaj nepričakovano zalomi. Sam niz formata ostaja enak; spremeni se le mehanizem dostave.