Umíme to s Delphi, 37. díl – datum a čas je nade vše: výběr data a času

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):

Klepněte pro větší obrázek

Klepněte pro větší obrázek

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.

Klepněte pro větší obrázek

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:

Klepněte pro větší obrázek

Poznámky k aplikaci:

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.

Na závěr

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.
Diskuze (4) Další článek: Nadupaný pomocník

Témata článku: Software, Windows, Programování, DEL, Význam, Předchozí den, Pole, Datum, Komponenta, Předchozí odstavec, Čas, Díl, DM, Editační funkce


Určitě si přečtěte

10 míst na mapách Googlu, která nesmíte vidět. Nahradily je čtverečky

10 míst na mapách Googlu, která nesmíte vidět. Nahradily je čtverečky

** Deset míst, které nesmíte vidět ve webových mapách ** Jsou to letiště, základny i elektrárny ** Nejvíce míst tají Francie

Jakub Čížek | 21

Jakub Čížek
Mapy GoogleMapy
Dostali jste nový počítač? Tohle s ním udělejte, než ho začnete používat

Dostali jste nový počítač? Tohle s ním udělejte, než ho začnete používat

** Každý nový počítač si zaslouží počáteční péči ** Odinstalujte bloatware a nezapomeňte na vhodné nastavení ** Poradíme, jak se o počítač s Windows 10 postarat

David Polesný, Stanislav Janů | 71

David PolesnýStanislav Janů
PočítačeNotebooky
26 užitečných rozšíření pro Chrome: Naučte prohlížeč nové věci

26 užitečných rozšíření pro Chrome: Naučte prohlížeč nové věci

** Prohlížeč Chrome obsahuje širokou škálu funkcí, neumí ale všechno ** Jeho schopnosti můžete rozšířit pomocí rozšíření ** Vybrali jsme pro vás zajímavé a užitečné doplňky

Karel Kilián | 44

Karel Kilián
Doplňky do prohlížečeChromeProhlížeče
CZ.NIC bezplatně naděluje USB/NFC klíče. Jak jej získat?
Lukáš Václavík
CZ.NICeGovernment
Vážně dnes ještě někdo krade Adobe? Video můžete stříhat zdarma v Resolve a fotky i vektory zvládne Affinity

Vážně dnes ještě někdo krade Adobe? Video můžete stříhat zdarma v Resolve a fotky i vektory zvládne Affinity

** Kde jsou ty doby, kdy měl skoro každý doma Photoshop ** Photoshop a Premiere Pro od kamaráda nebo z warezu ** Dnes už to nemá smysl, existuje totiž hromada laciných alternativ

Jakub Čížek | 90

Jakub Čížek
Grafický editorStřih videa
Vyšel Windows 10 October 2020 Update. Poradíme, jak je stáhnout a co je nového
Vladislav Kluska
October 2020 UpdateWindows 10
Google vymyslel technologii superpřesného GPS. Už ji podporuje Pixel 5 a dorazí i na ostatní telefony

Google vymyslel technologii superpřesného GPS. Už ji podporuje Pixel 5 a dorazí i na ostatní telefony

** Kvalita GPS ve městech občas stojí za starou bačkoru ** Mohou za to odrazy signálu od okolních budov ** Google má jejich 3D model, a tak spolupracuje s výrobci GPS čipů

Jakub Čížek | 40

Jakub Čížek
NavigaceTechnologieGoogle

Aktuální číslo časopisu Computer

Jak prodloužit výdrž notebooku

Velké testy: gamepady a inkoustové tiskárny

Důkladný test Sony Playstation 5