Strona Główna - Artykuły - Galeria - Szukaj
Nawigacja
Portal
  Strona Główna
  Artykuły
  Galeria
  Kontakt
  Linki
  SZOK
  Szukaj

O nas
  Historia
  Kadra
  Kierunki kształcenia
  Patroni
  Polska i Litwa
  Prasa o szkole
  Projekty EFS

Dla uczniów
  Informatyka
  Konkursy
  Pedagog
  Pobierz
  Sport

Rekrutacja
  Kierunki kształcenia
  Nabór 2009

Różne
  WebGG

Reklama

Spacerkiem po Myśliborzu

Wirtualny Myślibórz

Matura z OPERONEM

Powiat Myśliborski

Wyższa Szkoła Integracji Europejskiej

Gimnazjum im. Dariusa i Girenasa w Kownie

Angielski
Wpisz wyrażenie polskie lub angielskie:

Niemiecki
Wpisz wyrażenie polskie lub niemieckie:

Delphi - cz 17

Delphi, cz. 17


Tym razem coś bardziej skomplikowanego. Najpierw zapoznam Ciebie z dynamicznym przydziałem pamięci, omówię także wskaźniki, a pod koniec zaprezentuje aplikację, która wymieniała będzie dane ze schowkiem na podstawie swojego własnego formatu. Aplikacja ta będzie kopiowała dane z rekordu do pamięci komputera, następnie do schowka.


Wskaźniki


Wskaźniki to chyba najtrudniejsza do opanowania cześć programowania w Delphi. Tak mi się zdaje, bo pamiętam jak mi sprawiało trudności opanowanie tego.


Normalnie pisząc program i deklarując zmienne pamięć dla nich przydzielana jest przy uruchamianiu program. Ty nie musisz się o nic martwić - Delphi sam sobie pamięć dla programu zarezerwuje. Takie coś nazywa się alokacją statyczną.


Stos to cały obszar pamięci, który rezerwowany jest dla aplikacji w czasie jej uruchamiania. 


 A więc obszar pamięci ( Stos ) nie może być w żaden sposób modyfikowany. Jeżeli piszesz mały programik to taka alokacja ( statyczna ) jest wystarczająca.


Sterta to cała dostępna pamięć komputera. + całe dostępne miejsca na dysku komputera.


Teraz jeżeli w swoim programie masz dużo rekordów i zmiennych to przydział statyczny może być niewystarczający. Wówczas możesz skorzystać ze wskaźników przydzielając im pamięć dynamicznie, czyli jawnie. Musisz o to zadbać sam... Tak jak mówiłem. Alokując pamięć statycznie nie możesz korzystać z przestrzeni dyskowej, a tylko z pamięci fizycznej. Jeżeli masz w swoim dużo tablic, rekordów ta pamięć może być niewystarczająca. Trzeba wówczas dynamicznie zwalniać i alokować pamięć. Popatrz na poniższy przykład.


procedure TForm1.Button1Click(Sender: TObject);

type

TRec = record // rekord

Imie: String;

Nazwisko: String;

Kod: Integer;

end;

PRec = ^TRec; // wskazanie na rekord "TRec"

var

Rec : PRec; // zmienna na wskaźnik

begin

New(Rec);  // przydział pamięci


  Rec^.Imie := 'Adam'; // wypełnienie rekordu

Rec^.Nazwisko := 'Boduch';

Rec^.Kod := 54150;


  Dispose(Rec); // zwolnienie pamięci

end;


Pewnie nie po raz pierwszy spotykasz się z taką konstrukcją. Nowy typ "PRec" wskazuje na rekord "TRec". Wskazanie następuje poprzez znak '^'. Następnie jako zmienna zadeklarowany zostaje typ "Rec". Następnie przydział pamięci następuje poprzez polecenie "New". Po tym można zacząć wypełnienie rekordu ( także z wykorzystaniem znaku '^' ). Tak więc operacja została wykonana ( na końcu nastąpiło zwolnienie pamięci ).

Tak więc dzięki wskaźnikom pamięć może być modyfikowana podczas działania programu.


Istnieje kilka sposobów na alokację pamięci. Możesz to np. zrobić poprzez polecenie "AllocMem":


 


type

PRec = ^Trec;

Trec = record

S : PCHar;

I : Double;

end;

var

Rec : PRec;

begin

Rec := AllocMem(SizeOf(Trec));


Teraz żeby zwolnić pamięć należy wywołać polecenie:


FreeMem(Rec);


Kolejny sposób:


type

PRec = ^Trec;

Trec = record

S : PCHar;

I : Double;

end;

var

Rec : PRec;

begin

GetMem(Rec, SizeOf(TRec));


Przy zwalnianiu także należy wywołać polecenie "FreeMem".


Przydział dynamiczny ma swoje wady i zalety, ale przy wielkich tablicach takie zastosowanie jest konieczne.


Tak jak mówiłem - wskaźniki przechowują informacji o komórce pamięci w jakiej przechowywana jest dana zmienna. Popatrz na poniższy przykład:


var

A : Integer;

B : ^Integer; // wskaznik na typ integer

begin

A := 11; // przypisanie wartosci do zmiennej

// wyswiet zmiena...

Canvas.TextOut(10, 10, IntToStr(a));

B := @A; // przypisz adres komorki do zmiennej

// wyswietl dotychczasowa wartosc komorki

Canvas.TextOut(10, 30, IntToStr(B^));

B^ := 14; // przypisz nowa wartosc dla zmiennej

// wpisz wartosc zmiennej "A"

Canvas.TextOut(10, 50, IntToStr(A));


 


W powyższym przykładzie następuje przypisanie zmiennej "A" odpowiedniej wartości. Następnie do wskażnika "B" zostanie przypisany adres pamięci pod którym znajduje się zmienna "A" ( operator "@" ). Następnie na ekranie wyświetlona zostaje dotychczasowa wartość komórki. Później ta wartość zostaje zmodyfikowna. Inaczej mówiąc komórce pamięci, która przechowuje wartość zmiennej "A" zostaje przypisana nowa wartość ( cyfra 14 ).


Wykorzystanie schowka


O schowku trochę pisałem podczas odpisu budowania edytora tekstu TeXT Edit. W Delphi. schowek ma dużo większe zastosowanie. Do listy uses dodaj słowo "Clipbrd". Teraz możesz wykorzystać inne jego elementy. Np. żeby do schowka dodać tekst piszesz:


ClipBoard.AsText := 'Nowy tekst w schowku!';


Możesz także kopiować inne elementy - np. zawartość komponentu "Image":


ClipBoard.Assign(Image.Picture);


Żeby teraz do "Image'a" wstawić obrazek ze schowka piszesz:


Image.Picture.Assign(ClipBoard);


Polecenie "Assign" pobiera strumień danych. Inaczej mówiąc robi kopie jakiegoś obiektu.


Tak jak mówiłem wcześniej stworzymy aplikację rejestrującą nowy format danych w schowku. Windows rozpoznaje takie typy:


CF_TEXT - zwykły tekst;

CF_BITMAP - bitmapa Windows;

CF_PALETTE - paleta Windows;


Żeby sprawdzić jaki typ danych znajduje się w schowku stosujesz polecenie "HasFormat":


  if ClipBoard.HasFormat(CF_TEXT) then { jakieś czynności }


Na potrzeby naszej aplikacji będziemy musieli zarejestrować nowy format danych. Stworzymy także nowy moduł. Stwórz więc nowy projekt i zapisz go w jakimś katalogu. W programowaniu ciągle korzystasz z modułów napisanych przez programistów Borlanda. Przykładowo: chcesz użyć funkcję "ShellExecute". Jeżeli do listy uses nie dodasz słwa "ShellAPI" to Delphi nie rozpozna polecenia "ShellExecute". Ty także możesz stworzyć nowy moduł. W Delphi z menu "File" wybierz "New". W oknie, które się pojawi wybierz ikonę z napisem "Unit". Delphi otworzy nowy moduł. Zapisz go pod nazwą "DataUnit.pas". Ok teraz do tego modułu należy dodać potrzebne nam procedury i funkcje.

W sekcji "Interface" wpisz słwo "uses" i pod nim wypisz wszystkie potrzebne nam moduły. Będą to: Windows, Classes, Clipbrd;

Teraz należy stworzyć nowy rekord, klasę. Oto jak powinno to wyglądać:


unit DataUnit;


interface


uses

Classes, Windows, { wykorzystanie schowka ->> }Clipbrd;


var

CF_USER : WORD; // zmienna zawiera wynik rejestracji nowego formatu


{

  Ten nowy rekord zawiera informacje o wypozyczonej kasecie video :)

  Pierwszym jego parametrem jest nazwa filmu, ktora skladac sie bedzie

  z max. 20 znakow. Kolejnym parametrem jest numerek wypozyczajacego,

  a ostatnim data i czas wypozyczenia filmu.

}

type

TVideoRec = packed record

Film: String[20];

Numer: Integer;

Data : TDateTime;

end;


{

  Ta klasa zawiera dwie wazne procedury. Pierwsza z nich kopiuje

  dane z rekordu do schowka, a druga pobiera te dane ze schowka i

  przypisuje do rekordu.

}

type

TVideo = class

public

Rec : TVideoRec;

procedure CopyToClipBoard;

procedure GetFromClipBoard;

end;


implementation


 


Zacznijmy od góry. Nowa zmienna, która przechowuje w sobie informacje o tym czy rejestracja nowego formatu powiodła się, czy też nie. Następnie nowy rekord. Zauważ słowo "packed" przy rekordzie. Oznacza ono, że rekord zostanie 'spakowany', czyli zawierać będzie mniej miejsca w pamięci. Jeżeli opatrzymy rekord tą klauzurą to rekord w pamięci zawierać będzie sumę podporządkowanych mu zmiennych. Jeżeli nie opatrzyłbyś rekordu tą klauzurą to pamięć zajmowana przez rekord zaokrąglana by była do 8 bajtów, czyli 8 lub 16 lub 32. Pierwsza zmienną wchodzącą w skład rekordu jest nazwa filmu. Będzie ona typu "String". W nawiasach klamrowych można określić ile znaków zawierać będzie ta zmienna ( czyli max. długość nazwy filmu ). Kolejna zmienna to informacja o numerze klienta, który wypożycza film. No i ostatni parametr to data wypożyczenia filmu.

Następnie rejestracja nowej klasy. Nasza klasa zawiera tylko sekcje "public" by zawarte w niej pola mogły być wykorzystane przez inny moduł. Klasa ta zawiera zmienną która wskazuje na rekord oraz dwie procedury: kopiująca i wklejająca tekst.


No. Teraz w sekcji "Implementation" należy zapisać deklarację dwóch procedur: kopiującej i wklejającej tekst:


procedure TVideo.CopyToClipBoard;

var

Data : THandle;

PData : Pointer; // wskaznik!

begin

{ Zarezerwuj pamiec o rozmiarze rekordu }

Data := GlobalAlloc(GMEM_MOVEABLE, SizeOf(TVideoRec));

try

PData := GlobalLock(Data); // przeksztalc we wskaznik


    Move(Rec, PData^, SizeOf(TVideoRec)); // skopiuj do pamieci


    ClipBoard.Open; // otworz schowek

ClipBoard.SetAsHandle(CF_USER, Data); // dodaj do schowka

ClipBoard.Close;  // zamknij schowek

finally

GlobalUnlock(Data); // uwolnij pamiec

end;

end;


 


Na pierwszy rzut okna procedura może wydać się skomplikowana. Na samym początku następuje rezerwacja pamięci potrzebnej do przechowania rekordu. Funkcja "SizeOf" oblicza ile miejsca w pamięci zajmuje dany typ - w tym wypadku rekord. Zauważ, że zadeklarowałem jako zmienną wskaźnik. Następnie przekształciłem pamięć we wskaźnik ( GlobalLock ). Wiadomo, że wskaźnik ma zawierać tylko adres pamięci która zadeklarowaliśmy. Następnie polecenie "Move", które przenosi dane z jednego miejsca na drugie. Pierwszym jej parametrem jest źródło - w tym wypadku rekord - drugim wskaźnik, czyli miejsce do którego dane mają być przeniesione. Ostatni parametr to porcja przenoszonych danych. Tak jak poprzednio oblicza się ją za pomocą polecenia "SizeOf".

Kolejne polecenia to operacje na schowku. Następuje jego otworzenie, czyli teraz żadna aplikacja nie może ze schowka korzystać.  Następuje do schowka wstawienie nowych danych. Pierwszy parametr to informacja o tym w jakim formacie mają być informacje wstawione. W końcu schowek zostaje zamknięć, a pamięć zwolniona.

Teraz druga procedura wklejająca informacje ze schowka do rekordu:


procedure TVideo.GetFromClipBoard;

var

Data : THandle;

PData : Pointer;

begin

Data := ClipBoard.GetAsHandle(CF_USER); // pobierz dane ze schowka

try

PData := GlobalLock(Data); // przeksztakc we wskaznik


    Move(PData^, Rec, SizeOf(TVideoRec)); // skopiuj do rekordu

finally

GlobalUnlock(data);  // uwolnij pamiec;

end;

end;


Ta procedura jest krótsza. Najpierw następuje pobranie formatu ze schowka. Później przekształcenie tego na wskaźnik. Z pamięci dane mają być zapisane do rekordu.

To jeszcze nie wszystko. Przed zakończeniem modułu dodaj takie linie:


{ Rejestracja nowego formatu w schowku }

initialization

CF_USER := RegisterClipBoardFormat('CF_DGUSER');


To jest kolejna sekcja! Tak po słwie "Initialization" możesz zawrzeć instrukcje które będą wykonywane na samym początku uruchomienia programu. Następuje tutaj zadeklarowanie nowego formatu wymiany danych ze schowkiem. Tak jak mówiłem: zmienna "CF_USER" zawiera informacje o zarejestrowanym formacie.

W module możesz także umieścić linię "finalization" Po tej linii możesz zawrzeć instrukcję, które będą wykonywane podczas zakończenia pracy programu.

Moduł mamy już gotowy:


 


(********************************************************)

(*                                                      *)

(*        DataUnit  for Borland Delphi 5                *)

(*      Copyright (c) 2001 by Adam Boduch               *)

(*           Build:  04.03.2001 r.                      *)

(*       HTTP://WWW.PROGRAMOWANIE.OF.PL                 *)

(*            E - mail:  boduch@poland.com              *)

(*                                                      *)

(********************************************************)


unit DataUnit;


interface


uses

Classes, Windows, { wykorzystanie schowka ->> }Clipbrd;


var

CF_USER : WORD; // zmienna zawiera wynik rejestracji nowego formatu


{

  Ten nowy rekord zawiera informacje o wypozyczonej kasecie video :)

  Pierwszym jego parametrem jest nazwa filmu, ktora skladac sie bedzie

  z max. 20 znakow. Kolejnym parametrem jest numerek wypozyczajacego,

  a ostatnim data i czas wypozyczenia filmu.

}

type

TVideoRec = packed record

Film: String[20];

Numer: Integer;

Data : TDateTime;

end;


{

  Ta klasa zawiera dwie wazne procedury. Pierwsza z nich kopiuje

  dane z rekordu do schowka, a druga pobiera te dane ze schowka i

  przypisuje do rekordu.

}

type

TVideo = class

public

Rec : TVideoRec;

procedure CopyToClipBoard;

procedure GetFromClipBoard;

end;


implementation


 


{ TVideo }


procedure TVideo.CopyToClipBoard;

var

Data : THandle;

PData : Pointer; // wskaznik!

begin

{ Zarezerwuj pamiec o rozmiarze rekordu }

Data := GlobalAlloc(GMEM_MOVEABLE, SizeOf(TVideoRec));

try

PData := GlobalLock(Data); // przeksztalc we wskaznik


    Move(Rec, PData^, SizeOf(TVideoRec)); // skopiuj do pamieci


    ClipBoard.Open; // otworz schowek

ClipBoard.SetAsHandle(CF_USER, Data); // dodaj do schowka

ClipBoard.Close;  // zamknij schowek

finally

GlobalUnlock(Data); // uwolnij pamiec

end;

end;


procedure TVideo.GetFromClipBoard;

var

Data : THandle;

PData : Pointer;

begin

Data := ClipBoard.GetAsHandle(CF_USER); // pobierz dane ze schowka

try

PData := GlobalLock(Data); // przeksztakc we wskaznik


    Move(PData^, Rec, SizeOf(TVideoRec)); // skopiuj do rekordu

  finally

GlobalUnlock(data);  // uwolnij pamiec;

end;

end;


{ Rejestracja nowego formatu w schowku }

initialization

CF_USER := RegisterClipBoardFormat('CF_DGUSER');


end.


 


Teraz na formularzu umieść dwa Buttony odpowiadające za kopiowanie i wklejanie informacji. Umieść także dwie kontrolki typu "Edit" i nazwij je odpowiednio "FileName" i "UserNumber". Umieść na formie także komponent "DateTimePicker". Pokazuje on aktualną datę. Teraz do listy modułów uses twojego modułu dodaj nazwę stworzonego przed chwilą modułu ( DataUnit ). Teraz wygeneruj procedurę "OnClick" pierwszego przycisku.


procedure TMainFrm.btnCopyClick(Sender: TObject);

var

Video : TVideo; // utworz klase...

begin

Video := TVideo.Create;


  try

with Video.Rec do

begin

{ Przypisz dane z kontrolek na formie do rekordu w module "DataUnit" }

Film := FilmName.Text;

Numer := StrToInt(UserNumber.Text);

Data := Dates.DateTime;

Video.CopyToClipBoard; // wywyolaj procedure...

end;

finally

Video.Free; // zwolnij pamiec...

end;

end;


Konstrukcja nie jest trudna. Na początku utworzona została klasa ( przydzielona została pamięć ), następnie do rekordu wchodzącego w skład tej klasy przypisane zostały pola z komponentów. No i na końcu oczywiście wywołanie procedury kopiującej.

Wygeneruj procedurę "OnClick" dla przycisku wklejającego tekst:


procedure TMainFrm.btnPasteClick(Sender: TObject);

var

Video : TVideo;

begin

Video := TVideo.Create;

try

{ Sprawdz jaki format danych znajduje sie w schowku. Jezeli to nasz... }

if ClipBoard.HasFormat(CF_USER) then

with Video.Rec do

begin

Video.GetFromClipBoard; //... wywolaj procedure

FilmName.Text := Film;  // do kontrolek przypisz dane z rekordu

UserNumber.Text := IntToStr(Numer);

Dates.DateTime := Data;

end;

finally

Video.Free; // zwolnij pamiec

end;

end;


Działanie jest odwrotne. Najpierw następuje sprawdzenie formatu znajdującego się w schowku, a następnie do kontolek przypisane zostały dane z rekordu.

Oto cały program:


 


(********************************************************)

(*                                                      *)

(*        Test programme for Borland Delphi 5           *)

(*      Copyright (c) 2001 by Adam Boduch               *)

(*           Build:  04.03.2001 r.                      *)

(*       HTTP://WWW.PROGRAMOWANIE.OF.PL                 *)

(*            E - mail:  boduch@poland.com              *)

(*                                                      *)

(********************************************************)

//

//  Program ten wykorzystuje schowek i pamiec oraz wskazniki.

//  Ma on za zadanie zarejestrowac nowy format wymiany danych

//  ze schowkiem.

//  Nastepnie kopuiuje on dane z rekordu do schowka.


unit MainForm;


interface


uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, ComCtrls, ClipBrd, { Nasz modul ->> }DataUnit;


type

TMainFrm = class(TForm)

FilmName: TEdit;

UserNumber: TEdit;

Dates: TDateTimePicker;

btnCopy: TButton;

btnPaste: TButton;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

procedure btnCopyClick(Sender: TObject);

procedure btnPasteClick(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;


var

MainFrm: TMainFrm;


implementation


{$R *.DFM}


procedure TMainFrm.btnCopyClick(Sender: TObject);

var

Video : TVideo; // utworz klase...

begin

Video := TVideo.Create;


  try

with Video.Rec do

begin

{ Przypisz dane z kontrolek na formie do rekordu w module "DataUnit" }

Film := FilmName.Text;

Numer := StrToInt(UserNumber.Text);

Data := Dates.DateTime;

Video.CopyToClipBoard; // wywyolaj procedure...

end;

finally

Video.Free; // zwolnij pamiec...

end;

end;


procedure TMainFrm.btnPasteClick(Sender: TObject);

var

Video : TVideo;

begin

Video := TVideo.Create;

try

{ Sprawdz jaki format danych znajduje sie w schowku. Jezeli to nasz... }

if ClipBoard.HasFormat(CF_USER) then

with Video.Rec do

begin

Video.GetFromClipBoard; //... wywolaj procedure

FilmName.Text := Film;  // do kontrolek przypisz dane z rekordu

UserNumber.Text := IntToStr(Numer);

Dates.DateTime := Data;

end;

finally

Video.Free; // zwolnij pamiec

end;

end;


end.


 


Pozdrawiam!

Dodane przez Root dnia marzec 08 2008 00:33:20 · 0 Komentarzy · 272 Czytań · Drukuj
Komentarze
Brak komentarzy.
Dodaj komentarz
Zaloguj się, żeby móc dodawać komentarze.
Oceny
Dodawanie ocen dostępne tylko dla zalogowanych Użytkowników.

Proszę się zalogować lub zarejestrować, żeby móc dodawać oceny.

Brak ocen.
Ulubione i Startowa
Licznik
18 czerwca

KONIEC ROKU SZKOLNEGO
Ostatnie Artykuły
Powtorka z gramatyki...
Powtorka z gramatyki...
Nauka jezyka Angiels...
Delphi - cz 18
Delphi - cz 17
Delphi - cz 16
Delphi - cz 15
Delphi - cz 14
Delphi - cz 13
Delphi - cz 12
Najchętniej pobierane
C++Builder 6 Personal 469
Delphi 7 Personal 464
Kalkulator okienkowy 428
Podstawy JavaScript 301
Kalkulator Konsolowy 259
Szyfrator 212
Kalkulator w C# 211
WebBrowser 2.0 Beta 196
Screenshots 195
Renamer v1.0 by David23 182
Zegar & Kalendarz
Logowanie
Nazwa Użytkownika

Hasło

Zapamiętaj mnie



Rejestracja
Zapomniane hasło?