Programování 3 a 4 – poznámky k výuce Algoritmus a jeho vlastnosti
Transkript
Programování 3 a 4 – poznámky k výuce Algoritmus a jeho vlastnosti
Programování 3 a 4 – poznámky k výuce verze 2007-05-04 Tento text není v žádném případě učebnicí Delphi nebo programování, jsou to pouze (mírně) uspořádané poznámky, které chronologicky kopírují to, co děláme na semináři z programování. V textu jsou odkazy i další dokumenty a literaturu k danému tématu. U jednotlivých komponent nejsou uváděny všechny vlastnosti, ale jen ty, které budeme ze začátku potřebovat. Podobně i další informace v tomto textu nejsou leckdy úplné, často jde o zjednodušení dané problematiky. RNDr. Jan Preclík, Ph.D. Další literatura Text se odkazuje na další literaturu, zejména na: [1] Pavel Satrapa. Pascal pro zelenáče. Neokortex spol. s r.o., Praha, 2000. (výborná knížka o jazyce Pascal) [2] dokument „Algoritmus a jeho vlastnosti“. http://ivt.gymnachod.cz/materialy/programovani/ALGORITMUS.PDF [3] dokument „Jazyk Pascal – úvod“. http://ivt.gymnachod.cz/materialy/programovani/PASCAL_UVOD.PDF [4] dokument „Pole (vícerozměrné i jednorozměrné)“. http://ivt.gymnachod.cz/materialy/programovani/POLE.PDF [5] dokument „Vyhledávání v poli“. http://ivt.gymnachod.cz/materialy/programovani/VYHLEDAVANI_V_POLI.PDF [6] nápověda k Delphi (menu Help/Delphi Help) Algoritmus a jeho vlastnosti Viz dokument [2] – „Algoritmus a jeho vlastnosti“. Delphi – úvod, aneb jak se programuje pod Windows Delphi jsou nástrojem pro RAD = Rapid Application Development (rychlý vývoj aplikací), vzhled aplikace se skládá z předpřipravených prvků – komponent, jde o tzv. vizuální programování (programování pomocí myši, bez psaní programového kódu). Co se stane například po stisku tlačítka (stisk tlačítka = event, událost) je ale už třeba psát přímo v programovacím jazyce (tzv. event handler = zpracující procedura této události). Delphi jsou založeny na jazyce Pascal a jeho rozšíření Object Pascal. Hlavní program je v podstatě nekonečná smyčka, ve které se zpracovávají události, které nastanou, tj. vyvolávají se odpovídající event handlery, ve kterých se skrývá celá funkčnost programu. Hovoříme o programování řízeném událostmi (event-driven programming). „Dneska všechny programy běží v nekonečné smyčce a čekají, až si nějakej cvok zvykne na myš.“ Dr. Rudolf Kryl, MFF UK, přednáška Metodika programování a filozofie programovacích jazyků, 2005 Komponenty v Delphi Komponentu umístíme na formulář jejím výběrem v paletě komponent a kliknutím na formulář (komponenta bude mít svoji standardní velikost) nebo tažením myší (a tím určíme velikost komponenty). Object Inspector Okno slouží k nastavování vlastností komponent (karta Properties) a reakcí na události (karta Events). Vlastnosti mohou být: • jednoduché (mohou obsahovat pouze jednu hodnotu, například číslo – Left) • výčtového typu (nabízí se nám seznam možných hodnot – symbolických konstant s prefixem odpovídajícím názvu vlastnosti, např. BorderStyle a možné hodnoty bsSizeable, bsDialog…) • strukturované – položky se zobrazí po kliknutí na symbol , případně tlačítko vyvolá editor této vlastnosti (samostatné dialogové okno) Vlastnosti společné všem komponentám (až na pár výjimek) • Name – jméno komponenty, musí být (na formuláři) jedinečné, komponentu jednoznačně na formuláři • Left – x-souřadnice levého horního rohu komponenty v pixelech (pozor, odkud se počítá – od levého • • • Top – y-souřadnice levého horního rohu komponenty v pixelech (pozor, odkud se počítá!) Width – šířka komponenty Height – výška komponenty identifikuje horního rohu uživateli dostupné plochy, tj. ne od levého horního rohu okna!) Nevizuální komponenty (reprezentované na formuláři pouze svojí ikonou, např. MainMenu nebo Timer) mají pouze vlastnost Name. Formulář (TForm) • • • Caption – text v titulkovém pruhu BorderStyle – vlastnosti okraje okna (bsDialog, bsSizeable, bsNone) Position – umístění formuláře (poDesigned – podle vlastností Top a Left, poScreenCenter – vždy ve středu bez ohledu na rozlišení obrazovky) Ještě pár obecnějších vlastností − společné pro TLabel, TEdit, TButton, TBitBtn • Font – písmo • Hint – text popisku (žluté okno se stručnou nápovědou), objeví se, pokud kurzor myši chvíli setrvá nad komponentou • ShowHint – zda se bude popisek zobrazovat • Visible – zda je komponenta viditelná (při běhu, při návrhu je viditelná vždy) • Enabled – zda je komponenta povolená (pro uživatele přístupná) Komponenta Label (TLabel) − pro zobrazení textu na formuláři • Caption – text • AutoSize – automatická změna velikosti (velikost komponenty se přizpůsobuje jejímu obsahu) • Color – barva podkladu (barva písma se nastavuje ve vlastnosti Font) • Transparent – zda je pozadí průhledné (pokud ano, pak se na barvu Color nebere ohled) • Alignment – zarovnání textu v rámci komponenty (nemá smysl, pokud je AutoSize = TRUE) • WordWrap – zalamování textu na více řádků Komponenta Edit (TEdit) − editační řádek (políčko), pro vstup hodnot od uživatele • Text – text zobrazený v editačním políčku (je dobré vymazat přednastavený název komponenty) • ReadOnly – zda je komponenta určená pouze pro čtení Komponenta Button (TButton) − tlačítko • Caption – text na tlačítku Tlačítku nejde nastavit barva pozadí (tj. barva tlačítka). Komponenta BitBtn (TBitBtn) − podobné jako TButton, ale navíc má vlastnost Kind • Kind – určuje druh tlačítka (podle toho se nastaví text a obrázek) Komponenta Image (TImage) − obrázek (formát JPG, BMP, ICO, EMF, WMF, GIF) Picture – obrázek, okno pro práci s obrázkem se objeví také po dvojkliku na komponentu • AutoSize – velikost komponenty se přizpůsobí velikosti obrázku • Stretch – velikost obrázku se přizpůsobí velikosti komponenty, algoritmus pro změnu velikosti není příliš podařený, je lepší obrázek zmenšit/zvětšit v grafickém editoru a do Delphi ho nahrát v té velikosti, ve které je potřeba (vhodné i pro úsporu místa) • Center – pokud je obrázek menší jak komponenta, bude umístěn v rámci komponenty na střed • Transparent – zda bude pozadí obrázku průhledné (záleží na formátu: ICO, WMF, EMF – průhledné vždy, GIF – průhlednost podle alfa-kanálu obrázku, JPG – nemá průhlednost, BMP – jako průhledná barva se bere barva pixelu v levém dolním rohu obrázku) Některé kombinace vlastností jsou nemá smysl používat, např. AutoSize a Strech, Center a AutoSize… Komponenta Shape (TShape) − geometrické tvary pro umístění na formulář • Shape – tvar • Brush – štětec = výplň (Color – barva, Style – typ výplně) • Pen – pero = čára (Color – barva, Style – typ čáry, Width – tloušťka čáry v pixelech) Komponenta CheckBox (TCheckBox) − samostatné zaškrtávací (označovací) tlačítko, může jich být označeno více najednou • Caption – text vedle označovacího čtverečku • Checked – zda je označené • Color – barva pozadí Související komponenty CheckBox můžeme umístit do komponenty GroupBox nebo na komponentu Panel. Komponenta RadioGroup (TRadioGroup) − skupina radiových tlačítek, z této skupiny může být označeno nejvýše jedno tlačítko • Caption – nadpis skupiny • Color – barva pozadí skupiny • Columns – počet sloupců, do kterých jsou položky rozmístěny (pokud je počet sloupců stejný jako počet položek, budou položky v řadě vedle sebe) • Items – položky (jejich názvy), každá na jednom řádku • ItemIndex – číslo vybrané položky (první položka v seznamu má číslo 0), -1 znamená, že není vybraná žádná položka Můžeme také použít komponenty RadioButton (samostatná rádiová tlačítka) a umístit je do komponenty GroupBox, která je sváže dohromady. Je to však komplikovanější. Komponenta MainMenu (TMainMenu) − hlavní menu aplikace, jde o nevizuální komponentu – na formuláři je reprezentována pouze svojí ikonou, která se při běhu aplikace nezobrazuje (nemá vlastnosti Top, Left, Height, Width), po dvojkliku se objeví Menu Designer – editor menu Pro položky menu můžeme nastavovat: • Caption – text položky menu, přiřazením „-“ (mínus) do této vlastnosti vytvoří vodorovnou čáru místo položky • ShortCut – klávesová zkratka položky Komponenta Panel (TPanel) − slouží pro umísťování dalších (vizuálních) komponent, jde o tzv. kontejner (=komponenta, která může obsahovat další komponenty) • BevelInner – vnitřní okraj • BevelOuter – vnější okraj • BevelWidth – šířka okraje, kombinací těchto tří vlastností lze vytvářet nejrůznější efekty (rámeček, vyvýšení/snížený panel…) • Caption – nadpis panelu, většinou je potřeba standardní text (jméno komponenty) vymazat • Color – barva panelu Zarovnávání komponent na formuláři Chceme-li, aby například tlačítko bylo vždy umístěno u dolního okraje formuláře i při změně jeho velikosti, nemusíme hned programovat, ale můžeme využít vlastnost Align u většiny komponent. Tato vlastnost určuje, jak bude komponenta zarovnána v rámci kontejneru, který ji obsahuje (buď formulář nebo komponenta Panel). Nastavování vlastností více komponentám najednou Pokud vybereme více komponent na formuláři, v Object Inspectoru se objeví pouze ty vlastnosti, které jsou společné všem komponentám, a lze je nastavit najednou. Programování v Delphi Borland Delphi jsou založeny na programovacím jazyce Pascal, viz dokument [3] – „Jazyk Pascal – úvod“. Konzolová aplikace aneb programování ve stylu operačního systému MS DOS Konzolová aplikace využívá pouze standardní textový vstup (z klávesnice) a standardní textový výstup (na textovou konzoli – „DOSovské okno“). Můžeme tak programovat (s některými omezeními) podobně jako v Turbo Pascalu pro operační systém MS DOS. Konzolovou aplikaci založíme v Delphi z menu File/New/Other…, Console Application. Důležitý je řádek {$APPTYPE CONSOLE}, který překladači specifikuje, o jaký typ aplikace se jedná. Poznámka: Překladač lze přímo ovládat pomocí příkazů ve tvaru {$...}. Z hlediska Pascalu jde o komentář – nemá tedy význam pro program, ale je to informace pro překladač. Výhodou konzolových aplikací je malá velikost výsledného exe souboru (v porovnání s aplikací pro Windows). Příklad KONZOLE_LINEARNI_ROVNICE Příklad KONZOLE_KVADRATICKA_ROVNICE Programování pod Windows Jak pojmenovávat komponenty Je výhodné zavést a dodržovat určité konvence, například jméno komponenty začínat prefixem určujícím typ komponenty, tj. například: Buton → btnTlacitko Label → lblNapis Edit → edtPolicko Image → imgObrazek CheckBox → ckbZaskrtavatko RadioButton → rdbRadioveTlacitko RadioGroup → rdgSkupinaRadiovychTlacitek Panel → pnlPanel Při psaní kódu v editoru Delphi po napsání části názvu komponenty a stisku CTRL+SPACE nám budou nabídnuty všechny komponenty, jejichž název začíná zapsaným textem. Takže pokud napíšeme edt a stiskneme CTRL+SPACE, budou nám nabídnuta jména všech editačních políček na formuláři (pochopitelně pokud dodržujeme výše uvedenou konvenci). Události V Delphi nenajdete žádný hlavní program ale pouze několik podprogramů (event-handler, zpracující procedura události), které se vyvolají, pokud nastane určitá událost (event). Událost může vygenerovat například uživatel (stisk tlačítka, pohyb myší, kliknutí myší, vypnutí počítače…) nebo ji může vygenerovat operační systém (po uplynutí určitého času, v pravidelných časových intervalech…). Události pro vybranou komponentu nastavujeme v Object Inspectoru na kartě Events. Každá komponenta má jiné vlastnosti, některé jsou společné. Nastavování vlastností komponent za běhu Tečková notace umožňuje přistupovat k vlastnostem komponent jako by to byly proměnné určitého typu. Syntaxe je JmenoKomponenty.JmenoVlastnosti. Jméno vlastnosti je stejné, jako v Object Inspectoru. Po napsání jména komponenty a tečky nám Delphi po chvíli nabídnou seznam vlastností komponenty (pro urychlení lze stisknout CTRL+SPACE). Co budeme dále potřebovat… Načtení hodnoty uložené v editačním políčku do proměnné – konverzní funkce HodnotaRetezec := edtPolicko.Text Toto bude fungovat pouze pokud je proměnná HodnotaRetezec typu string (textový řetězec), jinak musíme řetězcovou hodnotu uloženou v edtPolicko.Text převést na číslo pomocí konverzní funkce StrToFloat (řetězec na reálné číslo) nebo StrToInt (řetězec na celé číslo). HodnotaRealneCislo := StrToFloat(edtPolicko.Text) HodnotaCeleCislo := StrToInt(edtPolicko.Text) Výpis hodnoty proměnné do komponenty Label Výpis hodnoty řetězcové proměnné je jednoduchý: lblNapis.Caption := HodnotaRezetec Vlastnost Caption je typu string, proto pro výpis číselných hodnot musíme použít konverzní funkce – FloatToStr (reálné číslo na řetězec) nebo IntToStr (celé číslo na řetězec). lblNapis.Caption := FloatToStr(HodnotaRealneCislo) lblNapis.Caption := IntToStr(HodnotaCeleCislo) Příklad KVADRATICKA_ROVNICE Poznámka: Řešení kvadratické rovnice, algoritmus je stejný jako v příkladu KONZOLE_KVADRATICKA_ROVNICE, ale jedná se o „okenní“ aplikaci. Podmíněný příkaz Syntaxe viz dokument [3] – „Jazyk Pascal – úvod“ a [1] – Pascal pro zelenáče (str. 33–34 kap. 3.5, 53–58 kap. 5.1 a 5.2). Složené podmínky, priorita operátorů, tabulky pravdivostních hodnot viz [1] – Pascal pro zelenáče (str. 53–58 kap. 5.1 a 5.2). Příklad POHYB_KOLECKA_1 Poznámka: Kolečko se pohybuje bez ohledu na rozměry formuláře. Příklad POHYB_KOLECKA_2 Poznámka: Pomocí podmínek nepovolíme kolečku opustit formulář, kolečko se na okrajích formuláře zarazí. Rozměry oblasti formuláře, kam lze umísťovat komponenty (tzv. klientská oblast) zjistíme pomocí vlastností ClientWidth a ClientHeight. Vlastnosti Width a Height udávají velikost okna formuláře, tj. včetně titulkového pruhu, okrajů apod. Příklad POHYB_KOLECKA_3 Poznámka: Stejné jako POHYB_KOLECKA_3, ale kolečkem pohybujeme pomocí kláves A, S, D, W – pomocí události OnKeyPress. Klávesnice má funkci autorepeat, takže stačí klávesu držet a kolečko se bude pohybovat. Příklad POHYB_KOLECKA_4 Poznámka: Stejné jako POHYB_KOLECKA_3, ale kolečkem pohybujeme pomocí kurzorových šipek – k tomu je potřeba události OnKeyDown, která na rozdíl od události OnKeyPress dovoluje pomocí virtuálních kódů kláves ošetřit i kurzorové klávesy, funkční klávesy a další. Zkrácené a úplné vyhodnocování booleovských výrazů viz [1] – Pascal pro zelenáče (str. 57 kap. 5.2), v Delphi je ho možno (kromě direktiv překladače {$B+} a {$B-}) zapnout/vypnout v menu Project/Options, karta Compiler, volba Complete boolean eval. Toto nastavení se ukládá pro daný projekt do souboru JMENO_PROJEKTU.CFG. Cyklus s podmínkou na začátku a na konci Syntaxe viz dokument [3] – „Jazyk Pascal – úvod“ a [1] – Pascal pro zelenáče (str. 34–37 kap. 3.6). Příklad KONZOLE_HVEZDICKY_TROJ_1 Poznámka: Pravoúhlý trojúhelník z hvězdiček v textovém režimu. Příklad KONZOLE_HVEZDICKY_TROJ_2 Poznámka: Rovnoramenný trojúhelník z hvězdiček v textovém režimu. Číselné datové typy Dělí se na celočíselné a reálné. Celočíselné jsou buďto se znaménkem (Integer, Shortint, Smallint, Longint, Int64) nebo bez znaménka (Byte, Word, Longword, Cardinal), viz [6] – nápověda k Delphi (klíčové slovo integer). Ze znalosti, kolik daný celočíselný typ zabírá místa v paměti odvodíme rozsah hodnot tohoto typu: integer zabírá 32 bitů, tj. může uchovávat 232 různých hodnoty, a protože je se znaménkem, tak tato čísla budou z intervalu 2 32 232 ; − 1 , tj. 2147483648 , 2147483647 . Horní mez je o 1 menší kvůli 0. 2 2 Pozor, díky omezenému rozsahu nemusí být například sčítání asociativní, viz [1] – Pascal pro zelenáče, str. 40 (kap. 4.1) a 50–52 (kap. 4.5). Reálné datové typy jsou ukládány v semilogaritmickém tvaru, viz [1] – Pascal pro zelenáče, str. 41 (kap. 4.2). Reálná čísla jsou vždy uchovávána na konečný počet desetinných míst nebo jako zlomky – jedná se tedy vždy pouze o čísla racionální!!! V Delphi jde o datové typy Single, Extended, Real48, Double, Comp, Currency, Real, viz [6] – nápověda k Delphi (klíčové slovo real). Pozor, díky zaokrouhlovacím chybám může porovnávání reálných čísel působit problémy, viz [1] – Pascal pro zelenáče, str. 49 (kap. 4.4) – není vhodné testovat reálné hodnoty na rovnost. Datový typ Char Reprezentuje jeden znak. Znaková konstanta je (podobně jako řetězec) uzavřena do apostrofů. Apostrof zapíšeme tak, že ho zdvojíme – tj. '''' je znaková konstanta pro zápis apostrofu. Znaky jsou uspořádány v pořadí podle tzv. ASCII tabulky (American Standard Code for Information Interchange). Jazyk Pascal předpokládá o ASCII tabulce následující – viz [1] – Pascal pro zelenáče, kapitola 6.1 (str. 61). Příklad ASCII_TABULKA_1 Poznámka: Konzolová varianta – výpis ASCII tabulky na textovou konzoli. Příklad ASCII_TABULKA_2 Poznámka: Výpis ASCII tabulky do ListBoxu. Konstanty Pro zpřehlednění kód a zjednodušení případných změn – stačí změnit danou hodnoty pouze na jednom místě, viz [1] – Pascal pro zelenáče, kapitola 4.3 (str. 43–46). Používání symbolických konstant nijak neovlivňuje výsledný exe soubor, protože preprocesor ještě před vlastním překladem nahradí všechny zápisy identifikátorů konstant jejich hodnotami. Typované konstanty Jsou to v podstatě inicializované proměnné (tj. již při deklaraci jim je přiřazena hodnota), viz [1] – Pascal pro zelenáče, kapitola 4.3 (str. 45–46). Pozor, pokud se jedná o lokální konstantu, hodnota je jí přiřazena pouze jednou – ne při každém volání podprogramu. V Delphi je tato nebezpečná možnost standardně vypnuta, lze ji ale povolit – Project/Options, karta Compiler, pole Assignable typed constant. Stejnou funkci má direktiva překladače {$J+} – musí být uvedena na začátku zdrojového kódu. Co dělá preprocesor Preprocesor upraví zdrojový kód ještě před vlastním překladem, například odstraní komentáře a nahradí identifikátory konstant jejich hodnotami. program Pokus; const CISLO = 25; {symbolická konstanta} var A, B: integer; begin A:=CISLO; {inicializace proměnné A} B:=A+CISLO; {výpočet hodnoty proměnné B} end; Zdrojový kód preprocesor program Pokus; var A, B: integer; begin A:=25; B:=A+25; end; Upravený zdrojový kód překladač Strojový kód Pole Deklarace viz [1] – Pascal pro zelenáče, kapitola 9.1 (str. 77–79). Vícerozměrné pole a kompatibilita typů viz [4] – „Pole (vícerozměrné i jednorozměrné)“. Příklad POLE_1 Poznámka: Kopírování obsahu jednoho pole do druhého – kompatibilita typů v praxi. Příklad POLE_2 Poznámka: Ukázka generování náhodných čísel z určitého rozmezí, ukládání do pole a výpis obsah pole do komponenty TListBox. Delphi při standardním nastavení projektu při běhu nekontrolují meze polí, takže následující kód neohlásí chybu při překladu (což je vcelku logické) ale ani při běhu (!):. var pole: array[1..10] of integer; i: integer; begin i:=11; pole[i]:=999; end; Bude však přistupovat k paměti, která mu není vyhrazena – to je hodně nebezpečné a bývá to příčinou těžko odhalitelných chyb („program občas spadne, zatuhne…“). Při běhu se můžeme v lepším případě (tj. víme, že je něco špatně) dočkat následujícího hlášení, v horším případě se bude program chovat nepředvídatelně a nevypíše žádnou chybovou hlášku: Proto je vhodné ve vlastnostech projektu nastavit kontrolu mezí polí za běhu – Project/Options, karta Compiler, pole Range Checking. Je to bezpečnější (každé překročení mezí pole bude hlášeno vyvoláním výjimky), ale mírně to zpomaluje výsledný kód. Vyhledávání v poli (lineární vyhledávání) Viz dokument [5] – „Vyhledávání v poli“. Příklad SPORTKA Poznámka: Program generuje 6 náhodných neopakujících se čísel ze 49. Pro vyhledávání v poli je použito lineární vyhledávání se zarážkou. Komponenta TTimer – časovač V pravidelných intervalech generuje zprávu – vyvolává událost OnTimer. Je to nevizuální komponenta (nezáleží na jejím umístění a nelze nastavovat její velikost). Vlastnost Enabled udává, zda bude tato událost generována (tj. časovač bude aktivní) a ve vlastnosti Interval je časový interval v milisekundách. Příklad HODINY Práce s datumem a časem Datový typ TDateTime je totožný s reálným typem Double, datum a čas se uchovává jako počet dní od 30. 12. 1899 12.00 dopoledne (čas se uchovává jako zlomky dne – 1/24 je jedna hodina, 1/(24*60) jedna minuta…). Díky tomu lze od sebe dva datumy odečíst a dostaneme počet dní mezi nimi. Funkce Now vrací aktuální datum a čas, Date vrací pouze datum, Time pouze čas. Pro převod datumu a času na řetězce slouží funkce DateTimeToStr, funkce DateToStr převádí pouze datum na řetězec, TimeToStr pouze čas. Nejvíce možností pro formátování datumu a času nabízí funkce FormatDateTime. K převodům řetězců na datum a čas slouží funkce StrToDateTime, StrToDate, StrToTime. Více viz [6] – nápověda k Delphi (klíčové slovo date/time routines) Příklad STOPKY_1 Poznámka: Nepřesné stopky – časovač není příliš přesný. Příklad STOPKY_2 Poznámka: Stopky s vylepšenou přesností využívající systémového času. Jednoduché animace pomocí časovače Komponentu TTimer můžeme využít k jednoduché animaci. Výhodou (na rozdíl od použití cyklů) je, že tento způsob neblokuje celou aplikaci, která tam může reagovat na myš, klávesnici apod. Příklad POHYB_KOLECKA_5 Poznámka: Pohyb kolečka pomocí časovače. Klikáním na šipky zvětšujeme rychlost pohybu v daném směru. Kolečko se odráží od okrajů formuláře. Datový typ String (řetězec) – práce s textem Datový typ String slouží pro uložení posloupnosti znaků, mohli bychom ho nahradit polem znaků, tj. deklarací: const MaxDelka = 100; var retezec: array[1..100] of char; Při použití datového typu řetězec určeného pro práci s textem nám Delphi dávají k dispozici další funkce – například pro spojení řetězců, zjištění délky, vyhledávání v řetězci apod. K jednotlivým znakům řetězce přistupujeme podobně jako v prvkům pole – index znaku je uzavřen v hranatých závorkách. V jazyce Pascal je datový typ řetězec ukládán jako pole znaků o maximální délce 255 znaků (Pascalovské řetězce). V nultém indexu pole je uložen znak, jehož ordinální hodnota udává aktuální počet znaků v řetězci. Do závorek je možno při deklaraci uvést maximální možný počet znaků v řetězci (do hranatých závorek, tj. např. String[13]). Tomuto odpovídá v Delphi datový typ ShortString. Delphi umožňují (a upřednostňují) používání i tzv. null-terminated strings (pocházejících z jazyka C) – řetězců ukončených znakem s ordinální hodnotou nula (null, #0), tento znak označuje konec řetězce. Řetězec může mít délku až 230 znaků a zabírá v paměti 4 B až 2 GB. Tomuto odpovídají datové typy AnsiString a WideString. Jak se chová obecný datový typ String určuje nastavení překladače – menu Project/Options, karta Compiler, volba Huge strings: pokud je zapnuto, tak String=AnsiString (standardně), jinak String=ShortString. Lze přepínat i volbami překladače {$H+} zapne Huge strings, a {$H-} vypne tuto volbu. Pozor, v Delphi nemůže řetězcová konstanta obsahovat více jak 255 znaků. Tj. zápis retezec := 'více jak 255 znaků'; je chybný (i když proměnná retezec je typu AnsiString), chybu ohlásí už při překladu („String literals may have at most 255 elements.“). Tuto dlouhou řetězcovou konstantu je nutno rozdělit na dvě a ty spojit (sečíst): retezec := 'první část - méně jak 255 znaků' + 'druhá část - méně jak 255 znaků'; Přetypování Jde vlastně o „násilnou“ změnu typu proměnné – donutím překladač, aby s hodnotou, která je uložena v proměnné určitého typu, pracoval jako s hodnotou jiného typu. Pozor, je to dosti nebezpečné!!! Musím přesně vědět, co dělám, proč to dělám a zda si mohu přetypování dovolit. Přetypování může být bezpečné (překladač provádí základní kontroly, zda takto přetypovat mohu) a nebezpečné (bez jakýchkoli kontrol). Bezpečné přetypování: <proměnná> as <nový typ> Nebezpečné přetypování: <nový typ>(<proměnná>) var znak: char; cislo: byte; begin znak:='A'; // // cislo:=znak; cislo:=znak as byte; cislo:=byte(znak); // // // // // prosté přiřazení - nelze, chyba!!! bezpečné přetypování - nelze, chyba!!! nebezpečné přetypování – lze nyní bude v proměnné cislo hodnota 65, tj. ordinální číslo znaku 'A' end; Použití přetypování pro načítání a výpis hodnot výčtového typu Hodnoty výčtového typu nelze jednoduše načítat ani vypisovat. Při načítání hodnot výčtového typu, které uživatel vybírá z rozbalovacího seznamu (TComboBox), si lze ulehčit práci pomocí přetypování. Musí ale platit, že hodnoty uvedené při deklaraci výčtového typu jsou ve stejném pořadí jako hodnoty v rozbalovacím seznamu. Zde využíváme toho, že symbolické konstanty ve výčtovém typu mají hodnoty 0, 1, 2… podle jejich pořadí při deklaraci. type TStav = (svobodny, zenaty, rozvedeny, vdovec); var stav: TStav; Doporučený postup pomocí case – delší, ale bezpečné: procedure TForm1.ComboBox1Change(Sender: TObject); begin case ComboBox1.ItemIndex of 0: stav:=svobodny; 1: stav:=zenaty; 2: stav:=rozvedeny; 3: stav:=vdovec; end; end; Kratší, ale nebezpečnější postup pomocí přetypování: procedure TForm1.ComboBox1Change(Sender: TObject); begin stav:=TStav(ComboBox1.ItemIndex); end; Podobný přístup můžeme využít při výpisu hodnot uložených v proměnné stav. Připravíme si pole hodnot výčtového typu (tak, jak chceme, aby se v textové podobě vypisovaly) a poté jednoduše pomocí ordinální hodnoty konstanty uložené v proměnné stav toto pole indexujeme. Můžete také využít přetypování proměnné stav na typ byte (to je ale méně bezpečné). const stav_hodnoty: array[0..3] of string = ('svobodný', 'ženatý', 'rozvedený', 'vdovec'); ... ShowMessage(stav_hodnoty[ord(stav)]); // pomocí ordinální hodnoty ShowMessage(stav_hodnoty[byte(stav)]); // pomocí přetypování Příklad VYCTOVY_TYP_PRETYPOVANI Práce se soubory Soubor = abstrakce, kterou nám poskytuje OS; takže pracuji se souborem a nezajímá mě, kde a jak jsou data skutečně fyzicky uložena (na HDD, disketě, flash disku, magnetické pásce…). Práce se souborem má většinou následující fáze: 1. otevření souboru (OS zjistí, zda takový soubor existuje, zda aplikace má právo pracovat s tímto souborem, provede zamčení souboru, aby do něho ostatní aplikace nemohly zapisovat…) 2. zpracování dat (čtení a zápis dat) 3. uzavření souboru (uložení dat z vyrovnávací paměti na disk, uvolnění souboru) Dělení souborů: 1. textové (informace v nich jsou čitelné v textové podobě) 2. binární (data v binární podobě) – typové nebo netypové (amorfní) Jak v Delphi? Příkazy pro práci se soubory v Delphi se mírně liší od příkazů jazyka Turbo Pascal, ale až na pár odlišností je vše uvedeno v [1] – Pascal pro zelenáče, kapitola 15 (str. 143–158). V Delphi pracujeme s proměnnou typu soubor, tu nejprve svážeme s fyzickým souborem na disku pomocí AssignFile(<prom. typu soubor>, 'c:\...'). Poté soubor otevřeme procedurou Reset(<prom. soubor>). typu soubor>) nebo Rewrite(<prom. typu Data do souboru zapisujeme pomocí write(<prom. typu soubor>, <prom1>, <prom2>, …), ze souboru čteme data pomocí read(<prom. typu soubor>, <prom1>, <prom2>, …). Na konec soubor uzavřeme procedurou CloseFile(<prom. typu soubor>). Pro test, zda jsme přičtení na konci souboru používáme funkci EOF(<prom. typu soubor>). Textové soubory Textové soubory jsou čitelné pro „lidi“, data v nich jsou uspořádána do řádků. Řádky jsou odděleny dvojicí znaků CR+LF (ordinální hodnoty 13 a 10). Pro podrobnější informace viz [1] – Pascal pro zelenáče, kapitola 10 (str. 87–99). Deklarace var soubor: TextFile; Reset otevře soubor pro čtení a nastaví čtecí hlavu na začátek, soubor musí existovat. Rewrite založí nový soubor (stávající případně smaže) a otevře ho pro zápis. Append otevře existující soubor pro zápis a nastaví zápisovou hlavu na konec souboru. Procedura writeln(<prom. typu soubor>) zapíše do souboru znak konce souboru – EOLN (který je reprezentován dvojicí znaků CR+LF), procedura readln(<prom. typu soubor>) skočí (nastaví čtecí hlavu) za nejbližší znak EOLN. writeln(<prom. typu soubor>, <prom1>, <prom2>) je zkratkou za write(<prom. typu soubor>, <prom1>); write(<prom. typu soubor>, <prom2>); writeln(<prom. typu soubor>) Funkci EOLN(<prom. typu soubor>) používáme pro testování zda je konec řádku. Textové soubory poskytují pouze sekvenční přístup – čteme jednotlivé znaky od začátku do konce, jeden po druhém. Nemohu tedy v souboru „skákat“.