Delphi i nie tylko. Efektywne programowanie
Ten artykuł jest w trakcie tworzenia. Jeśli chcesz w tym pomóc, edytuj go. |
Wstęp Edytuj
Niniejszy podręcznik ma na celu nauczenie cię efektywnego programowania i usuwania błędów w środowisku Borland Delphi, choć niektóre informacje mogą być użyteczne także w innych IDE. Zakładam, że znasz podstawy języka Object Pascal i obsługi środowiska Delphi. Jeśli nie, możesz kliknąć w powyższe linki aby zaznajomić się z informacjami.
Sztuczki Edytuj
Zmniejszenie ilości kodu Edytuj
Dużo nie kodować, dobrze programować
Możemy zaoszczędzić sobie pisania, a program będzie wykonywał to samo. W tym rozdziale podam kilka sztuczek.
Operacje występujące jedna po drugiej Edytuj
W DOS-ie niektóre klawisze klawiatury powodują przekazanie do programu kodów: 0 (zero) oraz kod klawisza. Na przykład klawiszowi F1 odpowiada sekwencja: 0, 59. Kod mało doświadczonego programisty wyglądał by tak:
if readkey=#0 then if readkey=#59 then instrukcja;
I teraz przydaje się sztuczka:
if (readkey=#0) and (readkey=#57) then instrukcja;
Program przed wykonaniem operacji AND wykona obie instrukcje, w kolejności. Dlatego instrukcja
wykona się tylko wtedy, gdy w buforze klawiatury będą znaki #0 i #57.
Sztuczka ta jest bardzo przydatna także w pętlach, np. repeat - until
. Przykład kodu niepotrzebnie wydłużonego (wyjście z pętli po wciśnięciu F1):
repeat ... instrukcje; ... if readkey=#0 then if readkey=#59 then instrukcja; until false;
I kod skrócony:
repeat ... instrukcje; ... until (readkey=#0) and (readkey=#57);
- Ćwiczenie
Przekształć poniższy kod na postać skróconą. Program reaguje na wpisanie kolejno ciągów "Delphi", "jest", "fajny".
procedure TForm1.Button1Click(Sender: TObject); begin if InputBox('Wpisz', 'Wpisz tekst', ' ')='Delphi' then if InputBox('Wpisz', 'Dobrze, więc...', ' ')='jest' then if InputBox('Wpisz', 'no i...', ' ')='fajny' then ShowMessage('Zgoda!'); end;
Zobacz rozwiązanie ćwiczenia.
Istniejące funkcje Edytuj
Niektórzy nie wiedzą o przydatnych procedurach/funkcjach (dostępnych zwłaszcza w VCL). Oto lista takich funkcji (na początku podano nazwę typu, o ile funkcja jest w klasie):
TMemo.Lines.Clear
- czyści zawartość komponentu TMemoMaxValue, MaxIntValue
- parametr jest tablicą wypełnioną wartościami Double (MaxValue
) lub Integer (MaxIntValue
). Funkcja zwraca maksymalną wartość (nie klucz!) ze wszystkich.- W Turbo Pascalu:
Str, Val
- zamieniają liczbę na string lub odwrotnie. Szczegółowe informacje w pomocy Turbo Pascala.
Tworzenie funkcji dla zrytualizowanych czynności Edytuj
W Turbo Pascalu brakuje użytecznych funkcji IntToStr
oraz StrToInt
. Zamiast męczyć się ze zmiennymi przy Str i Val, można utworzyć funkcje - ich odpowiedniki. Te, i inne często używane funkcje można umieścić w unit'cie i korzystać z nich w swoich programach.
Ćwiczenie: zrób takie funkcje, umieść je w unicie "DelphiFunc
". Dodaj też typ bool
, będący aliasem typu boolean
. Rozwiązania możesz znaleść tutaj.
Komponenty największym wrogiem (inteligentnych) programistów Edytuj
Skąd taki tytuł? Bo właściwości komponentu trzeba dłuuugo pisać! Np. aby zrobić właściwość, której zmiana aktualizowała by komponent, należy kodować tak:
type TKomponent=class(TPersistant) ... private FWlasciwosc1: word; FWlasciwosc2: integer; procedure SetWlasciwosc1(value:word); ... published property Wlasciwosc1: word read FWlasciwosc1 write SetWlasciwosc1; property Wlasciwosc2: integer read FWlasciwosc2 write SetWlasciwosc2; ... implementation ... procedure TKomponent.SetWlasciwosc1(value:word); begin FWlasciwosc1 := value; Aktualizuj; end; procedure TKomponent.SetWlasciwosc2(value:word); begin FWlasciwosc2 := value; Aktualizuj; end; ...
Z pomocą przychodzą tu rekordy. Wystarczy zadeklarować typ rekordu i jedną właściwość, jedną zmienną pomocniczą, jedną procedurę:
type TWlasciwosci=record Wlasciwosc1:word; Wlasciwosc2:integer; end; TKomponent=class(TPersistant) ... private FWlasciwosci: TWlasciwosci; procedure SetWlasciwosc1(value:TWlasciwosci); ... published property Wlasciwosci: TWlasciwosci read FWlasciwosci write SetWlasciwosci; ... implementation ... procedure TKomponent.SetWlasciwosci(value:TWlasciwosci); begin FWlasciwosci := value; Aktualizuj; end; ...
Można też skorzystać z generatora kodu, obecnie pracuje nad jednym.
Edycja w Delphi - przydatne sztuczki Edytuj
Code Completion a nieznane typy Edytuj
Jeśli nie znasz jakiegoś typu, np. klasy komponentu, nie musisz zaglądać do pomocy! Najpierw w dowolnej procedurze (np. TForm.FormCreate) napisz nazwę typu, kropkę i wciśnij Ctrl+Spacja. Jeśli procedur jest dużo, a chcesz wyszukać np. czyszczącą, wpisz Clear
. Przykładowy, fikcyjny komponent może wyświetlić następującą listę po wpisaniu "TFikcyjnyKomponent.Clear
:
procedure ClearAll; procedure ClearItems; function ClearS : boolean;
Teraz już wiesz, jakie funkcje czyszczące zawiera ta klasa. Możesz ich użyć w bardziej sensownym fragmencie kodu. Ale to jeszcze nie wszystko! Jeśli klasa zawiera inną klasę lub rekord, możesz zrobić to samo:
- Wpisz
TFikcyjnyKomponent.Items
i wciśnij Ctrl+Spacja - Przykładowe elementy CodeCompletion:
property ItemsList: TFikcyjneItemy; property ItemsImages: TFikcyjneObrazki; function ItemValue(index:word): TFikcyjnyItem;
- Wpisz np.
ItemsImages.
- Pojawi się lista wszystkich elementów
- Wpisz np.
Total
(będzie to:TFikcyjnyKomponent.ItemsImages.Total
) - Pojawi się:
function TotalItems: word; function TotalSize: Cardinal;
- Już wiadomo, jakie funkcje podające informacje na temat całości zawiera ta klasa.
Kompilacja w trakcie tworzenia programu Edytuj
Jeśli nie jesteś pewien działania jakiegoś fragmentu kodu, np. czy w Turbo Pascalu można porównywać rekordy (podpowiem, że NIE), możesz skompilować program bez uruchamiania. Wtedy wyświetlą się wszystkie błędy składni i inne czasu kompilacji. Zrób tak po jednej "niepewnej" instrukcji, aby nie trzeba było poprawiać więcej.
Efektywne debugowanie Edytuj
Kolejnym problemem programistów jest to, że program nie chce działać tak, jak trzeba. W takim przypadku:
- Sprawdź, czy na pewno dobrze obsługujesz program (jako użytkownik)
- Przejrzyj kod, popraw ewentualne zauważone błędy
- Sprawdź ponownie, jeśli nie działa:
- Załóż breakpoint na pierwszą instrukcję z felernej procedury
- Uruchom program, włącz tę funkcję
- Sprawdzaj, jak zachowuje się program, poprawiaj błędy
- Jeśli do tej pory nie wyeliminowałeś błędu, obejrzyj DOKŁADNIE kod, zwróć szczególną uwagę na powtarzające się fragmenty
- Nie ma rady, baw się watches'ami
- Jeśli użycie podglądu (i zmiany) zmiennych nie daje efektów, napisz na forum dyskusyjne, polecam 4programmers.net lub forum.ks-ekspert.pl
Obsługa narzędzi do debugowania w Delphi Edytuj
(w planach)
Pewien przykład Edytuj
Oto przykład kodu, nad którym się sporo natrudziłem, doszedłem do siódmego punktu i udało mi się "odbugować" (błąd został podkreślony).
... AssignFile(f1, Edit1.Text); ReSet(f1); AssignFile(f2, Edit1.Text); ReSet(f2); ...
A mianowicie program służy do porównywania plików, a tu... porównuje dwa takie same! Kod poprawny:
... AssignFile(f1, Edit1.Text); ReSet(f1); AssignFile(f2, Edit2.Text); ReSet(f2); ...
Zakończenie Edytuj
Rozwiązania ćwiczeń Edytuj
Ćwicz. "Operacje występujące..." Edytuj
Kod rozwiązania:
procedure TForm1.Button1Click(Sender: TObject); begin if (InputBox('Wpisz', 'Wpisz tekst', ' ')='Delphi') and (InputBox('Wpisz', 'Dobrze, więc...', ' ')='jest') and (InputBox('Wpisz', 'no i...', ' ')='fajny') then ShowMessage('Zgoda!'); end;
Ćwicz. "Tworzenie funkcji..." Edytuj
unit DelphiFunc; interface type bool = boolean; function IntToStr(i : Integer) : String; function StrToInt(s : String) : Integer; implementation function IntToStr(i : Integer) : String; var s : String; begin Str(i, s); IntToStr := s; end; function StrToInt(s : String) : Integer; var i, c : Integer; begin Val(s, i, c); if c <> 0 then i := 0; StrToInt := i; end; end.