Wyszukiwanie obiektów w drzewie

From MorphOS Library

Grzegorz Kraszewski


Ten artykuł w innych językach: angielski


Po stworzeniu kompletnego drzewa obiektów, nie ma bezpośredniego dostępu do żadnego z nich, oprócz obiektu głównego, klasy Application. Jakiś dostęp jednak jest potrzebny, można go uzyskać na trzy sposoby:

  • Wskaźniki do obiektów jako zmienne globalne. To najprostszy sposób, może się sprawdzać w małych projektach. Jego wadą jest naruszanie zasad projektowania obiektowego (np. zasady enkapsulacji danych) i bałagan jaki się tworzy gdy liczba zmiennych globalnych osiąga 50, 100 i więcej.
  • Przechowywanie wskaźników do obiektów w polach obszaru danych jakiegoś obiektu (na przykład obiektu aplikacji). To dobry pomysł, ale problematyczny w implementacji. Obszar danych obiektu istnieje dopiero po jego stworzeniu (dokładniej - po wykonaniu konstruktora w klasie rootclass), a obiekt aplikacji jest tworzony jako ostatni. Wskaźniki do obiektów potomnych musiałyby być przechowywane w jakichś zmiennych tymczasowych. Ta technika zakłada również, że obiekt nadrzędny wobec tego, do którego potrzebny jest dostęp, jest obiektem jakiejś klasy niestandardowej (z przeciążonym konstruktorem). Oprócz tego zakłada, że obiekt nadrzędny tworzy nasz poszukiwany w tymże konstruktorze, co nie zawsze musi być prawdą.
  • Użycie atrybutu MUIA_UserData i metody MUIM_FindUData() w celu dynamicznego wyszukiwania obiektów. To najlepsze rozwiązanie, gdy dostęp do obiektów potrzebny jest nie za często (na przkład tylko raz, w celu ustawienia notyfikacji). Jeżeli dostęp zachodzi często (powiedzmy kilka razy na sekundę i częściej) można tę technikę połączyć z przechowywaniem wskaźników w obiekcie nadrzędnym.

Wyszukiwanie dynamiczne działa następująco: każdy obiekt, jaki będzie później wyszukiwany, ma atrybut MUIA_UserData ustawiony na określoną, unikalną wartość. Następnie w dowolnym momencie można uzyskać wskaźnik do tego obiektu wywołując metodę MUIM_FindUData() na jego obiekcie (bezpośrednio lub pośrednio) nadrzędnym, na przykład na obiekcie aplikacji, który jest nadrzędny dla wszystkich innych.

#define OBJ_JAKIS_PRZYCISK 36

/* Gdzieś w wartościach początkowych dla atrybutów obiektu */
MUIA_UserData, OBJ_JAKIS_PRZYCISK,
/* ... */

/* Chcemy uzyskać wskaźnik do obiektu */

Object *jakis_przycisk;

jakis_przycisk = (Object*)DoMethod(App, MUIM_FindUData, OBJ_JAKIS_PRZYCISK);

Ponieważ to bardzo często wykonywana operacja, wygodnie jest opakować ją w makro:

#define findobj(id, parent) (Object*)DoMethod(parent, MUIM_FindUData, id)

jakis_przycisk = findobj(OBJ_JAKIS_PRZYCISK, App);

Makro można oczywiście bezpośrednio wywoływać w innych funkcjach, na przykład przy zmianie atrybutów, albo w notyfikacjach. Oto przykład zmieniający tekst przycisku:

set(findobj(OBJ_JAKIS_PRZYCISK, App), MUIA_Text_Contents, "Kliknij");

Trzeba zauważyć, że makro findobj() nie jest zdefiniowane w systemowych plikach nagłówkowych MUI, trzeba je zdefiniować samodzielnie w kodzie programu.