Před týdnem jsme popisovali komponentu MonthCalendar a začali jsme se zabývat také komponentou DateTímePicker. V dnešním díle seriálu budeme pokračovat v seznamování s touto komponentou a v závěru společně vytvoříme komplexní aplikaci, která demonstruje práci s měsíčním kalendářem i s komponentou DateTimePicker.
Minulý týden jsme skončili úvodním seznámením s komponentou DateTimePicker. Slíbili jsme si, že dnes začneme popisem jejích vlastností. Nuže, onen čas nadešel.
Vlastnosti komponenty DateTimePicker
Vlastnost CalAlignment
V této vlastnosti se nastavuje, kde se bude zobrazovat kalendář po klepnutí na šipku v pravé části komponenty DateTimePicker. Může nabývat dvou hodnot: dtaLeft (vlevo), dtaRight (vpravo). Při standardní šířce komponenty DateTimePicker rozdíl skoro ani nepoznáte (skoro:-)). Pokud ale šířku zvětšíte, rozdíl bude patrný (viz obrázky):
Vlastnost CalColors
Význam vlastnosti CalColors je stejný jako v případě komponenty MonthCalendar.
Vlastnost Checked
Říká, zda má být zatrženo zatrhávací pole vedle data přímo uvnitř komponenty DateTimePicker. Zobrazení tohoto zatrhávacího pole musí být ovšem povoleno ve vlastnosti ShowCheckBox.
Vlastnost Date
Tentýž význam jako u komponenty MonthCalendar – obsahuje právě vybrané (tedy zobrazované) datum.
Vlastnost DateFormat
Specifikuje formát, ve kterém je datum zobrazováno. Nastavování této vlastnosti má význam pouze a jen v případě, že hodnota vlastnosti Kind = dtkDate, neboť v případě, že Kind = dtkTime, nemá něco podobného vůbec smysl. Možné hodnoty:
- dfShort: pokud je formát nastaven na tuto hodnotu, datum se zobrazuje ve tvaru 20.10.2001 (nebo 10/20/01, přesný tvar záleží na místních nastaveních).
- dfLong: tento formát znamená, že datum se bude zobrazovat ve tvaru 20. října 2001 (opět jsou možné odchylky typu Pátek, říjen 21, 2001).
Vlastnost DateMode
Pomocí této vlastnosti můžete nastavit, jakým způsobem se fyzicky bude provádět výběr data. Opět platí, že tato vlastnost má význam jen v případě, že hodnota Kind = dtkDate.
- dmComboBox: standardní hodnota, která způsobí otevření kalendáře (typu MonthCalendar), ze kterého se datum jednoduše vybere.
- dmUpDown: v tomto případě se žádný kalendář neotevře, komponenta se přestane chovat jako rozbalovací seznam a začne připomínat spíše spojení komponenty UpDown s editačním polem: objeví se šipky nahoru a dolů a pomocí nich se datum nalezne.
Vlastnost Kind
Kind říká, co se vlastně v komponentě DateTimePicker bude zobrazovat, zda datum (dtkDate) nebo čas (dtkTime). V případě času nemají smysl některá nastavení několika dalších vlastností (např. DateMode, apod.).
Vlastnosti MinDate, MaxDate
Význam těchto vlastností je stejný jako u komponenty MonthCalendar (viz předchozí podkapitola). Umožňují nastavit minimální (nejmenší, „nejdávnější“) a maximální datum, které lze v komponentě vybrat a zobrazit.
Vlastnost ParseInput
Tato vlastnost udává, má-li se generovat událost OnUserInput v případě, že uživatel začne cosi zapisovat přímo do editačního pole – tedy v případě, že provádí zadání data přímo, nikoliv přes šipky (UpDown) nebo pomocí výběru z kalendáře (ComboBox).
Vlastnost ShowCheckBox
Logická vlastnost říkající, má-li se v levé části komponenty, vedle vlastního údaje, zobrazit zatrhávací políčko (viz obrázek). Je-li zobrazen, je možné nastavovat a testovat jeho hodnotu pomocí vlastnosti Checked. Pozor: zaškrtnutí/nezaškrtnutí políčka se nikam neukládá, proto pokud byste např. chtěli uživateli dát možnost u každého data ukládat nějakou poznámku prostřednictvím zatržení políčka (např. zatrženo = „tento den nemusím vstávat před jedenáctou“), mějte na paměti, že zatržení se nikde neuchovává a jakmile se v komponentě zobrazí jiné datum, je zapomenuto! Jeho případnou příslušnost k určitému datu musíte případně uchovávat sami.
Poznámka pro pokročilé uživatele: Předchozí popis je trochu nepřesný, protože zatržení není zapomenuto, ale prostě jenom zůstává při změně data nezměněno, protože je na něm naprosto nezávislé. Onu závislost si pak musíme vytvořit (doprogramovat) sami.
Vlastnost Time
Vlastnost Time má podobný význam jako vlastnost Date, jediný rozdíl spočívá v tom, že neobsahuje právě zadané/zobrazované datum, nýbrž čas. Typ této vlastnosti je však také TDateTime. Tato vlastnost má význam jen v případě, že hodnota vlastnosti Kind = dtkTime.
Události komponenty DateTimePicker
Po (snad dostatečně vyčerpávajícím) popisu vlastností se pojďme podívat na události:
Událost OnCloseUp
Tato událost vzniká v případě, že se právě chystá zavřít rozbalená část komponenty. Raději ještě jednou a jinak: máte-li nastaveno zobrazování kalendáře (tedy DateMode = dmComboBox), je událost OnCloseUp generována v okamžiku, kdy se rozbalený kalendář zase balí nazpět, kdy se zkrátka zavírá.
Událost OnDropDown
Událost OnDropDown se objevuje naopak v okamžiku, kdy uživatel klepl na šipku v pravé části komponenty a chystá se rozevření kalendáře.
Událost OnUserInput
Je generována, když uživatel přímo zadává údaje do komponenty (tedy nevybírá je pomocí kalendáře nebo šipek). Přesněji řečeno: událost OnUserInput je generována, až když uživatel potvrdí nový vložený údaj, nikoliv během zadávání. Stejně tak se nevyvolá v případě, že si to uživatel rozmyslí a při editování stiskne Esc. V obsluze této události můžeme pracovat s několika parametry:
type TDTParseInputEvent = procedure(
Sender: TObject;
const UserString: string;
var DateAndTime: TDateTime;
var AllowChange: Boolean) of object;
property OnUserInput: TDTParseInputEvent;
Nevadí, nerozumíte-li hlavičce úplně dokonale; pro naše účely nyní postačí popsat si parametry:
- Sender – obvyklý význam, odesílatel události;
- UserString – řetězec, který nám uživatel do komponenty zadal;
- DateAndTime – reprezentuje hodnotu vlastností Date a Time;
- AllowChange – logická hodnota, pomocí které můžeme změnu hodnoty komponenty zakázat (tedy uživatelův vstup nepřijmout).
Metody komponenty DateTimePicker
Odstavec shrnující metody komponenty bude tentokráte mimořádně stručný, neboť DateTimePicker žádné zajímavé (tj. vlastní) metody nemá, s výjimkou metody Create, která je sice jeho vlastní, ale zase není až tak zajímavá;-). Za zmínku proto stojí snad jen metoda BoldDays, se kterou jsme se setkali u komponenty MonthCalendar (viz předchozí podkapitola) a která slouží k zvýraznění některých dnů v kalendáři.
Ukázková aplikace využívající obě popsané komponenty
Na závěr kapitoly opět společně vytvoříme ukázkovou aplikaci, která ukáže, kterak pracovat s probranými komponentami.
Na formuláři (frmHlavni) jsou umístěny následující komponenty:
- MonthCalendar (Name = MonthCalendar);
- DateTimePicker (Name = DateTimePicker);
- ListBox (Name = lbDatumy);
- 4x Button (Name = btnPridat, btnVymazat, btnVymazatVse, btnKonec);
- 3x CheckBox (Name = cbKrouzek, cbDnes, cbDlouhy).
Zdrojové kódy celého modulu:
unit Hlavni;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, CommCtrl;
type
TfrmHlavni = class(TForm)
MonthCalendar: TMonthCalendar;
DateTimePicker: TDateTimePicker;
lbDatumy: TListBox;
btnPridat: TButton;
btnVymazat: TButton;
btnVymazatVse: TButton;
btnKonec: TButton;
cbKrouzek: TCheckBox;
cbDnes: TCheckBox;
cbDlouhy: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure btnPridatClick(Sender: TObject);
procedure DateTimePickerChange(Sender: TObject);
procedure btnKonecClick(Sender: TObject);
procedure btnVymazatVseClick(Sender: TObject);
procedure MonthCalendarClick(Sender: TObject);
procedure MonthCalendarGetMonthInfo(Sender: TObject; Month: Cardinal;
var MonthBoldInfo: Cardinal);
procedure btnVymazatClick(Sender: TObject);
procedure cbKrouzekClick(Sender: TObject);
procedure cbDnesClick(Sender: TObject);
procedure cbDlouhyClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmHlavni: TfrmHlavni;
implementation
{$R *.DFM}
procedure TfrmHlavni.FormCreate(Sender: TObject);
begin
frmHlavni.Caption := `Komponenty MonthCalendar a DateTimePicker`;
btnPridat.Caption := `&Pøidat`;
btnVymazat.Caption := `&Vymazat`;
btnVymazatVse.Caption := `Vym&azat vše`;
btnKonec.Caption := `&Konec`;
cbKrouzek.Checked := True;
cbKrouzek.Caption := `&Kroužek`;
cbDnes.Checked := True;
cbDnes.Caption := `Zobraz &dnes`;
cbDlouhy.Checked := True;
cbDlouhy.Caption := `Dlouhý &tvar`;
DateTimePicker.DateMode := dmUpDown;
DateTimePicker.DateFormat := dfLong;
end;
procedure TfrmHlavni.btnPridatClick(Sender: TObject);
var
S : String;
begin
S := FormatDateTime(`d.m`, MonthCalendar.Date);
if lbDatumy.Items.IndexOf(S) = -1
then lbDatumy.Items.Add(S);
end;
procedure TfrmHlavni.DateTimePickerChange(Sender: TObject);
begin
MonthCalendar.Date := DateTimePicker.Date;
end;
procedure TfrmHlavni.btnKonecClick(Sender: TObject);
begin
Application.Terminate;
end;
procedure TfrmHlavni.btnVymazatVseClick(Sender: TObject);
begin
lbDatumy.Clear;
end;
procedure TfrmHlavni.MonthCalendarClick(Sender: TObject);
begin
DateTimePicker.Date := MonthCalendar.Date;
end;
procedure TfrmHlavni.MonthCalendarGetMonthInfo(Sender: TObject;
Month: Cardinal; var MonthBoldInfo: Cardinal);
var
I: Integer;
RokListBox, MesicListBox, DenListBox: Word;
MnozinaDnu: array[0..30] of LongWord;
begin
ZeroMemory(@MnozinaDnu, SizeOf(MnozinaDnu));
for I := 0 to (lbDatumy.Items.Count - 1) do begin
DecodeDate(StrToDate(lbDatumy.Items[I]), RokListBox,
MesicListBox, DenListBox);
if (MesicListBox = Month) then
MnozinaDnu[I] := DenListBox;
end; // for I := 0
MonthCalendar.BoldDays(MnozinaDnu, MonthBoldInfo);
end;
procedure TfrmHlavni.btnVymazatClick(Sender: TObject);
begin
lbDatumy.Items.Delete(lbDatumy.ItemIndex);
end;
procedure TfrmHlavni.cbKrouzekClick(Sender: TObject);
begin
MonthCalendar.ShowTodayCircle := cbKrouzek.Checked;
end;
procedure TfrmHlavni.cbDnesClick(Sender: TObject);
begin
MonthCalendar.ShowToday := cbDnes.Checked;
end;
procedure TfrmHlavni.cbDlouhyClick(Sender: TObject);
begin
if cbDlouhy.Checked then
DateTimePicker.DateFormat := dfLong
else
DateTimePicker.DateFormat := dfShort;
end;
end.
Běžící aplikaci ukazuje následující obrázek:
Od dnešního dílu budou poznámky k aplikaci vždy rozděleny do dvou částí. V odstavci Popis funkce bude program popsán z uživatelského hlediska, tedy popis funkcí a ovládacích prvků. Odstavec Poznámky ke zdrojovému kódu pak bude vysvětlovat detaily implementace, použité metody a „fígle“ bezprostředně související s programováním. Doufám, že toto dělení uvítáte.
Popis funkce: Program funguje tak, že v komponentách MonthCalendar, případně DateTimePicker uživatel vybere nějaké datum a po klepnutí na tlačítko Přidat je toto datum přidáno do seznamu ListBox. Přidává se vždy jen den a měsíc, bez ohledu na rok. Komponenta MonthCalendar slouží totiž už z principu k zobrazování údajů o jednotlivých měsících v libovolném roce a jeho filozofie je taková, že budou-li 1.7. - 31.8. prázdniny nebo má-li někdo svátek 3.5., platí
to každý rok.
Datum ze seznamu je možné také vypustit, a to jeho vybráním a klepnutím na Vymazat. Po klepnutí na Vymazat vše je celý seznam vyprázdněn. Třemi zatrhávacími poli je možné ovlivnit vzhled komponent MonthCalendar a DateTimePicker: pole Kroužek říká, má-li se zobrazovat červený kroužek u dnešního dne, pole Zobraz dnes říká, bude-li se pod kalendářem objevovat řádka „Dnes: … dnešní datum“ a konečně pole Dlouhý tvar předurčuje zobrazení data v komponentě DateTimePicker. Klepnutí na Konec aplikaci ukončí. Po změně měsíce se v kalendáři zobrazí tučně všechny dny, které jsou v seznamu.
Poznámky ke zdrojovému textu:
- V rámci obsluhy události OnCreate hlavního formuláře jsou opět provedeny inicializace a nastavení titulků komponent.
- Po klepnutí na tlačítko Přidat (událost OnPridatClick) je nutné získat z údaje typu TDateTime (údaj z kalendáře) na řetězec (údaj zobrazitelný v seznamu). Použijeme k tomu funkci FormatDateTime, která byla popsána v 33. dílu seriálu.
- Změní-li se hodnota v DateTimePicker, je nutné tuto změnu přenést do MonthCalendar (metoda DateTimePickerChange), stejně tak naopak (metoda MonthCalendarClick).
- Metoda MonthCalendarGetMonthInfo (ošetření událost OnGetMonthInfo) slouží především k zvýraznění dnů, které jsou uvedeny v seznamu. Je k tomu použita metoda BoldDays a pomocné pole MnozinaDnu, které naplníme čísly dnů určenými k zvýraznění. Procházíme postupně všechny dny uvedené v seznamu, kontrolujeme, zda odpovídá měsíc aktuálnímu údaji z kalendáře, a pokud ano, přidáme den do pole MnozinaDnu. Nakonec toto pole použijeme jako parametr metody BoldDays. Je nutné použít pomocné pole a metodu BoldDays volat nakonec jen jednou, protože kdybychom BoldDays volali opakovaně a vždy jako parametr předali jen jeden den, budou všechny ostatní dny zobrazeny normálně (tučný by tedy byl vždy jen jeden den).
- Na začátku metody MonthCalendatGetMonthInfo je nutné vynulovat pole, ve kterém uchováváme tučné dny. Děláme to pomocí funkce WinAPI ZeroMemory(@MnozinaDnu, SizeOf(MnozinaDnu)); Tato funkce zajistí vynulování paměti zadané jejím počátkem a velikostí. Pokud nemáte rádi funkce Windows API, můžete stejně tak dobře použít cyklus for, ve kterém postupně přiřadíte každému prvku pole hodnotu 0.
Dnes jsme tedy úspěšně dokončili problematiku, kterou jsme „nakousli“ již před časem – a sice problematiku práce s datem a časem. Popsali jsme jednoduchý kalendář a snad všechny metody, které se k datu a času vztahují, dnes (a před týdnem) jsme si ukázali dvě poměrně elegantní a moderně vyhlížející komponenty, pomocí kterých bude tvorba vašich aplikací opět lepší a profesionálnější:-) Příště nashledanou.