[#1] Własne klasy
Witam!

Podczas tworzenia własnej klasy na podstawie istniejącej już klasy MUI
często zachodzi potrzeba zmodyfikowania wiadomości przekazywanych do
klasy nadrzędnej (msg). Proglem w tym, że nie wiem skąd czerpać
informacje na temat wyglądu owego msg, który przecież zależy od danej
metody. Przykładowo chcę, aby podczas wykonywania metody:

DoMethod(txtObiekt, MUIM_Set, MUIA_Text_Contents, "tekst");

string "tekst" był najpierw zamieniany na wielkie litery, a dopiero
potem przekazywany metodzie odpowiedzialnej za jego wyświetlenie.
Domyślam się, że trzeba to zrobić jakoś tak:

SAVEDS ULONG mChangeText(struct IClass *cl, Object *obj, Msg msg)
{
  /* zamiana na wielkie litery */

  return (DoSuperMethodA(cl, obj, msg));
}

Gdzie dispatcher przekierowuje wywołanie MUIM_Set do powyższej metody.
Przy czym nie mam pojęcia, jak dostać się do stringu przekazywanego
metodzie klasy nadrzędnej. Innymi słowy: co powinno mieścić się w:
/* zamiana na wielkie litery */?

Pomożecie? ;)
[#2] Re: Własne klasy

@Kamul, post #1

sredni przyklad podales. mozna uzyc MUIM_Set ale tutaj lepszym wyjsciem jest SetAttrs(obj, ...) czyli:

SetAttrs(obj, MUIA_String_Contents, tekst, TAG_DONE);

ewentualnie makro set().

Pomijajac to (bo MUIM_Set i tak wywola OM_SET), w swojej klasie ktora przeciaza klase string w metodzie OM_SET przechwytujesz obsluge tagu MUIA_String_Contents. Mozesz oznaczyc oryginalny tag jako ignorowany i wystawic wlasny z nowa zawartoscia, lub po prostu zmodyfikowac dane bedace atrybutem tagu. Metoda OM_SET twojej klasy wygladalaby mniej wiecej tak:

ULONG fooSet(struct IClass *cl, Object *obj, struct opSet *msg)
{
struct TagItem *tag = FindTagItem(MUIA_String_Contents, msg->ops_AttrList);

if (tag != NULL)
{
char *str = tag->ti_Data;
while(*str)
{
*str = toupper(*str);
str++;
};
}

return DoSuperMethodA(cl, obj, (Msg)msg);
}

voila!

[#3] Re: Własne klasy

@kiero, post #2

Modyfikacja wartości argumentu to raczej słaby pomysł ponieważ nie wiadomo do czego ta wartość jeszcze będzie wykorzystywana poza tym może to być string na stałe wpisany w kodzie. Należy skopiować wartość i na tej kopi operować.

[#4] Re: Własne klasy

@Kamul, post #1

Proglem w tym, że nie wiem skąd czerpać
informacje na temat wyglądu owego msg


Podstawowe metody są zdefiniowane w , te specyficzne dla MUI w .
SAVEDS ULONG mChangeText(struct IClass *cl, Object *obj, struct opSet *msg)
{
  STRPTR text;
  text = (STRPTR)GetTagData(MUIA_Text_Contents, 0, msg->ops_AttrList);
  if (text) ZmianaLiter(text);
  return (DoSuperMethodA(cl, obj, (Msg)msg));
}




Ostatnia modyfikacja: 29.12.07 14:47
[#5] Re: Własne klasy

@smith, post #3

dlatego napisalem o podstawianiu wlasnego tekstu. a ze podmiana aktualnego jest prostsza to na potrzeby przykladu zrobilem wlasnie tak.

tak jeszcze po chwili. podiana tekstu to juz nieco bardziej skomplikowana sprawa. trzebaby w instancji klasy trymac sobie bufor i tam zapisywac nowe teksty. na koniec w dispose wywalic bufor.



Ostatnia modyfikacja: 29.12.07 14:30
[#6] Re: Własne klasy

@kiero, post #5

kiero napisał(a):

> dlatego napisalem o podstawianiu wlasnego tekstu.

aj tam łobuzie ;)

> a ze podmiana
> aktualnego jest prostsza to na potrzeby przykladu zrobilem
> wlasnie tak.

Tylko zeby Kamul-owi tak nie zostalo ;)

> tak jeszcze po chwili. podiana tekstu to juz nieco bardziej
> skomplikowana sprawa. trzebaby w instancji klasy trymac sobie
> bufor i tam zapisywac nowe teksty. na koniec w dispose wywalic
> bufor.

A moze byc jeszcze gorzej jesli takiej zmodyfikowanego obiektu klasy beda uzywaly dwa (albo wiecej) procesy... :)

[#7] Re: Własne klasy

@szuler, post #6

"A moze byc jeszcze gorzej jesli takiej zmodyfikowanego obiektu klasy beda uzywaly dwa (albo wiecej) procesy..."

humm, to juz niby leci do stringa i w tym momencie wszystko zaley od implementacji/specyfikacji (czy kopiuje on sobie dane do wlasnego bufora czy nie). w tym konkretnym przypadku (string ma wlasny bufor) jezeli nie mamy innej superklasy to bufor musi istniec tylko na czas wykonywania DoSuperMethod, czyli nawet na stosie moze byc. w przypadku ogolnym trzeba sie glebiej zastanowic:)

[#8] Re: Własne klasy

@kiero, post #2

Witam!

Przede wszystkim dzięki Wam za cenne informacje.

Próbowałem obu funkcji: GetTagData() i FindTagItem(). Za każdym razem gdy program dojdzie do lini zawierającej te instrukcje, pojawia się exception - load from a not existing page. Przykładowo gdy zastosuję kod Krashana, wskaźnik text uzyskuje wartość 0 (co, biorąc pod uwagę exception, wcale mnie nie dziwi). ;)

Mój dispatcher wygląda tak:
DISPATCHER(TestClass)
{
  switch (msg->MethodID)
  {
    case MUIM_Set:   return (mChangeText(cl, obj, (APTR) msg));
  }
  return (DoSuperMethodA (cl, obj, (APTR) msg));
}
DISPATCHER_END

Zaś klasę tworzę w ten sposób:
mccExtendedClip = MUI_CreateCustomClass(NULL, "Text.mui" /*MUIC_Text*/, NULL, 0, DISPATCHER_REF(ExtendedClipClass))

Czy ktoś ma pomysł, gdzie może leżeć przyczyna?

I drugie pytanie: gdybym chciał zrobić kopię stringa na użytek klasy, to czy (pomijam fakt, że GetTadData() zwraca mi na chwilę obecną 0) mogłoby to wyglądać mniej więcej tak:
struct Data { char str[100]; };

SAVEDS ULONG mChangeText(struct IClass *cl, Object *obj, struct opSet *msg)
{
  struct Data *data;
  STRPTR text;

  data = INST_DATA(cl, obj);
  if (text = (STRPTR) GetTagData(MUIA_Text_Contents, 0, msg->ops_AttrList))
  {
    strcpy (data->str, "nowy_tekst");
    text = data->str;
  }

  return (DoSuperMethodA(cl, obj, (Msg) msg));
}

i w MUI_CreateCustomClass() zamiast 0 - sizeof(struct Data)?
Czy trzeba jeszcze porzeźbić w konstruktorze i desktruktorze? Jeśli tak, to w jaki sposób - czy to jest dobry trop?
struct Data { STRPTR str; };

SAVEDS ULONG mNew(struct IClass *cl, Object *obj, Msg msg)
{
  struct Data *data;

  if (!(obj = (Object *) DoSuperMethodA(cl, obj, msg)))
    return (0);
  data = INST_DATA(cl, obj);
  if (data->str = AllocVec(100, MEMF_ANY))
    return ((ULONG) obj);
  else
    return (0);
}

SAVEDS ULONG mDispose (struct IClass *cl, Object *obj, Msg msg)
{
  struct Data *data;

  data = INST_DATA(cl, obj);
  if (data->str) FreeVec(data->str);
  return (DoSuperMethodA(cl, obj, msg));
}
[#9] Re: Własne klasy

@Kamul, post #8

Cisza...

To jakoś działa:
SAVEDS ULONG mShowExtendedText(struct IClass *cl, Object *obj, struct opSet *msg)
{
  struct Data *data;
  struct TagItem *tag = FindTagItem(MUIA_Text_Contents, msg->ops_AttrList);

  if (tag)
  {
    data = INST_DATA(cl, obj);
    strncpy (data->str, (STRPTR) tag->ti_Data, 90);
    strcat(data->str, "->dodatek");
    tag->ti_Data = (ULONG) data->str;
  }

  return (DoSuperMethodA(cl, obj, (Msg) msg));
}

Gdzie struct Data jest identyczna jak w poście powyżej.

Uzyskałem to, co chciałem - tzn. dane są kopiowane tak, że mogę w tej metodzie dokonać dowolne operacje na stringu. Nawet jeśli nowy string będzie dłuższy od starego. Nie czuję się jednak zbyt pewnie w programowaniu obiektowym (a mimo wszystko zaczynam to lubieć) ;) i dlatego mam do Was pytanie. Czy to co powyżej napisałem jest poprawne? Czy może działa to tylko przez przypadek i prędzej czy później system pójdzie w kosmos?
[#10] Re: Własne klasy

@Kamul, post #8

Próbowałem obu funkcji: GetTagData() i FindTagItem(). Za każdym razem gdy program dojdzie do lini zawierającej te instrukcje, pojawia się exception - load from a not existing page.

Nic dziwnego, bo powinieneś przechwytywać OM_SET a nie MUIM_Set, ta druga ma zupełnie inną wiadomość (nie ma w niej taglisty).

Czy trzeba jeszcze porzeźbić w konstruktorze i desktruktorze?

Przy 100 bajtach lepsze jest moim zdaniem umieszczenie bufora na żywca w obiekcie.

[#11] Re: Własne klasy

@Kamul, post #9

wszystko zle:) w poprzednim przykladzie przeciazasz MUIM_Set a potem jako argument przyjmujesz opSet. ZLE. opSet jest argumentem tylko dla OM_SET. Dla MUIM_Set jest to po prostu para atrybut,wartosc, czyli cos takiego:

struct MUIP_Set{
ULONG MethodID;
ULONG attr;
ULONG val;
};

ULONG fooSet(struct Iclass *cl, Object *obj, struct MUIP_Set *msg);

w tym przypadku nie wyszukujesz zadnych tagow. tagi masz tylko w OM_SET. Przeczytaj co napisalem w swoim pierwszym poscie. Jezeli chcesz to ciagle zrobic na MUIM_Set, to swoja metoda powinna wygladac tak:

{
if (msg->attr == MUIA_String_Contents)
{
// zmiana
}

return DoSuperMethodA(cl, obj, (Msg)msg);
}

[#12] Re: Własne klasy

@Kamul, post #9

Zależy jakie masz założenia, na 1 rzut oka jest kilka niebezpieczeństw
1) jeśli data->str jest mniejsze niż kopiowany string
2) jeśli tag->ti_Data jest krótsze niż 90 znaków, to spoko, ale jak
dłuższe, albo równe, to znów może być zonk strcat zle zadziała. Błędy
te nie mają nic wspólnego z programowaniem obiektowym, raczej z
programowaniem w języku C.

[#13] Re: Własne klasy

@Grzegorz Kraszewski, post #10

Ups... Zapomniałem dodać, że to iż powinienem się zająć OM_SET, a nie MUIM_Set zdążyłem zauważyć po iluś tam nieudanych próbach. I tak też robię.

Przy 100 bajtach lepsze jest moim zdaniem umieszczenie bufora na żywca w obiekcie.

Czy jeśli potrzebny by był znacznie dłuższy bufor, to czy można to zrobić mniej więcej tak, jak to przedstawiłem na dole ósmego posta?
[#14] Re: Własne klasy

@kiero, post #11

wszystko zleusmiech w poprzednim przykladzie przeciazasz MUIM_Set a potem jako argument przyjmujesz opSet. ZLE. opSet jest argumentem tylko dla OM_SET. Dla MUIM_Set jest to po prostu para atrybut,wartosc, czyli cos takiego:

Oczywiście racja. Jak przed chwilą napisałem, zapomniałem poinformać, że po jakimś czasie zauważyłem tą niefortunną zawartość dispatchera. :)

Po drodze zrodziło mi się takie pytanie: czy (pod warunkiem, że będę to robił konsekwentnie) ;) jest wszystko jedno, którą z tych dwóch metod przeciążę? A może jeden ze sposobów jest pod jakimś względem lepszy od drugiego?
[#15] Re: Własne klasy

@Kaczus, post #12

1) jeśli data->str jest mniejsze niż kopiowany string

To chyba nie jest groźne, bo użyłem strncpi(), a nie strcpi(). Zresztą docelowo i tak moja metoda będzie wyglądać inaczej.

Mnie chodzi raczej o to, czy od strony obiektowości, MUI itp. kod jest poprawny. Jeśli w tym miejscu macie jakieś sugestie, to z chęcią ich wysłucham. :)
[#16] Re: Własne klasy

@Kamul, post #14

"Po drodze zrodziło mi się takie pytanie: czy (pod warunkiem, że będę to robił konsekwentnie) jest wszystko jedno, którą z tych dwóch metod przeciążę? A może jeden ze sposobów jest pod jakimś względem lepszy od drugiego?"

OM_SET lezy nizej niz MUIM_Set. MUIM_Set wychwyci jedynie odwolania wlasnie poprzez ta metode. OM_SET wszystkie sety (MUIM_Set wywoluje pozniej wlasnie OM_SET).

[#17] Re: Własne klasy

@Kamul, post #13

Czy jeśli potrzebny by był znacznie dłuższy bufor, to czy można to zrobić mniej więcej tak, jak to przedstawiłem na dole ósmego posta?

Tak.

[#18] Re: Własne klasy

@Kaczus, post #12

Witam!

Móglbyś rozwinąć punkt 2, bo ja nie za bardzo chwytam. Bardzo dziękuje.

Pozdrawiam

[#19] Re: Własne klasy

@asman, post #18

asman napisał(a):

> Witam!
>
> Móglbyś rozwinąć punkt 2, bo ja nie za bardzo chwytam. Bardzo
> dziękuje.
masz kod:
strncpy (data->str, (STRPTR) tag->ti_Data, 90);
strcat(data->str, "->dodatek");

jesli tag->ti_Data bedzie dluzzy badz rowny 90 znakow, wtedy string nie bedzie zakonczony. A gdy nie bedzie wczesniej wyzerowany, to pojawi sie zonk przy strcat. Nalezy pamietac, ze funkcja strncpy nie terminuje stringu, sami musimy go zaterminować.

[#20] Re: Własne klasy

@Kaczus, post #19

nie terminuje jezeli zabraknie miejsca. w normalnych przypadkach terminuje. polecam strlcpy lub na amigowych kompilatorach stccpy. skladnia taka sama. wydajniejsze (nie wypelniaja zerami pozostalej czesci ciagu) i zawsze terminuja ciag wynikowy.

[#21] Re: Własne klasy

@kiero, post #20

Dlatego napisalem, ze w przypadku, gdy kopiowany ciąg będzie dłuższy niz te 90 znakow, bądź równy 90 znakom, to string nie zostanie zaterminowany.

[#22] Re: Własne klasy

@Kaczus, post #19

Jak już pokazujesz przykład ze strncpy() + strcat(), to i strncat() powinieneś zapodać by być konsekwentnym ;)

Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem