Strona Główna - Artykuły - Galeria - Szukaj - Dziennik Lekcyjny
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

Dla rodziców
  Dziennik Lekcyjny

Rekrutacja
  Kierunki kształcenia
  Nabór 2010

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 13

Delphi, cz. 13


Ten rozdział może być niezbyt przyjemny :) Trzeba się bowiem nauczyć komunikatów. Jest to dość rozbudowany temat więc przeważająca część tego rozdziału będą stanowiły komunikaty. Ale nim to nastąpi....


Operacje na łańcuchach


Właściwie ten temat powinienem poruszyć już wcześniej. Nie jest to tak ważne, ale może się przydać - wierzcie mi :) Możecie dokładnie kontrolować swoje Stringi :) Tak łańcuch to nic innego jak tekst kryjący się pod zmienną "String". Przykładowo taki tekst:


var

S:  String;

begin

S := 'DELPHI';

S[1] := 'S';

ShowMessage(s);


Jak myślisz co teraz kryje się pod zmienną "S"? Tak napis "SELPHI". Przeanalizujmy przykład. Na początku zadeklarowaliśmy zmienną, a następnie odowłaliśmy się do pierwszego znaku z tej zmiennej. Odwołanie następuje za pomocą nawiasu klamrowego. W tym wypadku odwołanie do pierwszego znaku w zmiennej i zamiana go na literę "S". Teraz kolejna funkcja czyli "Pos". Podaje ona pozycje znaku w zmiennej. Spójrz na poniższy przykład:


const

S = 'ADAM';

begin

ShowMessage(IntToStr(Pos('D', S)));


Funkcja "Pos" podaje numer znaku jakiego szukasz w jakiejś zmiennej lub stałej typu "String". W powyższym przykładzie zwracany jest numer znaku ( litery "D" ) w stałej "S". Gdy uruchomisz program to Twoim oczom ukarze się cyfra 2.

Teraz coś trudniejszego, czyli usuwanie wszystkich spacji w zmiennej. Look:


var

S : String;

begin

S := 'A D A M'; // zmienna

while Pos(' ', S) > 0 do // odnajduj wszystkie spacje

Delete(S, Pos(' ', S), 1); // usuń spacje

ShowMessage(S);

end;


Na początek deklarowana jest zmienna, która zawiera spacje. Następnie pętla, która "mówi"  kompilatorowi, żeby szukał spacji w zmiennej "S" dopóki ilość spacji nie będzie się równać zero ( brak spacji ). Następna instrukcja to "Delete". Usuwa ona cześć z łańcucha. Pierwszym jej parametrem jest zmienna, której ma dotyczyć operacja. Kolejny to od którego miejsca w łańcuchu rozpoczynać się będzie operacja. Ostatni parametr "mówi" ile znaków ma zostać usuniętych. W naszym przypadku jest to jeden znak spacji. Jeszcze jeden przykład:


var

S : String;

begin

S := 'Zapraszamy do programowania w Delphi';

Delete(S, 29, 8);

ShowMessage(S);


Ta funkcja usunie ostatni wyraz, czyli 'w Delphi'. Kolejna funkcja to "Insert". Dodaje ona tekst do określonego String'a - przykład:


var

S : String;

begin

S := 'Zapraszamy do programowania';

Insert(' w Delphi', S, Length(S) + 1);

ShowMessage(S);


Tekst ' w Delphi' zostanie dodany do zmiennej "S" na samym końcu. Przy okazji poznajesz jeszcze jedna funkcje "Length". Podaje ona długość String'a w znakach. Do tego dodawana jest jeszcze cyfra 1, aby zachować odstęp.

Istnieje jeszcze jedna funkcja, która kopiuje część znaków. Najpierw przykład:


var

S : String;

Z : String;

begin

S := 'Adam Boduch';

Z := Copy(S, 1, 4); // skopuij te znaki do zmiennej "Z"

ShowMessage(Z);


Jak myślisz co zawiera zmienna "Z"?? Tak imię "Adam". Otóż ta zmienna kopiuje wybrane znaki ze zmiennej "S". Kopiuje od pierwszego do 4 znaku i przypisuje je zmiennej "Z". No, istnieje jeszcze jedna funkcja "Concat". Jest ona bardzo rzadko stosowana. Łączy ona bowiem dwa łańcuchy:


var

S1, S2 : String;

begin

S1 := 'Adam ';

S2 := 'Boduch';

ShowMessage(Concat(S1, S2));


 


Komunikaty


Jest to dosyć ważne w programowaniu. Być może sprawi Ci to trochę problemów, ale nie załamuj się - z czasem zrozumiesz o co chodzi :) Więc nie zniechęcaj się i zamiast zamknąć to okno przeczytaj ten text do końca :)


My tego nie widzimy, ale Windows ciągle generuje komunikaty. Jeżeli naciskasz przycisk myszy do systemu dociera komunikat że Ty właśnie nacisnąłeś przycisk. Windows rozpoznaje ok. 700 komunikatów. Wszystko to co robisz to komunikaty. Jeżeli ruszasz myszką - jest to komunikat; jeżeli naciskasz klawiszem także. Na samym początku możesz nie rozumieć sensu zastosowania komunikatów dlatego, że Delphi upraszcza to w znacznym stopniu. Zauważ, że jeżeli w Inspektorze Obiektów klikniesz na zakładkę "Events" to ujrzysz listę zdarzeń. Te zdarzenia to w rzeczywistości komunikaty. Weźmy za przykład zdarzenie "OnKeyPress". Zdarzenie to generowane jest w chwili naciśnięcia przez użytkownika jakiegoś klawisza. W rzeczywistości jest to komunikat "WM_CHAR". Tak, takie są nazwy komunikatów :) Przykładziki:


WM_PAINT                           Okno zostało odświeżone.

WM_ACTIVATE                     Okno stało się aktywne.

WM_CLOSE                         Występuje podczas zamykania okna.

WM_QUIT                             Cały program powinien zostać zakończony.

WM_LBUTTONDOWN            Lewy przycisk myszy został naciśnięty. 


 


 Najpierw podam przykład przechwycenia komunikatu, a później sami wyślemy jakiś komunikat. Może na początek komunikat "WM_CHAR":


1. Do sekcji "private" dodaj linię:


procedure WMChar(var Msg: TMessage); message WM_CHAR;


Taka struktura jest specyficzna dla komunikatów. W nawiasie znajduje się zmienna typu "Message". Omówię ją później. Najważniejsza jest ostatnia część. Po słowie "Message" następuje nazwa komunikatu - w tym wypadku jest to "WM_CHAR", który to komunikat jest generowany w chwili naciśnięcia przez użytkownika przycisku. Ok, teraz należy napisać kod obsługujący ten komunikat. Najedź kursorem myszy na nazwę procedury i wciśnij klawisze: Ctrl + Shift + C - procedura zostanie dodana do sekcji "Implementation". Wpisz taki kod do procedury:


ShowMessage('Naciśnięto klawisz...');


Nic nadzwyczajnego - po prostu wyświetlana jest informacja o naciśnięciu klawisza. Teraz możesz uruchomić program i sprawdzić jego działanie.

Teraz najważniejsze pytanie: po co właściwie stosować komunikaty skoro mam odpowiednie zdarzenia? Odpowiedzi jest kilka:



  • czasem zaistnieje potrzeba kontrolowania zdarzenia, którego nie ma na karcie "Event" Inspektora Obiektów. ( przykład dalej ).

  • gdy zaistnieje potrzeba poinformowania o czymś innego programu.

  • ta umiejętność przyda Ci się w przyszłości ( choćby podczas programowania w WinAPI ).


 


Dobra, teraz wyślemy jakiś komunikat. Spis wszystkich komunikatów możesz znaleźć w pliku "Messages.pas" w katalogu z Delphi.

Do wysyłania komunikatów służą dwie funkcje API: SendMessage i PostMessage.  Różnica pomiędzy nimi jest jedna - SendMessage zwraca rezultat działania funkcji. Po wysłaniu komunikatu czeka ona na jego wykonanie, a następnie zwraca rezultat. Jeżeli jest to cyfra -1 to komunikat został wysłany pomyślnie - jeżeli różna od zera to wystąpił jakiś błąd. Funkcja PostMessage natomiast po wysłaniu komunikatu nie czeka na jego zakończenie tylko automatycznie powraca do aplikacji.


No dobra teraz trzeba wysłać jakiś komunikat. Oto przykład zamknięcia naszej aplikacji poprzez wysłanie komunikatu:


PostMessage(Handle, WM_QUIT, 0, 0);


Pierwszym parametrem tej funkcji jest tzw. uchwyt okna. Każda kontrolka, czy okno posiada swój uchwyt. Trzeba go określić podczas przesyłania komunikatu. W naszym przypadku jest to główna forma naszego formularza. Kolejnym parametrem jest nazwa samego komunikatu, a dwa ostatnie to dodatkowe parametry. Jeżeli powyższy kod "podepniesz" pod przycisk to jego naciśnięcie spowoduje zamknięcie programu.

Równie dobrze możesz w ten sposób zamykać inne okna:


var

H : THandle; // zmienna przechowująca uchwyt

begin

// szukanie okna...

H := FindWindow(nil, 'Pad 1.3 - instalacja');

// wysłanie komunikatu

PostMessage(H, WM_QUIT, 0, 0);


W tym przypadku nastąpiło zamknięcie innego programu. Do tego potrzebny był nam uchwyt tegoż okna. Zdobyliśmy go poprzez użycie funkcji "FindWindow". Pierwszym parametrem tej funkcji jest klasa ( ponieważ jej nie znamy wpisujemy znak pusty nil ), a drugim jest nazwa okna ( text na pasku okna ). Gdy już zdobyliśmy uchwyt można wysłać komunikat.

Komunikaty można wysyłać do różnych innych komponentów. Przykładowo komponent "Memo" nie posiada procedury "Undo" ( Cofnij ). Trzeba do komponentu wysłać komunikat, który spowoduje cofnięcie ostatniej operacji. Oto przykład:


 PostMessage(Memo1.Handle, WM_UNDO, 0, 0);


Tak jak mówiłem - każdy komponent ma swój uchwyt - komponent "Memo" także posiada uchwyt o nazwie "Handle". W tym wypadku do komponentu wysłany został komunikat "WM_UNDO", który nakazuje mu cofnięcie ostatniej operacji.


Na początku tego artykułu napisałem, że podam przykład wykorzystanie komunikatów. Czy nie fajnie by było gdyby komponent "Label" mógł działać jak odnośnik? Tzn., po najechaniu kursorem myszy na niego zmieniał by kolor czcionki, a po usunięciu kursora powracałby do poprzedniego? Fajnie by było, nie? Można to zrobić korzystając z komunikatów. Trzeba bowiem kontrolować wejście i wyjście kursora myszy w obszar komponentu. Dokonują tego komunikaty: CM_MOUSEENTER i CM_MOUSELEAVE. Komponenty "Label" nie mają na karcie "Events" w Inspektorze Obiektów obsługi tych zdarzeń ( a widzisz? Kolejny powód dla używania komunikatów ). Trzeba teraz napisać nową KLASĘ, która dziedziczyła by wszystkie właściwości komponentu "Label", a oprócz tego zawierała dwa dodatkowe komunikaty.

W swoim programie pod sekcją "uses" dodaj takie linie:


type

TCss = class(TLabel)  // nowa klasa - nowy Label

protected

// komunikaty przechwytujące wejście i wyjście kursora w 

// obszar komponentu

procedure CMMouseEnter(var Msg:TMessage);

message cm_MouseEnter;

procedure CMMouseLeave(var Msg:TMessage);

message cm_MouseLeave;

public

// procedura klikniecia na Labela

procedure MyOnClick(Sender: TObject);

end;


 


Właśnie stworzyłeś nową klasę dziedziczącą z komponentu "Label". Teraz wiesz, że Ty także możesz tworzyć swoje własne klasy. Jak widzisz nie jest to trudne. Po słwie "type", które oznacza nowy typ deklarujesz nową nazwę Twojej klasy. Później słowo kluczowe "class". W tym wypadku w nawiasie wpisany jest komponent, który posłuży nam jako pierwowzór. To pole nie jest wymagane, ale w tym wypadku chcemy, aby nasza nowa klasa posiadała wszystkie funkcje standardowego "Label'a", a oprócz tego funkcje, które wpisaliśmy, czyli komunikaty obsługujące wejście i wyjście kursora w obszar komponentu. To się nazywa "dziedziczenie". Zauważ, że te komunikaty zadeklarowane zostały w sekcji "protected". Oznacza to, że te komunikaty nie będą dostępne dla z poziomu innych komponentów. Następnie w sekcji "public" procedura która będzie obsługiwała kliknięcie w nowy komponwnt.

Teraz w sekcji "Implementation" dodaj deklaracje tych komunikatów:


{ TCss }


procedure TCss.CMMouseEnter(var Msg: TMessage);

begin

Font.Color := clRed;

Font.Style := Font.Style - [fsUnderline];

end;


procedure TCss.CMMouseLeave(var Msg: TMessage);

begin

Font.Color := clBlue;

Font.Style := Font.Style + [fsUnderline];

end;


Pierwszy komunikat wejścia kursora w obszar komponentu powoduje dodanie podkreślenia do komponentu i zmianę koloru czcionki na niebieski. Drugi komunikat przywraca domyślną czcionkę. Pod tymi procedurami dodaj jeszcze jedną, która będzie uruchamiana w chwili kliknięcia w komponent "Label":


procedure TCss.MyOnClick(Sender: TObject);

begin

ShellExecute(0, 'open', PCHar(Caption), nil, nil,  SW_SHOWMAXIMIZED);

end;


Do listy uses dodaj jeszcze słowo "ShellAPI". Ta funkcja powoduje otwarcie przeglądarki i wczytanie adresu, który jest zapisany w "Labelu". O procedurze "ShellExecute" poczytaj na końcu rozdziału. Zaraz pod słowem "Implementation" dodaj linię:


var

Css : TCss;


Jest to zmienna, która wskazuje na nasz nowy komponent ( a dokładniej klasę ). Teraz w sekcji "private" klasy formularza [NIE "CSS"  ( cały kod programu podany jest niżej! )] dodaj takie linie:


  procedure WMCreate(var Msg: TMessage); message WM_CREATE;

procedure WMDestroy(var Msg: TMessage); message WM_DESTROY;


To są komunikaty WM_CREATE ( występuje podczas tworzenia formy ) i WM_DESTROY ( występuje podczas niszczenia formy ). A więc uzupełnij kod tych komunikatów w ten sposób:


procedure TForm1.WMCreate(var Msg: TMessage);

begin

Css := TCss.Create(Self); // stworzenia klasy

with Css do // instrukcja wiążąca

begin

Parent := Self;

 // wlasciwosc "Caption"

Caption := 'http://www.programowanie.of.pl';

// pozycja Label'a

Left := 100;

Top := 100;

Font.Color := clBlue; // kolor czcionki

Cursor := crHandPoint; // kursor

 // procedura klikniecia na Label'a

OnClick := MyOnClick;

 // dodaj podkreslenie

Font.Style := Font.Style + [fsUnderline];

end;

end;


procedure TForm1.WMDestroy(var Msg: TMessage);

begin

Css.Free; // zwolnij pamiec

end;


Tym sposobem zakończyliśmy pisanie programu. Napisaliśmy program nie kładąc żadnego komponentu! Takie tworzenie programu nazywa się tworzeniem dynamicznym gdyż w komunikacie "WM_CREATE" następuje stworzenie Label'a, a dokładniej klasy "TCss", który dziedziczy z komponentu "Label". Oto cały kod programu ( uwaga! kod może się nie kompilować w niższych wersjach Delphi ).


unit Unit1;


{ Copyright (c) 2001 by Adam Boduch }

{ E-mail: boduch@poland.com         }

{ http://www.programowanie.of.pl    }


interface


 


uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms, Dialogs, StdCtrls, ShellAPI; { <- ważny moduł }


type

TCss = class(TLabel)  // nowa klasa - nowy Label

protected

// komunikaty przechwytujace wejscie i wyjscie kursora w obszar komponentu

procedure CMMouseEnter(var Msg:TMessage);

message cm_MouseEnter;

procedure CMMouseLeave(var Msg:TMessage);

message cm_MouseLeave;

public

 // procedura klikniecia na Labela

procedure MyOnClick(Sender: TObject);

end;


type

TForm1 = class(TForm)

private

// komunikaty wystepujace podczas tworzenia i

// niszczenia formy

procedure WMCreate(var Msg: TMessage); message WM_CREATE;

procedure WMDestroy(var Msg: TMessage); message WM_DESTROY;

public

 { Public declarations }

end;


var

Form1: TForm1;


implementation


var

Css : TCss;


{$R *.DFM}


{ TCss }


procedure TCss.CMMouseEnter(var Msg: TMessage);

begin

Font.Color := clRed;

Font.Style := Font.Style - [fsUnderline];

end;


procedure TCss.CMMouseLeave(var Msg: TMessage);

begin

Font.Color := clBlue;

Font.Style := Font.Style + [fsUnderline];

end;


procedure TCss.MyOnClick(Sender: TObject);

begin

ShellExecute(0, 'open', PCHar(Caption), nil, nil, SW_SHOWMAXIMIZED);

end;


procedure TForm1.WMCreate(var Msg: TMessage);

begin

Css := TCss.Create(Self); // stworzenia klasy

with Css do // instrukcja wiążąca

begin

Parent := Self;

  // wlasciwosc "Caption"

Caption := 'http://www.programowanie.of.pl';

// pozycja Label'a

Left := 100;

Top := 100;

Font.Color := clBlue; // kolor czcionki

Cursor := crHandPoint; // kursor

  // procedura klikniecia na Label'a

OnClick := MyOnClick;

  // dodaj podkreślenie

Font.Style := Font.Style + [fsUnderline];

end;

end;


procedure TForm1.WMDestroy(var Msg: TMessage);

begin

Css.Free; // zwolnij pamięć

end;


end.


Ty także możesz przekazywać swoje komunikaty. W sekcji "Interface" dodaj takie linie:


const

Moj_Komunikat = WM_USER + 100;


Właśnie zadeklarowałeś swój komunikat. Komunikat deklaruje się podając nazwę WM_USER + numer komunikatu. To Ty określasz ten numer. Jeżeli deklarujesz kilka swoich komunikatów każdy z nich musi mieć inny numer. Górna granica tych numerów to ponad 30000. Najlepiej jest stosować numery  powyżej 100 by uniknąć kolizji komunikatów. Teraz do sekcji "private" dodaj taką linię:


 procedure MojKomunikat(var Msg: TMessage); message Moj_Komunikat;


W tej linii obsługiwany będzie właśnie nasz zadeklarowany komunikat. Teraz uzupełnij tę procedurę w podany poniżej sposób:


procedure TForm1.MojKomunikat(var Msg: TMessage);

var

S : String;

begin

S := Format('Błąd wystąpił w linii: %d, w znaku: %d',

[Msg.WParam, Msg.LParam]);


  MessageDlg(S, mtInformation, [mbOK], 0);

end;


W tym wypadku po otrzymaniu komunikatu wyświetlone jest okienko. Zmienna "S" przechowuje tekst. Nie będę tutaj omawiał funkcji "Format" gdyż nie ma ona znaczenia dla działania programu. W tym komunikacie pobierane są parametry Msg.WParam i Msg.LParam. Tak jak mówiłem wcześniej są to dodatkowe parametry.

No tak. Nie omówiłem jeszcze propcedury "MessageDlg"? A może omówiłem? Nie pamiętam. :) Cóż powtórka nie zaszkodzi. Ta procedura wyświetla okienko z jakimś tekstem. Pierwszy parametr to tekst okienka, drugi to typ ( od tego zależy jaka ikonka pojawi się w oknie ). Możliwe są także do wykorzystania: mtInformation, mtWarning, mtError. Sprawdź je! Przed ostatni to przycisk jaki się pojawi w oknie. W tym przypadku jest to OK. Może też być kombinacja: [mbYes, mbNo]. Poczytaj w helpie na temat tej procedury. Ostatni parametr to kontekst pliku pomocy. O tym będzie mowa kiedy indziej.


Teraz możesz wysłać już swój komunikat:


Perform(Moj_Komunikat, 20, 200);


Powiesz: "Zaraz, a gdzie funkcja "PostMessage"?". No tak zapomniałem powiedzieć. Istnieje jeszcze jedna funkcja do przesyłania komunikatów - "Perform". Nadaje się ona jednak tylko do przesyłania komunikatów w obrębie programu i tylko do komponentów znajdujących się w programie. Zauważ, że nie posiada ona jednego parametru jakim jest uchwyt okna. Po prostu pierwszym parametrem jest nazwa komunikatu, a dwa pozostałe to dodatkowe parametry "WParam" i "LParam". Najlepiej będzie jeżeli uruchomić program i sam sprawdzisz działanie tego programu.


Jeszcze trochę o "ShellExecute"


Funkcja "ShellExecute" służy przede wszystkim do otwierania jakiś programów itp. Jej budowa jest następująca:


ShellExecute(

HWND hwnd,

LPCTSTR lpOperation,

LPCTSTR lpFile,

LPCTSTR lpParameters, 

LPCTSTR lpDirectory, 

INT nShowCmd

);


 


Co oznaczają  te parametry? Już śpieszę z wyjaśnieniem. Pierwszy parametr to uchwyt okna. Kolejny parametr to operacja. Możliwe są do wykonania takie operacje:


"open" - otwiera plik.

"print" - drukuje.

"explore" - eksploruje.


Kolejnym parametrem jest parametr :)) Wiem, że to brzmi głupio, ale zaraz podam przykład. Przed ostatni to ścieżka dostępu, a ostatni to sposób pokazanie aplikacji. Dostępne są taki oto sposoby: 


SW_HIDE - aplikacja, którą otwierasz nawet się nie pojawi.

SW_SHOW - ukazanie aplikacji.

SW_MINIZE - otwarcie zminimalizowanej.

SW_MAXIMIZED - otwarcie zmaksymilizowanej.

SW_SHOWNORMAL - otwarcie okna w domyślnych rozmiarach.


Ok, teraz podam Wam przykład otwarcia jakiegoś programu (UWAGA! Jeżeli chcesz korzystać z funkcji ShellExecute musisz dodać słowo "SHELLAPI" do listy modułów).


ShellExecute(Handle, 'open', 'C:\Pad.exe', nil, nil, SW_SHOWNORMAL);


Zauważ, że nie musiałem podawać wszystkich parametrów, ani ścieżki  - podałem ją w trzecim parametrze.

Wyobraź sobie taką sytuację. Chcesz, chcesz, aby otwarty został "Notatnik" i wczytał kod HMTL Twojej strony WWW. Jak to zrobić? O tak:


ShellExecute(Handle, 'open','notepad.exe','C:\Moje dokumenty\www\index.html', 'C:\Windows', SW_SHOWNORMAL);


Po prostu jako parametr podałem ścieżkę ze stroną WWW.

Wyobraź sobie także sytuację, w której musisz wydrukować jakiś dokument, ale nie chce Ci się pisać procedury, która by to robiła. Możesz skorzystać z procedury drukującej Notatnika.


ShellExecute(Handle, 'print','C:\Frunlog.txt', nil, nil, SW_HIDE);


Teraz gdy naciśniesz przycisk dokument zostanie wydrukowany, a okno Notatnika nawet się nie pojawi (SW_HIDE). Zauważ, że nie musiałem podawać nazwy programu (notepad.exe), ani ścieżki. Po prostu użyty został domyślny program z którym skojarzone jest rozszerzenie *.txt.

Jeżeli chcesz np. wysłać poczte to piszesz:


ShellExecute(Handle, 'open', 'mailto:boduch@poland.com?Subject=List', nil, nil, SW_SHOW);


Istnieje prostsza, ale mniej oferująca funkcja do otwierania innych programów. Oto ona:


WinExec('C:\Progran.exe', SW_SHOW);


Kurde! Ale się rozpisałem :) Aż 442 linie! Dobra, kończę już, nara!

Dodane przez Root dnia marzec 08 2008 00:29:03 · 0 Komentarzy · 327 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
25 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
Delphi 7 Personal 567
C++Builder 6 Personal 560
Kalkulator okienkowy 529
Podstawy JavaScript 403
Kalkulator Konsolowy 367
Kalkulator w C# 314
Szyfrator 306
WebBrowser 2.0 Beta 297
Screenshots 290
Renamer v1.0 by David23 262
Zegar & Kalendarz
Logowanie
Nazwa Użytkownika

Hasło

Zapamiętaj mnie



Rejestracja
Zapomniane hasło?