Tekninen artikkeli

TDateTimePickerin muoto Delphi 5:ssä: DateTime_SetFormat

TDateTimePicker sai Format-ominaisuuden jossain Delphi 5:n ja Delphi 6:n välillä. Tarkkaa versiorajaa on harvoin dokumentoitu luotettavalla tavalla, ja kun törmäät siihen, kääntäjä vain kertoo, ettei tunnistetta ole olemassa. Rivi, joka kääntyy ja toimii jokaisessa uudemmassa Delphissäsi, epäonnistuu hiljaisesti tai suoraan vanhassa, riippuen siitä, kuinka projekti on rakennettu

Taustalla oleva komponentti on Windowsin yleinen DATETIMEPICK_CLASS-komponentti tiedostosta comctl32.dll, ja se on aina hyväksynyt muotoilumerkkijonon DTM_SETFORMAT-viestin kautta. Delphin VCL käärii kyseisen viestin ominaisuuteen Format uudemmissa versioissa. Delphi 5:ssä lähetät viestin itse CommCtrl-yksikössä esitellyn DateTime_SetFormat-makrokääreen kautta

Ehdollinen kääntämismalli

Vakiolähestymistapa on versiosymboliin perustuva kääntäjän ehtolohko. Delphi 5 määrittelee symbolin VER130; voit testata sitä suoraan tai määritellä oman D5-symbolisi projektiasetuksissa tehdäksesi haaran tunnisteesta luettavamman koodikannassa. Kummassakin tapauksessa Delphi 5 -haara kutsuu menetelmää DateTime_SetFormat komponentin kahvan (handle) kanssa; jokainen muu haara sijoittaa ominaisuuden:

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

Lisää CommCtrl uses-lausekkeeseen siinä yksikössä, joka sisältää Delphi 5 -haaran. Sitä ei tarvitse lisätä ehdoitta; jos haluat pitää riippuvuuden rajattuna, kääri uses-merkintä samaan ehtoon:

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

Muotoilumerkkijonon syntaksi

Menetelmälle DateTime_SetFormat välitetty muotoilumerkkijono noudattaa Windowsin päivämäärä-aikavalitsimen muotoa, ei Delphin FormatDateTime-tunnisteita. Nämä kaksi näyttävät samankaltaisilta, mutta ne eivät ole keskenään vaihdettavissa. Windows käyttää d kuukauden päivälle (ilman etunollaa), dd etunollalla varustetulle päivälle, M kuukauden numerolle, MM etunollalla varustetulle kuukaudelle, yy kaksinumeroiselle vuodelle ja yyyy nelinumeroiselle vuodelle. Aikakentät käyttävät h/hh 12 tunnin tunneille, H/HH 24 tunnin tunneille, m/mm minuuteille, s/ss sekunneille. Literaaliteksti (literal text) menee yksittäisten lainausmerkkien sisään muotoilumerkkijonossa, joten 'dd/MM/yyyy' on jo oikein, mutta 'dd '<literal>' MM' vaatisi upotettuja yksittäisten lainausmerkkien pareja

Sen sijaan Delphin FormatDateTime käyttää d/dd/ddd/dddd päivämuodoille eri semantiikalla, ja m kuukaudelle (ei M). Jos kopioit muotoilumerkkijonon FormatDateTime-kutsusta ja luovutat sen suoraan menetelmälle DateTime_SetFormat, kuukausi- ja minuuttikentät todennäköisesti vaihtuvat keskenään tulosteessa. Kirjoita komponentin muotoilumerkkijono alusta alkaen Windowsin dokumentaation perusteella sen sijaan, että muuntaisit sen Delphi-muodosta

Aluekohtaiset asetukset ja globaali ShortDateFormat

Delphin globaalin ShortDateFormat-muuttujan muuttaminen ei vaikuta jo luotuun TDateTimePicker-komponenttiin. Valitsin lukee aluekohtaiset asetukset Windowsista luontihetkellä ja sen jälkeen renderöi saamiensa viestien mukaan, ei Delphi RTL:n globaalien muuttujien mukaan. Se tarkoittaa, että muuttujan ShortDateFormat asettaminen FormCreate-tapahtumassa ei muuta komponentin näyttämää sisältöä. Tarvitset menetelmää DateTime_SetFormat (tai uudemman Delphin Format-ominaisuutta) ohittaaksesi komponentin oman muotoilumerkkijonon sen jälkeen, kun kahva on olemassa

Kansainvälisesti jaettavissa sovelluksissa testaa muotoilumerkkijonoa koneella, jolla on ei-yhdysvaltalainen alueasetus. Windows voi ohittaa tyhjän tai nil-arvoisen muotoilumerkkijonon alueasetuksen oletusarvolla, mutta nimenomainen ei-nil-merkkijono korvaa alueasetuksen kokonaan. Sitä yleensä halutaan, mutta se tarkoittaa, että Yhdysvaltoihin keskittyvä malli, kuten 'MM/dd/yyyy', näkyy sellaisenaan käyttäjille, jotka odottavat perinteisesti muotoa dd/MM/yyyy. Jos päivämäärävalitsin on tarkoitettu käyttäjille eikä puhtaaksi tiedonsyöttökentäksi, harkitse komponentin oletusarvon käyttämistä (syötä nil menetelmälle DateTime_SetFormat), jotta se seuraa käyttäjän alueasetusta automaattisesti

Kahvan uudelleenluonti

Muotoasetus kuuluu ikkunan kahvaan (window handle), ei mihinkään VCL-objektin kenttään. Jos komponentin kahva tuhotaan ja luodaan uudelleen, minkä VCL voi tehdä, kun muutat komponentin emoa (reparent) tai muutat tiettyjä tyyliominaisuuksia ajon aikana, muoto palautuu Windowsin oletukseen. Turvallinen paikka soveltaa menetelmää DateTime_SetFormat on käsittelijä, joka suoritetaan kahvan luomisen jälkeen: ohita (override) CreateWnd jälkeläisluokassa ja kutsu sitä siellä, tai sovella sitä OnEnter- tai OnShow-tapahtumassa vasta vahvistettuasi, että kahva on elossa. Sen asettaminen kerran FormCreate-tapahtumassa riittää usein yksinkertaisille lomakkeille, mutta se ei ole luotettavaa, jos lomake tekee dynaamisia tyylinvaihtoja tai komponenttien siirtoja emoikkunoiden välillä

Sama rajoitus koskee uudemmissa Delphi-versioissa olevaa VCL:n Format-ominaisuutta; sisäisesti se kutsuu samaa Windowsin viestiä ja kohtaa saman kahvan elinkaaren. Erona on, että VCL:n ominaisuuden asettaja tarkistaa, onko kahva varattu, ennen kuin se tekee kutsun, ja soveltaa muotoa automaattisesti uudelleen CreateWnd-kutsussa. Raaka DateTime_SetFormat-kutsu ei sisällä tällaista suojausta, joten Delphi 5 -haaran täytyy olla harkitumpi sen suhteen, milloin se suoritetaan

Kiertotavan poistaminen

Kun projekti pudottaa Delphi 5 -tuen, ehtolohkosta tulee turhaa painolastia. Poista {$IFDEF D5} -haara ja rajattu CommCtrl-tuonti, jättäen jäljelle vain suoran ominaisuuden Format sijoituksen. Pidä poisto yhdessä toimituksessa (commit), jotta on helppo tunnistaa, jos jokin odottamatta rikkoutuu kääntäjässä, jota et testannut. Itse muotoilumerkkijono pysyy samana; vain toimitusmekanismi muuttuu