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:

0 komentarzy