Převody ======= 1 b = 1 b 1 Kb = 1024 b 1 Mb = 1048576 b 1 Gb = 1073741824 b 1 Tb = 1099511627776 b
* * * * *
1024 1024 1024 1024 1024 .. atd. násobí se vždy 1024
1 1 1 1 1
1 1 1 1 1
B KB MB GB TB
B KB MB GB TB
= = = = =
8 b 8192 b 8388608 b 8589934592 b 8796093022208 b
= = = = =
1 B * 8 b 1024 B * 8 b 1048576 B * 8 b 1073741824 B * 8 b 1099511627776 B * 8 b
největší decimální číslo co se vejde např do 1 B zjistím takto - binárně největší číslo co se vejde do 1 B je 11111111 (každý z 8 bitů je 1) - to převedu na decimální číslo a je to hotovo 255 nebo jednodušeji takto {v podstatě to samé} - 1b může mít dva stavy 0 a 1 - 1B = 8b => 2^8 stavů = 256 - 4B = 4*8b = 32b => 2^32 stavů Struktura programu ================== - hlavička program - klausule uses - definice globálních konstant const - definice typů type - deklarace proměnných var - deklarace procedur a funkcí procedure function - vlastní program begin end. {------------------------------------------------------------------------------} program Prvni uses graph; const MAX = 100; type TPoleIntu = array[0..MAX] of integer; var a : byte; function plusJedna(i : byte): byte; //funkce begin plusJedna = i + 1; end; procedure napisAhoj; (* procedura *) begin writeln('ahoj'); end; begin { hlavni program } a := plusJedna(8); napisAhoj; readln; end. {------------------------------------------------------------------------------} Datové typy =========== - dvě základní skupiny + ordinální + neordinální Ordinální datové typy ===================== - je přesně dána posloupnost hodnot
1 z 35
2 z 35
- jde o všechny celočíselné typy - a typ char - pořadí každé hodnoty je dáno jejím ordinálním číslem - pro práci s ordinálnímy typy existuje 5 základních funkcí Ord() - ordinální hodnota Pred() - předchůdce Succ() - následník High() - maximální hodnota typu Low() - minimální hodnota typu Neordinální datové typy ======================= - všechny reálné datové typy (protože mezi 1 až 2 leží nekonečně prvků) Celočíselné typy (ordinální) ============================ generické --------- Integer (32 bitů signed) - Cardinal (32 bitů unsigned) fundamentální ------------- Shortint (8 bitů signed) - Smallint (16 bitů signed) - Longint (32 bitů signed) - Int64 (64 bitů signed) - Byte (8 bitů unsigned) - Word (16 bitů unsigned) - Longword (32 bitů unsigned) { rozsah např 8 bitového znaménkového typu zjistím takto největší číslo z 8 bitů je binárně 11111111 to je decimálně 255 rozsah bez znaménka je 0..255 tj. 256 hodnot 256 / 2 = 128 rozsah je tedy -128..127 (kvůli 0 uprostřed čísel. osy) } Reálné typy (neordinální) ========================= generické --------- Real (8 bitů signed) fundamentální ------------- Real48 (6 bitů signed) - Single (4 bitů signed) - Double (8 bitů signed) - Extended (10 bitů signed) - Comp (8 bitů signed) - Currency (8 bitů signed) Fundamentální / Generické typy ============================== - typy jsou FUNDAMENTÁLNÍ když je jejich velikost vždy stejná - typy jsou GENERICKÉ když se jejich velikost mění v závislosti na procesoru nebo verzi delphi Znakový typ char ================ - velikost je 8 bitů = 1 byte - lze použít 255 znaků - znak je uzavřen mezi apostrofy 'A' - Ord() vrací ordinální číslo znaku - Chr() převádí ordinální číslo na znak - pokud chceme znak co neni na klávesnici tak ho zapíšeme takto #13 (enter) Logické datové typy
=================== - Boolean (8 bite) - ByteBool (8 bite) - WordBool (16 bite) - Longbool (32 bite) Strukturované typy ================== objekt Object množina Set pole Array záznam Record soubor File třída Class rozhraní Interface Přetypování =========== - implicitní v některých případech se provádí samo - explicitní var y : byte; y := byte('b'); Datový typ Variant ================== - velikost 16 byte = 128 bite - lze do něho přiřadit hodnotu libovolného typu - nevýhodou je velikost a doba zpracování - funkce pro práci s typem variant > vartype() vrací jaký typ proměnné je přiřazen (je to nějaké číslo) > vartostr() převádí variant na řetězec - do typu variant nelze přiřadit pole - pokud cheme do typu variant vytvořit pole musíme použít funkci > vararraycreate() xxx := vararraycreate([0,5],varbyte); {typ promenne by mel byt z TVarData} Inicializované proměnné ======================= - Pascal neinicializuje proměnné na žádnou počáteční hodnotu ta je náhodná - pokud cheme nějakou mít musíme při deklaraci provést i inicializaci - takto nelze inicializovat lokální proměnné uvnitř funkcí var start : integer = 0; jePravda : boolean = false; Konstanty ========= - jejich hodnota již nelze změnit - před svým prvním použitím musí být již definována - typ konstanty je určen podle jejího obsahu const kilometru = 25; spotreba = kilometru * 0.6; znacka = 'BMW'; Operátory ========= - vyhrazený znak s nějakou specifickou funkcí := + * / div mod +
3 z 35
přiřazení součet rozdíl násobení dělení celočíselné dělení zbytek po celočíselném dělení unární kladné znaménko
4 z 35
-
unární záporné znaménko
Logické operátory ================= {tabulka výsledků log operací je na str 52} = rovnost <> nerovnost < menší > větší <= menší rovno >= větší rovno Výrazy ====== - výraz je spojení operátoru a operandů - má nějakou hodnotu - hodnota výrazu lze dále zpracovávát, ale nelze měnit - je to posloupnost proměnných, konstant, operátorů - výraz může stát na pravé straně přiřazení (nikdy však na levé) i := (i+1)/k; //správně (i+1)/k := 10; //NESMYSL Složené výrazy ============== - výrazy mohou uvnitř obsahovat další výrazy - důležitá je pak priorita operátorů - výrazy se vyhodnocují zleva doprava - první se vyhodnocují výrazy v závorkách - pokud neznáme prioritu operátorů tak je lepší uzávorkovat Operátory seřazené podle priority --------------------------------@, not *,/,div,mod,and,shl,shr,as +,-,or,xor =,<>,<,>,<=,>=,in,is Logické výrazy ============== - výsledek je typu Boolean Řídící struktury ================ Podmíněné příkazy ================= if..then..else ============== if a < b then mensi := true //pred else neni nikdy strednik else mensi := false; - pokud ma byt za if nebo else vice prikazu musi byt v bloku begin end; Příkaz case =========== - má funkci přepínače - zjistí vstupní hodnotu a podle ní provede příslušnou větev - pokud má větev víc příkazů musí být uzavřeny mezi begin end; - defaultní věteve se jmenuje else a lze ji vynechat - celý příkaz case je zakončen end; - příkaz case je možné použít jen pro ordinální proměnné case strtoint(edit2.text) of 0 : button10.caption := 'nula';
5 z 35
1 : button10.caption := 'jedna'; 2 : button10.caption := 'dva'; 3 : button10.caption := 'tri'; 4 : button10.caption := 'ctyri'; 5 : button10.caption := 'pet'; else button10.Caption := 'umim jen do 5'; end; Cykly ===== Cyklus For ========== - cyklus s pevným počtem opakování - není vhodné uvnitř cyklu měnit hodnotu čítače i (vede to k chybám) for i := 2 to 10 do begin //prikazy end; for i := 20 downto 10 do begin //prikazy end; Cyklus While ... do ================== - není známo kolikrát cyklus proběhne - cyklus probíhá dokud je podmínka true, při false cyklus končí - cyklus nemusí proběhnout ani jednou - je možná i nekonečná smyčka while true do while i < 100 do begin //příkazy end; Cyklus Repeat ... until ======================= - podmínka je vyhodnocena na konci - cyklus proběhne nejméně jednou - cyklus probíhá dokud je podmínka false (narozdíl od while) - pokud je podmínka splněna true tak cyklus končí - repeat - until nepotřebuje begin a end var x : byte = 0;
//takle se neda inicializovat lokální proměnná ve funkci
repeat inc(x); until x > 5; Řízení cyklů ============ + Continue - ukončí aktuální iteraci a skáče na začátek cyklu - cyklus neopouští + Break - ukončí aktuální iteraci a opustí cyklus - pokračuje se prvním příkazem za cyklem Procedury a Funkce ================== - procedury nevrací hodnotu - funkce vrací hodnotu přes result (mohou být na pravé straně přiřazení)
6 z 35
procedure Pozdrav; //nema zadny parametr a vola se take bez parametru begin ShowMessage('Ahoj Majkle!'); Beep; end; function NasobDvema(x : integer): integer; begin result := x * 2; end; Parametry procedur a funkcí =========================== - pokud žádné parametry nejsou neuvádí se ani () - pokud existuje více než 1 parametr oddělují se pomocí ; - když jsou param. stejneho typu stačí je oddělit čárkou a typ je až za posledním procedure TForm1.viceparam(x, y : integer; s : string); begin showmessage(inttostr(x)); showmessage(inttostr(y)); showmessage(s); end; Parametry předávané hodnotou ============================ - hodnota skutečného parametru se uvnitř fce. nebo proc. nezmění - pracuje se s formálním parametrem - skutečným parametrem může být proměnná nebo konstanta function NasobDvema(x : integer): integer; begin x := x * 2; result := x; end; //volani var x := 5; Showmessage(inttostr(x)); Showmessage(inttostr(NasobDvema(x))); Showmessage(inttostr(x));
// vysledek je 5 //vysledek je 10 // vysledek je 5
Parametry předávané odkazem =========================== - pomocí var v hlavičce fce. je předáván odkaz na skutečný parametr - hodnotu skutečného parametru je možno uvnitř fce. nebo proc. změnit - skutečným parametrem může být pouze proměnná - proc. nebo fce. může mít více parametrů některé odkazem jiné hodnotou procedure TForm1.odkazemIhodnotou(var o : integer; h : integer); begin o := o+10; //skutecny parametr zustane zmenen i po opusteni procedury h := h+10; showmessage(inttostr(o)+' - '+inttostr(h)); end; Konstantní parametry const ========================== - pokud má být parametr v průběhu fce. konstantní uvede se před něj const - tento parametr v průběhu funkce nelze změnit - výhoda je ta že je předávání const paramterů optimalizováno na rychlost procedure konstantiParam(const x : byte); //některé parametry mohou být const a jiné zase ne, na pořadí nezáleží procedure TForm1.Konst(const x : byte; y : byte);
7 z 35
begin //x := x + 100; TOTO NENÍ MOŽNÉ y := y + 100; showmessage(inttostr(x)+' .. '+inttostr(y)); end; Implicitní hodnota parametrů ============================ - umožňuje volat funkci s menším počtem skutečných parametrů než je počet formálních parametrů - v tom případě se pak použije implicitní hodnota - implicitní hodnota(y) musí být vždy jako poslední, pokud je použita nesmí za ní již být normální parametr bez impl. hodnoty procedure TForm1.secti(x : integer; y : integer = 100); begin showmessage(inttostr(x+y)); end; Výstupní parametr out ===================== - umožňuje vracet hodnotu i z procedury - je takto možné vracet hodnotu i z funkce - umožňuje vracet z procedury více hodnot - parametr out slouží jen pro výstup, nepředává se do něj žádná hodnota procedure TForm1.vystup(x, y: integer; out o : integer; out s : string); begin o := x + y; s := 'parametr out'; end; Dopředná deklarace forward ========================== - každá procedura musí být před svým použitím nejprve deklarována - problém může vzniknout když se volají procedury navzájem (v některých případech se to dá vyřešit pořadím deklarací, ale ne vždy!) - forward se uvádí na konec za hlavičku procedury procedure proc2(i : integer); forward; //dopředná deklarace hlavičky procedure proc1(r : real); begin proc2(22);//vola proc2 ktera by bez forward nebyla znama end; procedure proc2(i : integer); begin proc1(856);// vola proc1 ktera je jiz znama end; Lokální proměnné ================ - deklarují se hned za hlavičkou procedury pomocí klíč. slova var - počáteční náhod je náhodná - nelze použít lokální proměnné jako inicializované - pokud má lokální proměnná stejné jméno jako globální, tak ji uvnitř fce překrývá Přetížené procedury overload ============================ - existuje více procedur se stejným názvem - tyto procedury se liší : + typem parametrů + počtem parametrů - pro přetížení procedury se použije klíčové slovo overload - overload je uvedeno za hlavičkou procedury
8 z 35
procedure pretez(i : integer); overload; procedure pretez(s : string); overload; procedure pretez(ch : char); overload; { v typu formular - overload se uvadi jen v hlavicce - v implementacni casti se uz neuvadi - v published casti se smi uvest jen jedan overload hlavicka ostatni musi byt v private nebo public casti } Uživatelem definované typy ========================== Výčtový typ =========== - proměnné tohoto typu mohou nabývat hodnot které jsou uvedeny v definici typu - výčtový typ je typem ordinálním - každá hodnota má své ord číslo - program pracuje s těmito ordinálními čísly (názvy jsou jen pro nás) - ordinální čísla začínají od 0 type auta = (BMW,Mercedes,Audi,Jeep); {nazvy nejsou stringy ale identifikatory} var moje : auta; moje := BMW; //oboji je mozne a funguje to showmessage(inttostr(ord(Audi))); showmessage(inttostr(ord(moje)));
//vzpise 2, Audi ma ord cislo 2 //vypise 0, var moje ma prirazeno BMW
- nelze mít dva typy ktere maji stejny identifikator napriklad type barvyVlajky = (cervena, modra, bila); barvySemaforu = (zelena, oranzova, cervena); //dojde k chybě - cervena by byla obsažena dvakrát a pokaždé s jiným ord číslem - aby se tomu předešlo tak identifikátor obvykle začíná zkratkou svého typu type barvyVlajky = (bvCervena, bvModra, bvBila); barvySemaforu = (bsZelena, bsOranzova, bsCervena); - datový typ Boolean je také výčtový a má definovány dvě hodnoty type Boolean = (False, True); Typ množina set of ================== - může uchovávat hodnoty stejného ordinálního typu (bázový typ) - maximálně však může mít 256 hodnot - rozsah množiny může být v intervalu ord. čísel 0..255 - bázovým typem množiny může být i výčtový typ - množina je vnitřně prezentována takto 0010111001011110011 > 1 znamená že tam prvek je 0 že tam není, pořadí je podle ord. čísla - [] je konstruktor množiny může obsahovat hodnoty oddělené čárkou nebo rozsah .. var mnozina : set of char; mnozina := ['A','X','C']; mnozina := mnozina + ['F','d']; mnozina := ['a'..'x']; - testování na přítomnost prvku v množině if 'F' in mnozina then showmessage('F je v mnozine') else showmessage('F neni v mnozine'); Typ interval .. =============== - interval je souvislou podmnožinou hostitelského typu type velkaPismena = 'A'..'Z';
9 z 35
malaCisla = 0..10; Pole ==== - kolekce daného počtu prvků stejného typu - v pascalu je dolní mez pole libovolná (nemusí být nula) - datový typ pole se definuje takto type denniTrzby = array[1..31] of real; var listopad, prosinec : denniTrzby; - celé pole je možné přiřadit takto prosinec := listopad; - jinax se pracuje normálně pomocí indexů prosinec[10] := 26895.2; - dvoj a vícerozměrné pole se definují takto var dvojPole = array[1..10,100..110] of byte; výhody polí: ------------ uchovávají více hodnot stejného typu v jedné proměnné - snadná manipulace s daty pomocí indexů - možnost zvolit rozsah indexů pole nevýhody polí : --------------- nelze měnit velikost za běhu programu (jde o statickou strukturu) - velikost pole musí být známa v době překladu programu, proto nelze za běhu programu velikost pole nastavit (platí pro původní pascal) Otevřená pole jako parametr funkcí a procedur ============================================= - používá se to pro předání pole do fcí. a procedur - umožňuje to předat do fcí. a procedur různě veliká pole - v deklaraci formálních parametrů není uvedena velikost pole ale pouze jeho typ - velikost pole lze pak uvnitř fce. zjistit pomocí standartních funkcí low() - nejnižší index pole high() - nejvyšší index pole sizeof() - vrací velikost pole v Bytech procedure nulujPole(var pole : array of integer); var i : integer; begin for i := low(pole) to high(pole) do pole[i] := 0; end; - parametr pole je lepší předávat odkazem kvůli úspoře místa (lokální kopie) POZOR: - otevřená pole musí být indexována od 0 - pokud by bylo fci předáno pole indexované jinak než od 0 tak s ním bude pracovat jako by bylo indexováno od nuly takže nemůžem přistupovat na indexy jejich číslem protože by došlo k posunutí, pokud tedy předáváme pole do fce. tak je vhodné ho indexovat od 0 Záznamy ======= - může uchovávat položky různého typu - k položkám se přistupuje pomocí tečkové notace nebo pomocí with - položkou záznamu může být i další záznam
10 z 35
- záznamy lze přiřazovat najednou type auto = record znacka : string; pocetMist : byte; maxRychlost : integer; spotreba : real end; var mojeAuto, tvojeAuto : auto; mojeAuto.znacka := 'BMW'; mojeAuto := tvojeAuto; with tvojeAuto do begin znacka := 'Audi'; pocetMist := 5; maxRychlost := 210; spotreba := 8; end; Soubory ======= Rozdělení souborů podle typu ============================ soubor | +-textový | +-binární | +-typový | +-netypový Binární soubory s udaným typem (typové) var Fin : File of integer; Netypové binární soubory var Fin : File; Textové soubory var Fin : TextFile; (nebo Text) Příkazy pro práci se soubory ============================ Pozor před použitím musí být soubor nejprve otevřen (Reset, Rewrite, Append) Append procedure Append(var F: Text); - otevře textový soubor pro přípis na konec souboru (původní obsah souboru je zachován) AssignFile procedure AssignFile(var F; FileName: string); - spojuje proměnnou typu soubor s existujícím souborem na disku - první parametr je proměnná typu soubor - druhý parametr je skutečné jméno souboru BlockRead procedure BlockRead(var F: File; var Buf; Count: Integer [; var AmtTransferred: Integer]); - čte souvislý blok bitů - používá se pro čtení z netypových souborů - F je netypový soubor - Buf je libovolná proměnná
11 z 35
- Count je požadovaný počet přenesených bloků (čte Count nebo méně bloků) (velikost bloku v bitech je uvedena při otevření souboru Rewrite(Fout,1)) - AmtTransferred je skutečný počet přenesených bloků (skutečný počet přenesených bytů je AmtTransferred * velikost bloku) { obvykle se při otevření stanoví velikost bloku na 1Byte čte a zapisuje se pak SizeOf(Buf) tzn. počet bloků který odpovídá velikosti buffer v bytech } BlockWrite procedure BlockWrite(var f: File; var Buf; Count: Integer [; var AmtTransferred: Integer]); - zapisuje souvislý blok bitů - používá se pro zápis do netypových souborů - zapisuje Count nebo méně bloků - když je celý blok zapsán Count = AmtTransferred ChDir procedure ChDir(S: string); - změní adresář na jiný (nebo chyba) CloseFile procedure CloseFile(var F); - uzavření souboru Eof function Eof(var F): Boolean; //typové a netypové soubory function Eof [ (var F: Text) ]: Boolean; // textové soubory - vrací True pokud jsme na konci souboru Eoln function Eoln [(var F: Text) ]: Boolean; - vrací True pokud jsme na konci řádku textového souboru Erase procedure Erase(var F); - smaže soubor libovolného typu - po použití Erase se soubor již nezavírá (žádné CloseFile) FilePos function FilePos(var F): Longint; - vrací hodnotu aktuální položky v typovém souboru - nelze použít na textový nebo netypový soubor - parametrem je soubor FileSize function FileSize(var F): Integer; - vrací velikost soubor v počtu záznamů v typovém souboru (ne bytů) - nelze použít na textový nebo netypový soubor - parametrem je soubor - soubor musí být otevřen Flush procedure Flush(var F: Text); - vyprázdní buffer při zápisu do textového souboru - zajistí to skutečný zápis do souboru - použitelné jen pro textové soubory GetDir procedure GetDir(D: Byte; var S: string); - vrací aktuální adresář na specifikovaném driveru - D je driver (0 Default, 1 A, 2 B, 3 C) - S je string ve kterém se vrací výsledek IOResult function IOResult: Integer; - vrací status poslední I/O operace a současně ji vynuluje - {$I-} nebezpečná akce {$I+} musí být vypnuta kontrola I/O chyb - pokud je hodnota 0 tak proběhlo vše v pořádku MkDir procedure MkDir(S: string); - vytvoří nový adresář Read procedure Read(F , V1 [, V2,...,Vn ] ); //typové soubory procedure Read( [ var F: Text; ] V1 [, V2,...,Vn ] ); //textové soubory - čtení 1 řádky textového souboru bez odřádkování (čte vždy jen první řádku)
12 z 35
- první parametr je soubor, druhý je sting do kterého se čte Readln procedure Readln([ var F: Text; ] V1 [, V2, ...,Vn ]); - čtení 1 řádky textového souboru - po načtení řádky přejde na další řádku - v konzolové aplikaci při použití bez parametrů čte ze standartního vstupu - první parametr je soubor, druhý parametr je string do kterého se čte řádka Rename procedure Rename(var F; Newname); - změní jméno libovolného souboru Reset procedure Reset(var F [: File; RecSize: Word ] ); - otevře existující soubor - pokud jde o textový soubor je otevřen pro čtení - pokud je soubor již otevřen tak ho uzavře a znovu otevře Rewrite procedure Rewrite(var F: File [; Recsize: Word ] ); - pokud soubor neexistuje tak ho vytvoří a otevře - pokud soubor existuje je smazán a znovu vytvořen a otevřen - pokud jde o textový soubor je otevřen pro zápis (předtím je původní obsah vymazán) RmDir procedure RmDir(S: string); - smaže prázdný adresář (jinak chyba) Seek procedure Seek(var F; N: Longint); - přesune ukazatel na danou pozici v souboru - lze použít jen pro typové a netypové bin. soubory SeekEof function SeekEof [ (var F: Text) ]: Boolean; - pokud jsme na konci textového souboru vrací true - lze použít jen pro textové soubory SeekEoln function SeekEoln [ (var F: Text) ]: Boolean; - pokud jsme na konci řádky textového souboru vrací True - lze použít jen pro textové soubory SetTextBuf procedure SetTextBuf(var F: Text; var Buf [ ; Size: Integer] ); - každá TextFile proměnná má vnitřní 128-bitový buffer pro I/O akce - SetTextBuf umožňuje nastavit jinou (větší velikost bufferu) - F je TextFile, Buf je libovolná proměnná - může se použít ihned po Reset, Rewrite, nebo Append, ale nikdy ji nepoužívejte v uvnitř otevřeného souboru protože by jste ztratili data z bufferu původního Truncate procedure Truncate(var F); - smaže všechny záznamy za aktuální pozicí ukazatele v souboru - lze použít na jakýkoliv typ souboru kromě textového Write procedure Write(F, V1,...,Vn);//typové soubory procedure Write( [var F: Text; ] P1 [ , P2,..., Pn] ); //textové soubory - zapisuje 1 řádek do textového souboru, neodřádkuje (zapisovali bychom stále na první řádek text. souboru za sebe bez odřádkování) Writeln procedure Writeln([ var F: Text; ] P1 [, P2, ...,Pn ] ); - zapíše 1 řádek do textového soubor a odrádkuje - pokud se použije konzolové aplikaci bez parametrů píše na standartní výstup Binární typové soubory ====================== - soubory které obsahují položky předem známého typu - otevření typového souboru type Zaznam = Record jmeno : String[25]; prijmeni : String[25]; id : integer;
13 z 35
end; var Fin : file of Zaznam; var FInt : file of Integer;
//soubor záznamů //soubor integerů
AssignFile(Fin,'C:\data\zamestnanci.dat');
//spojeni prom. a exist. souboru
- vytvoření typového nového souboru Rewrite(Fin); - otevření existujícího typového souboru + smazání původního obsahu Rewrite(Fin); - otevření existujícího typového souboru Reset(Fin); - zavření typového souboru CloseFile(Fin); - zápis a čtení z typového souboru Write(typovySoubor,promennaDanehoTypu) Read(typovySoubor,promennaDanehoTypu) > přečtou nebo zapíšou proměnnou do/ze souboru > lze číst a zapisovat do/z více proměnných {------------------------------------------------------------------------------} procedure TForm1.Button8Click(Sender: TObject); var rec : Zaznam; begin //zápis záznamu do typového souboru rec.jmeno := Edit2.Text; rec.prijmeni := Edit3.Text; rec.id := strtoint(Edit4.Text); AssignFile(TypovySoubor,Edit1.Text); Rewrite(TypovySoubor); Write(TypovySoubor,rec); CloseFile(TypovySoubor); end; {------------------------------------------------------------------------------} procedure TForm1.Button12Click(Sender: TObject); var rec : Zaznam; str : String; begin //vypsání typového souboru do komponenty TMemo AssignFile(TypovySoubor,Edit1.Text); Reset(TypovySoubor); While not Eof(TypovySoubor) do begin Read(TypovySoubor,rec); str := rec.jmeno+';'+rec.prijmeni+';'+inttostr(rec.id); memo1.Lines.Add(str); end; CloseFile(TypovySoubor); end {------------------------------------------------------------------------------} procedure TForm1.Button10Click(Sender: TObject); var rec : zaznam; begin //přidání záznamu na konec typového souboru rec.jmeno := Edit2.Text; rec.prijmeni := Edit3.Text; rec.id := strtoint(Edit4.Text);
14 z 35
AssignFile(TypovySoubor,Edit1.Text); Reset(TypovySoubor); Seek(TypovySoubor,FileSize(TypovySoubor));//nastaveni na konec typ. souboru Write(TypovySoubor,rec); CloseFile(TypovySoubor); end; { Horší způsob jak se dostat na poslední záznam typ. souboru while not Eof(TypovySoubor) do seek(TypovySoubor,filePos(typovySoubor)+1); //dojde až na poslední záznam } {------------------------------------------------------------------------------} - pohyb v typovém souboru FilePos - vrací hodnotu aktuální položky Seek - mění pozici ukazatele v souboru FileSize - vrací počet záznamů v souboru Eof - vrací true když jsme na posledním záznamu > pomocí těchto funkcí se dá libovolně pohybovat v souboru > dají se přepisovat záznamy podobně jako v databázi Binární netypové soubory ======================== - předem není znám typ dat v souboru - čte a zapisuje se vždy soubislý blok bitů o dané velikosti - počet bytů v bloku je specifikován při otevření souboru - velikost bloku se obvykle stanoví na 1 Byte - při čtení a zápisu do souboru se pak jako požadovaný počet zapsaných/čtených bloků uvádí velikost bufferu v Bytech - používá se to hlavně pro rychlé kopírování souborů libovolného typu var Fin : file; //netypovy soubor AssignFile(Fin,'C:\data\zamestnanci.dat');
//spojeni prom. a exist. souboru
- vytvoření nového netypové hosouboru (velikost bloku 1 B) Rewrite(Fin,1); - otevření existujícího netypového souboru + smazání původního obsahu (velikost bloku 1 B) Rewrite(Fin,1); - otevření existujícího netypového souboru (velikost bloku 1 B) Reset(Fin,1); - zavření netypového souboru CloseFile(Fin); - čtení z netypového souboru procedure BlockRead (var Nf: file; var Buffer; PozadovanyPocet: Word [; var SkutPocet: Word]); - čte z netypového souboru Nf - do libovolné proměnné Buffer (obvykle pole) - čte PozadovanyPocet bloků (velikost bloku je stanovena při otevření souboru v Byte, obvykle 1 B) - SkutPocet je počet skutečně přečtených bloků - zápis do netypového souboru procedure BlockWrite (var Nf: file; var Buffer; PozadovanyPocet: Word [; var SkutPocet : Word]); - zapisuje do netypového souboru Nf - z libovolné proměnné Buffer - PozadovanyPocet bloků
15 z 35
- SkutPocet je počet skutečně zapsaných bloků {------------------------------------------------------------------------------} //prekopirovani souboru do noveho po 1000 B procedure TForm1.Button11Click(Sender: TObject); var Buf : array[1..1000] of byte; //prenosovy buffer novySoubor : file; //netypovy soubor pro vystup precteno, zapsano : integer; //pomocne promenne begin Pozor; AssignFile(NetypovySoubor,Edit1.text); //vstupni soubor AssignFile(novySoubor,'novy.dat'); //vystupni soubor Reset(NetypovySoubor,1); //otevre existujici typ. soubor velikost bloku 1 B Rewrite(novySoubor,1); //vytvori novy typ. soubor velikost bloku 1 B showMessage('Velikost Bufferu : '+inttostr(sizeof(Buf))); repeat BlockRead(NetypovySoubor,Buf,sizeOf(Buf),precteno); //cteny soubor, buffer, pocet bloku ke cteni, skutecny pocet prectenych bloku BlockWrite(novySoubor,Buf,precteno,zapsano); //zapisovany soubor, buffer, pocet bloku k zapisu, skutecny pocet zapsanych bloku showmessage('precteno '+inttostr(precteno)+' / zapsano '+inttostr(zapsano)); until (precteno = 0) or (precteno <> zapsano); //dokud je co cist nebo dokud nedojde k chybe (napr. plny disk) CloseFile(NetypovySoubor); //uzavreni obou souboru CloseFile(novySoubor); end; {------------------------------------------------------------------------------} Textové soubory =============== - unita System definuje datový typ TextFile - otevření textového souboru var Fin : TextFile; AssignFile(Fin,'C:\texty\poznamky.txt');
//promenna typu soubor //spojeni promenne a exist. souboru
- u textového souboru se musí určit k jakému účelu je otevírán - vytvoření nového souboru Rewrite(Fin); - otevření existujícího textového souboru + smazání původního obsahu Rewrite(Fin); - otevření textového souboru pro přidání na konec Append(Fin); - otevření textového souboru pro čtení Reset(Fin); - zavření textového soubouru CloseFile(Fin); - čtení textového souboru Read, Readln - zápis do textového souboru Write, Writeln - pohyb v textovém souboru (pouze sekvenční) Eof, Eoln, SeekEof, SeekEoln - vyprázdnění textového buffer
16 z 35
Flush procedure TForm1.Button4Click(Sender: TObject); var i : integer; begin //přidání textu do textového soubor z komponenty TMemo AssignFile(TextovySoubor,Edit1.Text); Append(TextovySoubor); for i := 0 to memo1.Lines.Count do Writeln(TextovySoubor,memo1.lines[i]); CloseFile(TextovySoubor); end; procedure TForm1.Button2Click(Sender: TObject); var str : String; begin //vypsání obsahu textového souboru do komponenty TMemo AssignFile(TextovySoubor,Edit1.Text); Reset(TextovySoubor); while not Eof(TextovySoubor) do begin Readln(TextovySoubor,str); memo1.Lines.Add(str); end; CloseFile(TextovySoubor); end; - pro textový soubor nejde použít FileSize() pro zjištění velikosti - pokud chceme zjistit velikost otevřeme textový soubor jako typový soubor s typem file of Char; FileSize() pak vrátí počet znaků v souboru - velikost typoveho souboru v B = FileSize(TypProText)*SizeOf(Char) Ukazatele ========= type poiNaInt = ^integer; - adresa proměnné se dá zjistit pomocí addr(jmenoPromenne) @jmenoPromenne var pni, pnj : poiNaInt; i,j : integer; pni := addr(i); pnj := @j;
//prirazeni adres
pni^ := 33; pnj^ := 100;
//prirazeni hodnot
Dynamicky alokované proměnné ============================ - vytvářejí a zanikají za běhu programu - lze k nim přistupovat pouze pomocí pointerů - k vytvoření slouží New, GetMem - k uvolnění slouží Dispose, FreeMem New - Dispose ============= - podle typu rozpoznají kolik paměti se má alokovat var ptr : ^integer; new(ptr);
//alokuje pamet
ptr^ := 123;
//prirazeni hodnoty
17 z 35
showmessage('pointer ptr^ ma hodnotu : '+inttostr(ptr^)); dispose(ptr); //uvolnuje pamet ptr := nil;
//pro jistotu aby neukazovala na pamet co uz neni alokovana
GetMem - FreeMem ================ - musí se zadat kolik paměti chceme alokovat i uvolnit var ptr : ^integer; GetMem(ptr,SizeOf(integer));
//alokuje pamet
ptr^ := 256;
//prirazeni hodnoty
showmessage('pointer ptr^ ma hodnotu : '+inttostr(ptr^)); FreeMem(ptr,SizeOf(integer)); //uvolnuje pamet ptr := nil; Dynamická pole ============== - dynamické pole se deklaruje bez velikosti - POZOR u dynamických polí není kontrolováno překročení rozsahu pole - indexuje se vždy od 0 - velikost pole se nastavuje pomocí procedury SetLength() - dají se použít funkce High(), Low() - SizeOf() vrací velikostPole * velikostJednePolozky - pokud provedu s dynamickými poli přiřazení A := B; tak se nezkopíruje obsah pole B do A ale pouze se přiřadí ukazatel na rozdíl od statických polí - velikost pole se dá zvětšit pomocí SetLength() - velikost pole se dá změnšit pomocí copy() - dynamické pole se zruší když je přiřazeno nil (paměť je uvolněna) var pole : array of integer; //neni udana velikost pole setLength(pole,15); //15 prvku indexovano od nuly showmessage(inttostr(low(pole))+' .. '+inttostr(high(pole))); //0 .. 14 pole := nil; //uvolneni pole showmessage(inttostr(low(pole))+' .. '+inttostr(high(pole))); //0 .. -1 setLength(pole,100); showmessage(inttostr(low(pole))+' .. '+inttostr(high(pole))); //0 .. 99 pole := copy(pole,20,10); //oriznuti pole od indexu 20 10 prvku showmessage(inttostr(low(pole))+' .. '+inttostr(high(pole))); //0 ..9 pole := nil; //uvolneni pole Řetězce ======= - je to pole znaků, k jednotlivým znakům se dá přistupovat pomocí[] - řetězce se dají spojovat pomocí operátoru + - délka řetězce se dá zjistit pomocí funkc Length() - do řetězců se přiřazují 'řetězcové konstanty uzavřené do apostrofů' - existují 3 typy řetězců + ShortString (256 znaků) + AnsiString (libovolně dlouhé) + WideString - normálně se ale takto nedeklarují s vyjímkou WideString - delphi sami rozpoznají který se má použít podle velikosti var str : string; delka : integer;
18 z 35
str := 'ahoj majkle'; delka := length(str);
//11
ShortString =========== - pouze pro zpětnou kompatibilitu s 16-bitovou verzí delphi - statické pole znaků s délkou 256 - dá se do něj uložit 255 znaků - toto pole má konstantní velikost 256 pro libovolný řetězec např. 'ahoj' - informace o skutečné délce řetězce je na indexu 0 - pokud chci šetřit míst mohu například mít řetězec jen o 10 znacích var kratkyRetezec = string[10]; AnsiString ========== - struktura + 4 Byte délka řetězce + 4 Byte počítadlo odkazů + vlastní řetězec - dynamicky alokovaný řetězec - v paměti zabírá jen místo skutečně potřebné pro řetězec - jde o ukazatelovou proměnnou - pokud je třeba větší paměť je celý řetězec automaticky realokován - pokud je počet odkazů na řetězec nulový tak je automaticky uvolněn z paměti - funguje podobně jako dynamické pole - odstraníme ho z paměti přiřazením prázdného řetězce '' var str : string; setLength(str,20); //nastavení délky řetězce WideString ========== - podobný typu AnsiString - jedotlivé znaky jsou 16-bitové znaky kódované Unicode Nulou ukončené řetězce ====================== - používají se když cheme použít WinApi - typ Pchar je ukazatel na nulou ukončený řetězec - je kompatibilní s AnsiString a lze přetypovat na Pchar var s : string; p : Pchar; s := 'retezec'; p := Pchar(s); Unity ===== Struktura unity - hlavička Unit NazevUnity; (měla by být shodná s názvem souboru) - rozhraní Interface obsahuje > hlavičky veřejných procedur a funkcí > deklarace veřejných proměnných a typů - vlastní kód Implementation obsahuje > definuje procedury a fce uvedené v Interface > definuje neveřejné procedury a funkce - inicializační část Initialization > tato část je nepovinná > obsahuje kód co se má provést před použitím jednotky (např nastavení počátečních stavů proměnných) - konečná část Finalization > není povinná > lze ji použít jen společně s Initialization - konec, jednotka je ukončena end.
19 z 35
- Interface, Implementation, Initialization, Finalization slouží jako přepínače - pokud chceme unitu používat musíme ji zařadit do uses {------------------------------------------------------------------------------} Unit test1; Interface uses SysUtils; var str : string; //verejna promenna function kratDva(int : integer) : integer;
//verejna funkce
Implementation uses Dialogs; //pro showmessage() procedure pozdrav; //neverejna funkce da se pouzit pouze uvnitr unity begin showmessage('AHOJ'); end; var int : ^integer; //neverejna promenna function kratDva(int : integer) : integer; //definice tela verejna funkce begin pozdarav; result := int * 2; end; Initialization //provede se pred pouzitim unity new(int); //vytvoreni promenne int^ := 10; //nastaveni promenne Finalization dispose(int);
//provede se pri ukonceni //uvolneni promenne
end. {------------------------------------------------------------------------------} Kruhové reference ================= - mohou nastat pokud unity vzájemně využívají jedna druhou - aby nedošlo ke kruhovému odkazu musíme pak uses přesunout z části interface do části implementation Objektově Orientované Programování ================================== Třída Class =========== - proměnné uvnitř třídy se nazývají atributy - procedury a funkce se nazývají metody - jména tříd se obvkle začínají písmenem T Vytvoření objektu Konstruktor Create ==================================== - k vytvoření objektu slouží konstruktor (constructor) - konstruktor vytváří a inicializuje objekt - deklarace konstruktoru nespecifikuje žádnou návratovou hodnotu - když je však konstruktor volán vrací však referenci na vytvořený objekt - každá třída má konstruktor který se jmenuje Create (zděděno z TObject) - standartní konstruktor nastavuje objekty takto : > ordinální atributy na 0 > pointery a reference na objekty na nil > string na '' prázdný řetězec - lze mít víc přetížených (overload) konstruktorů - standartní konstruktor pouze alokuje paměť, ostatní akce si musíme naprogramovat sami - uvnitř konstruktoru lze volat konstruktor rodiče pomocí inherited takto
20 z 35
inherited Create({parametry konstruktoru rodiče}) - první akcí uvnitř zděděného konstruktoru je obvykle volání konstruktoru rodiče - konstruktor může být virtual - pokud redefinujeme override konstruktor tak jako první akci musí volat konstruktor rodiče inherited Create()
TBod = Class private x, y : integer; public constructor.Create(x : integer = 0; y : integer = 0); destructor Destroy; end; constructor TBod.Create(x : integer = 0; y : integer = 0); begin self.x := x; self.y := y; end; var F : TBod; F := TBod.Create(10,6); F.Free;
//deklarace referencni promenne na TBod //vznik instance tridy TBod //uvolneni objektu z pameti
Použití self při vytváření instance třídy ========================================= - self označuje vlastníka nebo instanci třídy která volá metodu - nebo vlastní objekt nad kterým je metoda vyvolána - Sender se dá pak v metodě dál zpracovat (např. podle toho co je sender) procedure TForm1.Button26Click(Sender: TObject); var index : integer; begin index := 0; //pouziti self pri vytvoreni instance tridy MainMenu1.Items[0].Insert(index,TMenuItem.Create(self)); MainMenu1.Items[0][index].Caption := 'Nova Polozka'; showmessage(inttostr(MainMenu1.Items[0].Count)); end; Instance třídy ============== - pro práci s objekty se používá referenční model - proměnná typu třída se nazývá instance třídy - deklarací proměnné typu třída nevzniká instance (je to jen reference) - instance třídy vzniká až po volání konstruktoru Create - instance třídy zaniká voláním destruktor Free nebo Destroy - reference je na stacku - instance je na heapu Zrušení objektu Destruktor Destroy ================================== - každá třída obsahuje automaticky destruktor (destructor) Free - desktruktor slouží k uvolnění (dealokaci) objektu z paměti - Free + uvolňuje instanci z paměťi s testem na její existenci (neuvolní neexistující) + otestuje zda instance existuje + pokud instance existuje volá proceduru Destroy - Destroy + uvoní instanci z paměti okamžitě bez jakéhokoliv testu - pro uvolňování instance z paměti je lepší volat Free - třída může mít i více destruktorů ale je správné redefinovat stanartní Destroy a nedeklarovat další destruktory
21 z 35
- poslední akcí destruktoru by mělo být volání zděděného destruktoru destructor TBod.Destroy; override; begin //nealokovali jsme dynamickou pamet takze bychom destruktor nemuseli //vubec vytvaret, toto je jen pro ukazku inherited Destroy; end; - pokud je během vytváření objektu vyvolána vyjímka je automaticky volán Free destruktor a uvolní nedokončený objekt (Free kvůli testování) Metody objektu ============== - uvnitř objektu jsou pouze forward deklarace hlaviček metod - metody jsou definovány až v části implementation unity - klíčová slova (overload, override, abstract, virtual, dynamic, reintroduce) se uvádějí jen u hlaviček metod Použití self v metodách ======================= - self odkazuje na aktuální instanci objektu - lze to využí když se formální parametry metody jemnují stejně jako atributy objektu (rozliší se tím co je co) procedure TBod.SetXY(x, y : integer); begin self.x := x; self.y := y; //třída TBod má private atributy x, y : integer; end; Přístupová práva uvnitř objektu =============================== Private - atributy a metody private se dají použít jen v unitě kde jsou deklarovány - v ostatních unitách jsou neviditelné (i když by jsme byli v třídě která je dědicem) - pokud není uveden žádný modifikátor jsou automaticky public Protected - atributy a metody protected je přístupný jen vlastní třídě a potomků - takto je přístupný i v ostatních unitách Published - published mohou být pouze atributy typu class nebo interface a metody - tyto atributy a metody jsou veřejné - rozdíl je jen že některé tyto vlastnosti objektu mohou být zveřejňovány v inspektoru objektů Public - veřejné metody a atributy, jsou přístupné volně kdekoliv Dědičnost ========= - umožňuje odvozování nových tříd od stávajících (větší specializace) - všechny původní atributy a metody zůstanou zachovány, nebo se mohou překrýt, přetížit či redefinovat - pokud není uveden rodič třídy dědí se z TObject, ta obsahuje základní metody - lze vytvářet i celou hierarchii objektů co ze sebe navzájem dědí type TBod2D = Class
//dědí z TObject
type TBod3D = Class(TBod)
//dědí z TBod
- pokud se nějaká metoda liší od původní jen málo můžeme původní metodu rodiče vyvolat pomocí klíčového slova inherited
constructor TBod3D.Create(x,y,z :integer); begin inherited Create(x,y); {vola konstruktor predka se dvema parametry} self.z := z; {doplneni vlastniho kodu} end; Polymorfismus ============= - do proměnné předka lze přiřadit proměnnou potomka (instanci předka lze nahradit instancí potomka ale ne naopak) - pokud jsou metody virtual nebo dynamic tak jde o pozdní vazbu a jaká metoda (z předka nebo potomka) bude použita se určí až podle skutečného typu instance za běhu programu - metody které nejsou takto označeny používají statickou vazbu, tzn. již v době překladu je napevno určeno typem referenční proměnné jaké metody se budou volat a za běhu programu se s tím nedá nic dělat Statické metody =============== - jejich volání je nejrychlejší nemusí se nic zjišťovat ani určovat, metoda která se bude volat je určena již v době překladu programu - pokud je v potomkovi nadeklarována metoda se shodnou hlavičkou tak metodu rodiče prostě překryje - tyto metody používají statické vazby Virtuální metody ================ - jejich volání je pomalejší než u statických ale rychlejší než u dynamických - oproti dynamickým metodám jsou optimalizovány na rychlost - v rodiči se použije klíčové slovo virtual; - v dědici se použije klíčové slovo override; - tyto metody používají pozdní vazby - metoda je v dědicovi reimplementována Dynamické metody ================ - jejich volání je pomalejší než u virtuálních metod - oproti virtuálním metodám jsou optimalizovány na velikost kódu (úspora paměti) - v rodiči se použije klíčové slovo dynamic; - v dědici se použije klíčové slovo override; - tyto metody používají pozdní vazby - metoda je v dědicovi reimplementována Abstraktní metody ================= - tato metoda není v rodiči implementována má určenou pouze hlavičku - její implementace je ponechána až na dědice třídy - abstract metoda nesmí být volána v rodiči (dojde k chybě protože nemá tělo) - abstraktní metoda si nevynucuje svoji implementaci v dědici (narozdíl od C++) - v rodiči se použijí klíčová slova virtual; abstract; - dědici se použije klíčové slov override; Přetížení virtuální metody ========================== - pro přetížení virtual metody se nemůže použít klíčové slovo override ani samotné overload - v rodiči se použije klíčové slovo virtual; - v dědici musí se použít dvojice klíčových slov reintroduce; overload; type TPoly1 = Class private x : integer; public constructor Create(x : integer); destructor Destroy; function getX : integer;
22 z 35
{staticka metoda}
23 z 35
procedure procedure procedure procedure end;
getXY(out x, y : integer); virtual; abstract; {abstraktni metoda} tellName; virtual; {virtualni metoda} pozdrav(const s : string); dynamic; {dynamicka metoda} echo(const int : integer); virtual;
type TPoly2 = Class(TPoly1) private x, y : integer; public constructor Create(x, y : integer); destructor Destroy; {staticka metoda prekryva puvodni metodu rodice} function getX : integer; {definice abstraktni metody v dedici} procedure getXY(out x, y : integer); override; {reimplementace virtualni metody} procedure tellName; override; {reimplementace dynamicke metody} procedure pozdrav(const s : string); override; {pretizeni virtualni metody} procedure echo(const chr : char); reintroduce; overload; {pretizeni virtualni metody} procedure echo(const str : string); reintroduce; overload; end; Práce s typem třídy as, is ========================== - polymorfismus umožňuje přiřadit instanci potomka do reference na předka, k určení typu instance se použije operátor is - použitím operátoru is se dá zabránit použití metody nad objektem který ji nemá definovanou if F is TBod3D then F.setXY(1,6); - as umožňuje přetypovat objekt (pokud to ale není možné je vyvolána vyjímka) (F as TBod3D).setXY(8,6); //nebo with Sender as TButton do begin Caption := '&Ok'; OnClick := OkClick; end; - přetypování je někdy nutné například když je návratový typ TObject Knihovna Vizuálních Komponent - VCL =================================== - program v Delphi se skládá z komponent - komponenta je definována jako objektová třída v jazyce Object Pascal - umístěním komponenty na formulář je vytvořena instance této třídy - všechny komponenty jsou uloženy v knihovně vizuálních komponent VCL Hierarchie VCL ============== TObject | +---TPresident | +---TComponent | +---nevizuální komponenty | +---TControl |
24 z 35
+---TGraphicControl(nejsou spravován Win. nelze zaměřit) | +---TWinControl(jsou spravovány Win. lze zaměřit) Vlastnosti komponent ==================== - existují dva typy vlastností - všechny vlastnosti je však možné upravovat za běhu programu - Vlastnosti přístupné v době návrhu > dají se upravovat v inspektoru objektů - Vlastnosti přístupné pouze za běhu programu > nejsou přístupné v inspektoru objektů a dají se nastavit za běhu programu
Další objekty patřící do VCL ============================ - jsou to specifické třídy které jsou např. vlastnostmi dalších objektů nebo je možné je přímo využívat v aplikacích - lze je rozdělit do 5 základních skupin + Grafické objekty > TBitmap, TBursh, TCanvas, TFont, TGraphic, TGraphicObjekt, TIcon, TMetaFile, TPen, TPicture + Souborové objekty / Streamy > TBlobStream, TFileStream, THandleStream, TIniFile, TMemoryStream, TFilter, TReader, TWriter + Kolekce > TList, TStrings, TStringList, TColection + Třídy pro programování COM aplikací + Vyjímky {******************************************************************************} Zprávy ve Windows ================= type TMsg = packed record hwnd: HWND; //handle okna pro které je zpráva zaslána message: UINT; //konstanta s typem zprávy wParam: WPARAM; //může obsahovat nějakou hodnotu co souvisí se zprávou lParam: LPARAM; //může obsahovat index nebo pointer (4B lze přetypovat) time: DWORD; pt: TPoint; //pozice kurzoru myši při zaslání zprávy end; - do Application.OnMessage() se předává TMsg {zpráva předávaná z windows do aplikace má typ TMsg} - do ostatní procedur reagujících na zprávy se předává TMessage {zapouzdřená zpráva windows pro Delphi je typu TMessage} Události z Windows jako vlastnosti komponent ============================================ - události jsou v Delphi definovány jako vlastnosti komponent - každé události je přiřazena obslužná metoda - je možné několika událostem přiřadit stejnou obslužnou metodu - ### cheme-li upravit obslužnou metodu nějaké události, vytvoříme potomka třídy komponenty a upravíme její obslužnou metodu Delegování ========== - zjednodušuje práci s komponentami (### nemusí se vytvářet potomci komponent) - obsluhou událostí komponent je pověřen jejich vlstník (většinou Formulář) - je-li generována událost komponenty je obsloužena metodou ze třídy formuláře na kterém je komponenta umístěna
25 z 35
Systém zasílání zpráv ve Windows ******************************** - zprávu můžeme poslat libovolnému objektu který je potomkem TWinControl - delphi zapouzdřují systém zpráv Windows v knihovně komponent a vytvářejí typ TMessage (který představuje zprávu Windows) - TMessage je typ parametru který je předáván do WndProc - TMessage reprezentuje zprávy Windows v WndProc a ostatních metodách - zprávy se předávají odkazem (var) type TMessage = record Msg: Cardinal; case Integer of 0: ( WParam: Longint; //obsahuje WparamLo a WparamHi (old style names) LParam: Longint; Result: Longint); 1: ( WParamLo: Word; WParamHi: Word; LParamLo: Word; LParamHi: Word; ResultLo: Word; ResultHi: Word); end; Vytvoření vlastního typu zprávy ******************************* - pro vytvoření vlastní uživatelské zprávy slouží WM_USER - je vhodné používat WM_USER + 100 a výše do 7FFF const WM_MAJKL = WM_USER + 1969; Odeslání vlastní zprávy *********************** - handle je vlastnost z TApplication - property Handle: HWND; - ukazuje na handle rodičovského okna (vlastní aplikace) - těmito způsoby můžeme poslat libovolnou zprávu např. WM_PAINT - pokud bychmo chtěli zaslat zprávu jiné aplikaci museli bychom znát její HWND a použít API funkce SendMessage nebo PostMessage //v helpu je k tomu cosi v Calling conventions SendMessage(handle,WM_MAJKL,0,0); > zajistí předání zprávy do aplikace a ta je pozastavena až do vyřízení zprávy > předává zprávu rovnou do WindowProc > takto odeslanou zprávu nelze zachytit v Application.OnMessage function Perform(Msg: Cardinal; WParam, LParam: Longint): Longint; > použitelné jen v Delphi > používáme ji pokud posíláme zprávu vlastní aplikaci > vynechá Win. frontu zpráv a předá zprávu rovnou do WindowProc ke zpracování > takto odeslanou zprávu nelze zachytit v Application.OnMessage PostMessage(handle,WM_MAJKL,0,0); > umístí zprávu do fronty zpráv a pokračuje dál v práci (na nic nečeká) Postup při zpracování zprávy **************************** - v systému nastane událost (například kliknutí myši) - systém událost převede na příslušnou zprávu a umístí ji do fornoty zpráv aplikace - aplikace získá zprávu z fronty zpráv a umístí ji do záznamu typu TMsg - aplikace předá zprávu patřičné proceduře okna (WindowProc) - procedura okna provede akci jako odezvu na příslušnou zprávu Pořadí předávání zpráv v aplikaci *********************************
26 z 35
I. II. III. IV.
Aplikace.OnMessage Procedura okna WndProc Vlastní Procedura Zprávy DefaultHandler
//může být přeskočena
//pokud zpráva není zpracována jinde
I. OnMessage ************ TApplication.OnMessage type TMessageEvent = procedure (var Msg: TMsg; var Handled: Boolean) of object; property OnMessage: TMessageEvent; -
-
OnMessage je procedurální typ shodný s TMessageEvent cokoliv co má reagovat na zprávy musí být kompatibilní s TMessageEvent parametry jsou předávány odkazem událost nastane když aplikace dostane zprávu z Windows slouží k zachycení všech Win. zpráv poslaných do celých Win. v aplikaci vytvoření OnMessage handleru v aplikaci dovolí ostatním handlerům reagovat na i na jiné zprávy než jsou deklarovány pro TApplication když aplikace nemá specifický handler pro příchozí zprávu tak je zpráva odeslána do okna pro které byla určená a Windows zpracují zprávu OnMessage ukazuje (referencuje) na metodu která zpracovává příchozí Win. zprávy parametr Msg indentifikuje typ zprávy parametr Handled rozhoduje o tom zda byla zpráva zpracována či ne, pokud nastavíme TRUE znamená to že zpráva byla kompletně zpracována a zabrání to předání zprávy dál k (dalšímu) normálnímu zpracování do procedury okna WndProc OnMessage přijímá jen zprávy odeslané do fronty zpráv pomocí PostMessage() nepřijímá ty které jsou poslány přímo WinApi funkcí SendMessage()
//hlavička procedure OnAppMessage(var msg:TMsg; var Handled: Boolean); //přiřazení procedure TForm1.FormCreate(Sender: TObject); begin Application.OnMessage := OnAppMessage; //do události OnMessage přiřadíme vlastní metodu pro zpracování zpráv end; //implementace procedure TForm1.OnAppMessage(var msg:TMsg; var Handled: Boolean); begin if msg.message = WM_MAJKL then begin showmessage ('Majklovo Message prijata v Aplikaci'); Handled := False; //false znamená že zpráva bude předána dál ke zpracování do procedury okna //true by znamenalo že zpráva byla zpracována na úrovni aplikace end; end; WindowProc ********** TControl.WindowProc type TWndMethod = procedure(var Message: TMessage) of object; property WindowProc: TWndMethod; > ukazuje na proceduru okna která reaguje na zaslané zprávy > procedura okna přebírá zprávy z fronty zpráv a reaguje na ně > je to callback funkce kterou vola Windows a do Windows vraci hodnotu - místo úpravy WindowProc se overriduje WndProc - WindowProc proc je nejprve nastavena na proceduru WndProc II. WndProc - Procedura Okna **************************** TWinControl.WndProc (TObject dědí v hierarchii také z TWinControl) procedure WndProc(var Message: TMessage); override;
27 z 35
- umožňuje specifickou odezvu objektu na zprávu - override (redefinice) změní původní Windows handler pro zpracování zprávy - vlastnost TWinControl.WindowProc je inicializována tak že ukazuje (referencuje) proceduru WndProc() - když redefinujeme WndProc způsobíme specifickou reakci na zprávy, na konci je třeba volat inherited WndProc()kvůli odeslání všech nezpracovaných zpráv //hlavička procedure WndProc (var msg: TMessage);override; //implementace procedure TForm1.WndProc(var msg : TMessage); begin if msg.Msg = WM_MAJKL then begin showmessage('Majklovo zprava prijata v procedura okna WndProc'); end; inherited WndProc(msg); //bez inherited to nefunguje a zprave se nepreda dal do procedury zpravy end; III. Procedura zprávy ********************* - je to uživatelem vytvořená procedura která reaguje na příslušnou zprávu //hlavička procedure ProceduraZpravy(var msg : TMessage); message WM_MAJKL; //implementace procedure TForm1.ProceduraZpravy(var msg : TMessage); begin if msg.msg = WM_MAJKL then begin showmessage('Majklovo Message prijata v procedure zpravy'); end; inherited; //bez tohodle inherited se to neprada dal do defaultHandleru end; IV. DefaultHandler ****************** TObject.DefaultHandler procedure DefaultHandler(var Message); virtual; - parametr funkce DefaultHandler je netypový a v implementaci se musí přetypovat na typ TMessage - defaultHandler je volán pomocí Dispatch když není možné najít metodu pro konkrétní zprávu - DefaultHandler zpracuje všechny zpávy pro které objekt nemá specifický handler - třídy odvozené od TObject které zpracovávají zprávy obvykle definují metody DefaultHandler podle toho jaký typ zprávy zpracovávají - volání inherited v nějaké metodě která zpracovává zprávu způsobí volání předkovy DefaultHandler metody jen v případě že předek nespecifikuje proceduru zprávy pro konkrétní zprávu která je zpracovávána - jinak volání inherited způsobí volání specifického handleru pro danou zprávu //hlavička procedure DefaultHandler(var msg);override; //implementace procedure TForm1.DefaultHandler(var msg); begin if TMessage(msg).msg = WM_MAJKL then begin showmessage('Majklovo Message prijata v DefaultHandler'); end; inherited DefaultHandler(msg);
28 z 35
end; {******************************************************************************} Vyjímky ======= - vyjímka je objektová třída která je potomkem Exception (Unit SysUtils) - pokud se v programu objeví chyba je generována příslušná vyjímka - pro každý typ chyby je definována vlastní vyjímka Obsluha vyjímek =============== try .. except ------------- slouží k zachycení a ošetření vyjímky try //kód u kterého se předpokládá že by mohl vyvolat vyjímku except //kód který bude proveden v případě vyvolání vyjímky end; - program pak normálna pokračuje za end; které ukončuje blok except - pokud v bloku try mohou nastat různé vyjímky můžeme pak v bloku except podle toho jaká vyjímka nastane reagovat - k rozlišení typu vyjímky slouží příkaz on .. do .. [else] - použití else v bloku except znamená že se postaráme o všechny vyjímky v programu což většinou není vhodné řešení - pozor kód v bloku try za první chybou se již neprovede protože se skáče rovnou do bloku except - za on .. do následuje 1 příkaz nebo blok příkazů mezi begin end; - pokud použijeme on .. do pro testování jedné vyjímky musíme on .. do použít pro všechny ostatní vyjímky a nebo musíme použít else try P1 := TPoly1.Create(33); P1.getXY(lx,ly); //volani abstraktni metody zpusobi chybu showmessage('pred timto prikazem je chyba'); //tento kod se jiz neprovede P2.tellName; //pristup do pameti ktera neni alokovana (P1 as TPoly2).tellName; //spatne pretypovani zpusobi chybu except //musime vypsat na ktere typy vyjimek budeme reagovat on EAbstractError do showmessage('pokus o volani abstraktni metody'); on EAccessViolation do showmessage('pokus o pristup do nealokovane pameti') else showmessage('nejaka jina chyba'); //showmessage('tohle uz nejde'); //tohle jiz neni mozne zapsat chyba end; //zde se pokracuje po provedeni bloku try nebo except showmessage('kod po provedeni bloku exept'); P1.Free; try .. finally -------------- kód uvedený v bloku finally se provede VŽDY i když je vyvolána vyjímka - pro ošetření vyjímky a použití bloku finally musíme použít vnořený try try try //kód co může vyvolat vyjímku except //ošetření vyjímky end; finally //kód který se provede vždy i když dojde k vyjímce end;
29 z 35
- pořadí except a finally lze prohodit (efekt je obdobný) - pokud vyjímka naní zpracována uvnitř bloku finally předá se nadřazenému bloku except který ji ošetří - pokud vyjímka není zpracována v žádném nadřazeném bloku je předána ke zprcování delphi try try //kód co může vyvolat vyjímku finally //kód který se provede vždy i když dojde k vyjímce end; except //ošetření vyjímky end; {------------------------------------------------------------------------------} procedure TForm1.Button18Click(Sender: TObject); var lx, ly : integer; begin try try P1 := TPoly1.Create(33); P1.getXY(lx,ly); //volani abstraktni metody zpusobi chybu P1.tellName; //pokud dojde k vyjimce tento kod se neprovede except showmessage('except osetreni vyjimky'); end; finally showmessage('finally kod se provede vzdy i kdyz dojde k vyjimce'); P1.tellName; end; showmessage('konec testu'); P1.Free; end; {------------------------------------------------------------------------------} Opětovné vyvolání vyjímky ========================= - libovolnou vyjímku lze vyvolat pomocí příkazu raise - je to dobré například když chceme aby tuto vyjímku obsloužil znovu ještě nadřazený blok procedure TForm1.Button20Click(Sender: TObject); var lx, ly : integer; begin try P1 := TPoly1.Create(33); P1.getXY(lx,ly); //volani abstraktni metody zpusobi chybu except showmessage('chyba volani abstraktni metody'); raise; //znovuvyvolani vyjimky EAbstractError, je predana nadraz. bloku end; end; - vyjímka se dá také vyvolat pomocí jejího konstruktoru Create - destruktor vyjímky se volá automaticky na konci její obsluhy, pokus zrušit vyjímku ručně způsobí chybu procedure TForm1.Button21Click(Sender: TObject); begin try raise EAbstractError.Create('vyvolani vyjimky abstract error'); except on EAbstractError do begin
30 z 35
showmessage('osetreni abstract error'); raise; end; end; end; Vlastní vyjímky =============== - pro ošetření vlastních specifických chyb si můžeme vytvořit vlastní vyjímky - tyto vyjímky jsou vlastní třídy zděděné ze třídy Exception - názvy vyjímek je vhodné začít písmenem E {------------------------------------------------------------------------------} unit VlastniVyjimka; interface uses SysUtils; //kvuli pouziti tridy Exeption type EVelkaHodnota = class(Exception) //dedi vsecko z Exception bez uprav end; implementation end. {------------------------------------------------------------------------------} procedure TForm1.overHodnotu(hodnota, max : integer); begin //funkce co pri prekroceni max vyvola vlastni vyjimku if hodnota > max then raise EVelkaHodnota.Create('Velka Hodnota Exception'); end; procedure TForm1.Button23Click(Sender: TObject); begin try overHodnotu(165,100); //vyvola vlastni vyjimku except on EVelkaHodnota do begin showmessage('prekroceni mezi');//zpracuje vlastni vyjimku raise;//znovuvyvola vlastni vyjimku end; end; end; {------------------------------------------------------------------------------} Tiché vyjímky EAbort ==================== - všechny vyjímky odvozené z Exceptions vypisují při vyvolání hlášku - EAbort je tichá vyjímka, tzn. žádnou hlášku nevypisuje - vyvolá se pomocí raise nebo pomocí procedury Abort z Unit SysUtils raise EAbort.Create('Ticha vyjimka'); //vyvola tichou vyjimku Abort;
//vyvola tichou vyjimku
- text tiché vyjímky se dá vidět při hlášení debugeru pokud je zapnuta volba v Debbuger Options Stop on Delphi exceptions a neni ignorovana EAbort Schránka Windows ================ - je přístupná pro všechny aplikace (ukládání a čtení dat) - kromě dat je ve schránce uložen i jejich formát - Delphi přímo podporují tyto formáty > CF_TEXT text > CF_BITMAP obrázkek *.bmp
31 z 35
> CF_METAFILEPICT obrázek *.wmf > CF_PICTURE obrázek třídy TPicture > CF_COMPONENT data třídy TPersistent (CF_OBJECT) - pro ostatní typy formátů by se musely použít API funkce Práce se schránkou v Delphi =========================== - většina objektově orientovaných komponent (např.: Memo, RichEdit) pracuje se schránkou přímo pomocí metod Memo1.CopyToClipboard; Memo1.CutToClipboard; Memo1.PasteFromClipboard;
//zkopírovat do schránky //vystřihnout do schránky //vložit ze schránky
//při kopírování nebo vystřižení musí být text v Memo vybrán - pokud objekt (komponenta) nemá tyto metody musíme ke schránce přistupovat pomocí objektu Clipboard Objekt Clipboard ================ - definován v Unit Clipbrd {je lepší dát Uses Clipbrd až do implementační části} - třída TClipboard - objekt Clipboard nemusíme nijak vytvářet ani inicializovat - zjištění zda jsou ve schránce datata požadovaného typu if Clipboard.HasFormat(CF_TEXT) then //když je formát CF_TEXT tak vrací TRUE - zkopírování obrázku (nemá vlastní metody pro práci se schránkou) do schránky ClipBoard.Assign(Image1.Picture);
// zkopírování obsahu Image1 do schránky
- natažení obrázku ze schránky //POZOR: před prvním použitím se musí objekt Graphic vytvořit jinak chyba if image1.Picture.Graphic = nil then image1.Picture.Graphic := TBitmap.Create; Image1.Picture.Graphic.Assign(ClipBoard);
// získání obrázku ze schránky
Vlastnosti schránky =================== property FormatCount: Integer; - počet formátů schránky ve vlastnosti Formats[] property Formats[Index: Integer]: Word; - pole formátů které jsou uloženy ve schránce - aplikace ukládá obvykle data do schránky v několika formátech property AsText: string; - reprezentuje aktuální obsah schránky jako text - aby se to dalo použít musí Clipboard obsahovat text CF_TEXT Základní metody schránky ======================== procedure Assign(Source: TPersistent); - ukládá a získává data ze schránky - používá se hlavně pro obrázky *.bmp ClipBoard.Assign(Image1.Picture); // zkopírování obsahu Image1 do schránky Image1.Picture.Graphic.Assign(ClipBoard); // získání obrázku ze schránky procedure Clear; - vymazání obsahu schránky procedure HasFormat(Format: Word): Boolean; - testuje zda má schránka požadovaný obsah (když ano vrací TRUE) function GetTextBuf(Buffer: PChar; BufSize: Integer): Integer; - zkopíruje text z clipboardu do bufferu (buffer si musíme nejdřív alokovat)
32 z 35
- dá se použít k vytvoření více schránek size := 10000; GetMem(Buffer3,size); clipboard.GetTextBuf(Buffer3,size); procedure SetTextBuf(Buffer: PChar); - vloží text z bufferu do schránky (buffer je nulou ukončený řetězec) - dá se použít k vytvoření více schránek Clipboard.SetTextBuf(Buffer3);
procedure SetAsHandle (Format: Word; Value: THandle); - nastavení formátu dat ve schránce a přesunutí dat do schránky, používá se to u uživatelem definovaného formátu dat schránky function GetAsHandle (Format: Word): THandle; - získání handleru na data ze schránky v uživatelem definovaném formátu dat schránky { Funkce StrPas ------------function StrPas(Str: PChar): string; - převádí nulou ukončený řetězec na obyčejnej Pascal řetězec } Uživatelský formát dat ve schránce ================================== - umožňuje vytvořit a používat vlastní formát dat ve schránce windows - formát dat se musí nejprve zaregistrovat (při inicializaci) - registrace formátu dat je case sensitive - pokud registrace proběhne v pořádku je vrácena hodnota která identifikuje formát v systému pokud se nepovede vrací se 0 const MyData = 'CF_MYDT'; CF_MYDT := RegisterClipboardFormat(MyData); var CF_MYDT : word; - pro vlastní formát dat je třeba vytvořit typ záznam type TDataRecord = packed record Prijmeni : String[20]; Jmeno : String[20]; DatNar : TDateTime; end; - s tímto záznamem pak můžeme pracovat přímo nebo ho zapouzdřit do vlastní třídy a napsat příslušné metody CopyToClipBoard, PasteFromClipboard type TDta = class public Zaznam : TDataRecord; procedure CopyToClipBoard; procedure GetFromClipBoard; end; {------------------------------------------------------------------------------} procedure TDta.CopyToClipBoard; const CRLF = #10#13; //konec radky kvuli vlastnosti Clipboard.AsText var Data : THandle; //handle pro pristup k pameti DataPtr : Pointer; //genericky pointer tmp : String[50];//pro naplneni Clipboard.AsText
33 z 35
begin Data := GlobalAlloc(GMEM_MOVEABLE,SizeOf(TDataRecord)); //API Funkce pro prirazeni pameti ze systemu try DataPtr := GlobalLock(Data); //API pro uzamceni pameti aby bylo mozne pracovat pomoci pointeru try Move(Zaznam, DataPtr^, SizeOf(TDataRecord)); //presunuti bloku pameti do globalni pameti ClipBoard.Open; //otevreni clipboardu Clipboard.SetAsHandle(CF_DTA ,Data); //nastaveni formatu schranky a presunuti dat do schranky with Zaznam do begin tmp := Prijmeni+CRLF+Jmeno+CRLF+DateTimeToStr(DatNar); //vytvoreni retezce pro Clipboard.AsText end; ClipBoard.AsText := tmp;//nastaveni Clipboard.AsText ClipBoard.Close;//uzavreni schranky finally GlobalUnlock(Data);//API odemceni pameti kterou jsme meli zamknutou end; except //pokud by nastala vyjimka uvolnime handler a vyvolame vyjimku v bloku nad //pokud vyjimka nenastane tak se o uvolneni pameti postara schranka GlobalFree(Data); raise; end; end; {------------------------------------------------------------------------------} procedure TDta.GetFromClipBoard; var Data : THandle; DataPtr : Pointer; Size : Integer; begin Data := ClipBoard.GetAsHandle(CF_DTA);//ziskani handleru na data if Data = 0 then exit;//pokud je schranka prazdna koncime DataPtr := GlobalLock(Data);//uzamceni dat try if SizeOf(TDataRecord) > GlobalSize(Data) then //nastaveni velikosti dat Size := GlobalSize(Data) else Size := SizeOf(TDataRecord); Move(DataPtr^,Zaznam,Size);//presunuti dat ze schranky do zaznamu finally GlobalUnlock(Data);//odemceni dat end; end; {------------------------------------------------------------------------------} MDI aplikace ============ - MDI = Multiple Dcument Interface - umožňují v rámci jednoho okna vytvářet a otvírat libovolné množství podřízených oken - Rámec aplikace (aplikační okno) vymezuje prostor pro podřízená okna, toto okno musí mít nastavenu vlastnost FormStyle na fsMDIForm (jen toto jedine) - Podřízená okna musí mít nastavenu FormStyle na fsMDIChild (může jich být víc) - aplikace uchovává všechny formuláře v poli MDIChildren[] - počet formulářů se dá zjistit z vlastnosti MDIChildCount //read only - vlastnost ActiveMDIChild odkazuje na právě aktivní okno a můžeme s ním pomocí této vlastnosti pracovat například takto : procedure TForm1.minAktOkno(Sender: TObject);
34 z 35
var TheForm: TForm; begin if MDIChildCount > 0 then begin TheForm := Form1.ActiveMDIChild; TheForm.WindowState := wsMinimized; end; end; Vytvoření rámce aplikace ======================== > pouze nastavit na formuláři FormStyle na fsMDIForm Vytvoření podřízeného okna ========================== > File -> NewForm > FormStyle = fsMDIChild > uložit pod názvem třídy jako kterou budeme nové formuláře vytvářet > pokud nechceme aby se vytvořil nový formulář při startu aplikace tak smazat z Projektu (obvykle Project1) řádku s vytvořením child formuláře např.: //Application.CreateForm(TMDIPicture, MDIPicture); > do hlavní unity s rámcem aplikace (ovykle Unit1) přidat uses Unity z child formulářem abychom mohli používat svůj typ child formuláře > pokud chceme aby se child formulář dal zavřít a ne jen minimalizovat tak do události FormClose musíme zapsat Action := caFree; (*1*) > napsat proceduru pro vytvoření child formuláře (*2*) (*1*) //child formular se zavre bez dotazu procedure TMDIPicture.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; //child formular se zavre s dotazem procedure TMDIText.FormClose(Sender: TObject; var Action: TCloseAction); begin if MessageDlg('Fakt zavrit ?', mtConfirmation,[mbYes, mbNo], 0) = mrYes then Action := caFree else Action := caNone; end; (*2*) //1varianta procedure TForm1.VytvoritMDItxt(const Jmeno : String); var okno : TMdiText; //nas typ ktery je deklarovan v prislusne unite begin okno := TMdiText.Create(self); okno.Visible := true; okno.Caption := Jmeno; end; //2varianta procedure TForm1.VytvoritMDIobr(const Jmeno : String); var obr : TMdiPicture; begin obr := TMdiPicture.Create(application); obr.Show; obr.Caption := jmeno; end; - TCloseAction určuje co se má stát když se zavírá formulář (child formulář) type TCloseAction = (caNone, caHide, caFree, caMinimize); TCloseEvent = procedure(Sender: TObject; var Action: TCloseAction) of object; - caNone není dovoleno uzavření a nic se nestane
- caHide formulář se nezavře, jen se skryje, aplikace má k němu stále přístup - caFree formulář se uzavře a uvolní se alokovaná paměť - caMinimize formulář se minimalizuje, toto je defaultní nastavení pro MDIChild Nabídky v MDI aplikacích ======================== + při otevření různých typů podřízených oken se do nabídky hlavního okna mohou přidávat další speciální nabídky + pokud jsou otevřeny různé typy child oken tak jsou tyto nabídky přidávány podle toho které okno je zrovna aktivní Implementace > na každém formuláři musí být umístěna komponenta TMainMenu > jednotlivé nabídky této komponenty mají vlastnost GroupIndex > tato vlastnost nabídek se nastaví například takto : Form1 (rámec aplikace) soubor-GroupIndex 1, help-GroupIndex 4 Form2 (child form s textem) text-GroupIndex 2 Form3 (child form s obrázkem) obrázek-GroupIndex 3 ve všech Automerge nastavit na False Manipulace s podřízenými okny ============================= Uspořádání oken - jsou možné 4 varianty uspořádání oken > kaskáda + každý formulář obsahuje metodu Cascade; //metoda nemá vliv na minimalizovaná okna > vedle sebe + nejprve nastavíme vlastnost TileMode := tbVertical; + pak se zavolá metoda Tile; //metoda nemá vliv na minimalizovaná okna > pod sebe + nejprve nastavíme vlastnost TileMode := tbHorizontal; + pak se zavolá metoda Tile; //metoda nemá vliv na minimalizovaná okna > uspořádat ikony + použije se metoda ArrangeIcons; //metoda má vliv pouze na minimalizovaná okna Přepínání mezi okny - existují dvě metody Next; a Previous; Zavření všech oken - buďto se zavřou všechny s hlavním formulářem aplikace - nebo si pro to můžeme napsat vlastní metodu procedure TForm1.closeAll(Sender: TObject); var i : integer; begin for i := MDIChildCount-1 downto 0 do begin MDIChildren[i].Close; end; end; { je třeba jít downto protože hodnota MDIChildCount se při každém průchodu cyklem mění takže se nedá použít jako horní mez, nebo by se musela použít další proměnná do které by se přiřadila hodnota MDIChildCount před vstupem do cyklu }
35 z 35