Aplikacje zakładkowe
Japer
Witajcie,
w tym artykule przedstawię Wam mechanizm aplikacji zakładkowych oparty na listach.
Jest on dość prosty, jeśli oczywiście potrafi się korzystać z klas typu TList itp.
Struktura mechanizmu
Sprawa jest oczywista - najpierw trzeba zdeklarować klasę TList (lub TObjectList) aby móc przechowywać wskaźniki do obiektów.
Struktura głównej listy będzie zawierać obiekty zawierające komponenty.
Tak wygląda przykładowa struktura listy:
[Lista_glowna]
+----[Zakladka_1: TZakladka]
+----[Komponent_1: TComponent]
+----[Memo_2: TMemo]
+----[Frame_3: TFrame]
+----[Zakladka_2: TZakladka]
itp...
Projektowanie klasy-kontenera zakładki
W tym etapie projektowania mamy dwie drogi:
-
zmęczyć się trochę przy kodowaniu i stworzyć zagnieżdżone listy (jest męczące, lecz bardziej elastyczne - trzeba trochę pokodzić)
-
lub utworzyć własny obiekt zawierający komponenty, z przydatnymi metodami
Pokażę Wam metodę 2. mniej męczącą, ale i mniej elastyczną (zależy jak ktoś napiszę tą klase)
Najpierw trzeba pomyśleć nad strukturą takiego obiektu. Załóżmy, że robimy przeglądarkę internetową opartą na TWebBrowser. Warto by było wyposażyć taki obiekt w właściwości, które dawały by dostęp do tych komponentów. Można dodać (nawet trzeba!) konstruktor, który by tworzył komponenty na TTabSheet'cie. Więc zabieramy się za kodowanie. Deklaracja mojego obiektu będzie wyglądać tak:
TTabListItem = class
private
FTabSheet: TTabSheet;
FWebBrowser: TWebBrowser;
public
constructor Create(AOwner: TComponent);
property TabSheet: TTabSheet read FTabSheet write FTabSheet;
property WebBrowser: TWebBrowser read FWebBrowser write FWebBrowser;
end;
Okej, mamy deklarację przykładowego Itema, zabieramy się za pisanie konstruktora (swoją droga wszystkie kody, które piszę są pisane na sucho).
constructor TTabListItem.Create(AOwner: TComponent; pgcMainPageControl: TPageControl);
begin
inherited Create;
FTabSheet.Create(AOwner);
with FTabSheet do
begin
Parent := pgcMainPageControl;
Align := alClient;
Caption := 'Nowy';
end;
FWebBrowser.Create(AOwner);
with FWebBrowser do
begin
Parent := FTabSheet;
Align := alClient;
end;
end;
W destruktorze oczywiście niszczymy obiekty zawarte w obiekcie, a zostawiam to Wam.
Kodowanie
Kodowanie obsługi dodawania i usuwania zakładek
Projektowanie i kodowanie metod (jeśli dodasz), konstruktorów jest za nami. Teraz pora na dodanie obsługi. Na pewno musicie dodać PageControl'a
i podstawowy interfejs jest zrobiony, a i jeszcze trzeba zrobić jakikolwiek przycisk aby można było dodawać taby. Tutaj podam przykładową metodę dodawania zakładek.
type
TfrmMain = class(TForm)
//...//
pgcTabs: TPageControl;
private
lstTabs: TList; // to ta główna lista; załóżmy, że już został zainicjowany i jest zdatny do użycia
procedure AddTab;
end;
//...//
procedure TfrmMain.AddTab;
begin
// opieram się na przykładowym TTabListItem
lstTabs.Add(TTabListItem.Create(Self)); // dodajemy instancje naszego obiektu-kontenera komponentów zakładki
// i to wszystko xD
end;
Więc ten krótki kod dodaje nową zakładkę. Analogicznie tworzymy usuwanie zakładki:
procedure TfrmMain.DeleteTab;
begin
lstTabs.Delete(pgcTabs.ActivePageIndex);
end;
To są najbardziej esencjonalne funkcje operowania na zakładkach.
Kodowanie obsługi zdarzeń
Teraz zajmijmy się obsługą zdarzeń. W naszych kontenerach wystarczy dodać procedurę do obsługi zdarzenia i podczas konstruowania przypisać do kontrolki.
Przypisywania nie pokaże bo jest to podstawa w Delphi, lecz pokażę wam przykład metodę obsługującą zdarzenie.
// powiedzmy że dodałem procedurę OnClick w kontenerze, poziom dostępu private
procedure TTabListItem.OnClick(Sender: TObject);
begin
if Sender is TWebBrowser then // dzięki temu boskiemu operatorowi możemy utworzyć jedną metodę dla wielu eventów
begin
ShowMessage((Sender as TWebBrowser).LocationURL); // mam nadzieje że Dialogs jest dodany do uses :D
end;
end;
Ten kod obsługuje event kliknięcia i pokazuje aktywny URL przeglądarki.
Aby podpiąć wystarczy - jak mówiłem - przypisać to właściwości OnClick w FWebBrowser.
Obsługa pojedynczych obiektów i operacje na obiektach przechowywanych
Przy obsłudze pojedynczych obiektów wystarczy rzutować wskaźniki na kontener i operować na właściwościach lub metodach zaimplementowanych w kontenerze. Podam wam mały przykład (mocno obcięty).
TTabListItem(lstTabs[pgcTabs.ActivePageIndex]).TabSheet.Caption := 'Inna nazwa hehe';
Kodowanie dekonstruowania (oraz konstruowania) listy
Jeśli chodzi o konstrukcję i dekonstrukcję - trzeba zrobić w eventach OnCreate, OnDestroy - konstrukcję obiektu TList, a w drugim dekonstrukcję (czyli po prostu Free). Chyba to nie jest jakaś filozofia, aby "przypisać" konstruktor do zmiennej TList, a potem wywołać metodę Free, co nie?
Aspekty dwóch metod zakładek
Cechy | Metoda obiektów | Metoda list zagnieżdżonych |
---|---|---|
Rozszerzanie zakładek o komponenty | Jest trochę upośledzone | Bardzo łatwe |
Enkapsulacja | Bardzo naturalne | Mniej naturalne (więcej pisania) |
Obsługa obiektów w kontenerach | Bardzo łatwe | Trudne |
W listach zagnieżdżonych trudnością jest wielokrotne rzutowanie i za tym idzie rozległość kodu.
Porównując metody operacji na tabelach komponentów w głównych komponencie, widać że, jest bardziej zbugowany (wg mnie).
W tych metodach ma się kontrolę nad uwalnianiem obiektów i operacji na nich. Można też poddać kontener enkapsulacji, czyli "obiciu" kodu w wygodny interfejs.
Podsumowanie
Na razie to wszystko, jeszcze będę dodawać nowe wzmianki, poprawki itp.
Mało fajne zakończenie, ale cóż... najważniejszy jest środek :)
P.S: jak ktoś ma pomysły to niech mówi na komentarzach: