Delphi i nie tylko. Efektywne programowanie
Ten artykuł jest w trakcie tworzenia. Jeśli chcesz w tym pomóc, edytuj go. |
Wstęp
edytujNiniejszy 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
edytujZmniejszenie ilości kodu
edytujDuż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
edytujW 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
edytujNiektó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
edytujW 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
edytujSką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
edytujCode Completion a nieznane typy
edytujJeś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
edytujJeś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
edytujKolejnym 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
edytujOto 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
edytujRozwiązania ćwiczeń
edytujĆwicz. "Operacje występujące..."
edytujKod 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..."
edytujunit 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.