Obiekt własnej klasy w aplikacji okienkowej - WinApi i procedura okna

0

Witam,
stworzyłem sobie jakiś czas temu dość zaawansowaną klasę w konsoli. Teraz chciałbym ją nieco zmodyfikować i wykorzystać w nowym projekcie napisanym w WinApi. Klasa ma wiele funkcji, i w zależności od naciśniętego przycisku powinna wykonywać różne rzeczy. Mam jednak pewną wątpliwość, gdzie powinienem zadeklarować obiekt takiej klasy?
Jeśli zadeklaruję ją w funkcji main to nie będę miał dostępu do niej dostępu w procedurze okna, która przetwarza różne zdarzenia - np.wciśnięcie przycisku... Wydaje mi się, że w takim razie wszystkie własne klasy powinienem deklarować albo globalnie albo w procedurze okna.
Czy mógłby mi ktoś potwierdzić czy słusznie rozumiem problem? Który sposób jest bardziej praktyczny?
pozdrawiam i dziękuję za okazaną pomoc.

0

Aha i co jeśli będę chciał jakąś metodę klasy wywołać w innym okienku? Wówczas pozostaje tylko opcja globalnego deklarowania obiektu - co trochę mi się nie podoba ;-(

0

Jeżeli jest to klasa coś na wzór narzędzia to jak najbardziej można globalnie lub dodatkowo pokusić się o singleton.

0

Powinna się znajdować tuż obok uchwytu do okna głównego gdziekolwiek go trzymasz.

0
_13th_Dragon napisał(a):

Powinna się znajdować tuż obok uchwytu do okna głównego gdziekolwiek go trzymasz.

No dobra, ale jak mam taki kod:

LRESULT CALLBACK ProceduraOkna(...);

int WINAPI WinMain(...){
WNDCLASSEX wndclassex;
//...wypełnienie klasy okna (wndclassex)
RegisterClassEx(&wndclassex);

HWND UchwytOkna = 0;

moja_klasa obiekt_mojej_klasy; //<- TUTAJ JEST OBIEKT MOJEJ KLASY

uchwytOkna = CreateWindowEx(...);
ShowWindow(uchwytOkna, SW_NORMAL);
UpdateWindow(uchwytOkna);

MSG msg;
while(GetMessage(&msg,0,0,0)
   {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
   }
}

LRESULT CALLBACK ProceduraOkna(...)
{
switch(message)
   {
   case WM_COMMAND:
   //JAK MOGĘ SIĘ DOSTAĆ DO obiektu "obiekt_mojej_klasy", który zadeklarowałem w funkcji main obok "uchwytu do okna głównego"?
   //chciałbym np. wywołać funkcję obiekt_mojej_klasy.funkcja(); gdy użytkownik naciśnie jakiś przycisk - ale w tym miejscu nie mam dostępu do mojego obiektu...
   //...
   }
}

To jak mogę wywołać funkcję mojego obiektu po naciśnięciu jakiegoś przycisku? Przecież w procedurze okna obiekt ten nie będzie widoczny...

0

I jak? Jakieś koncepcje poza deklaracją obiektu globalnie? Ma ktoś może jakiś pomysł?
Jak to się robi w praktyce? Ja dopiero się uczę...
Nie podoba mi się to ;-(

0

zawsze możesz zrobić coś takiego:

moja_klasa &DawacUnikalnaMojaKlase()
  {
   static moja_klasa obiekt_mojej_klasy;
   return obiekt_mojej_klasy;
  }
0
_13th_Dragon napisał(a):

zawsze możesz zrobić coś takiego:

moja_klasa &DawacUnikalnaMojaKlase()
  {
   static moja_klasa obiekt_mojej_klasy;
   return obiekt_mojej_klasy;
  }

Ciekawe rozwiązanie, ale to chyba nie było na serio? Czy tak na prawdę się robi w praktyce? O_o
Myślałem bardziej o takim rozwiązaniu, co podałeś wcześniej tj. z deklaracją mojego obiektu bezpośrednio w funkcji main...

0

Ok, zakładam, że milczenie oznacza, że innej opcji po prostu nie ma ;)
Nie wiem dlaczego, ale do obiektów globalnych jestem jakoś uprzedzony... jednak w takim razie zdecydowałem się na jego utworzenie ;P
Mam jednak jeszcze jedno pytanie:
Czy z praktycznego punktu widzenia jest jakaś różnica między utworzeniem obiektu globalnego z utworzeniem wskaźnika do niego a w funkcji main utworzenie obiektu operatorem new?
Chodzi mi o to, że zbudowana klasa jest dość rozbudowana (ma wiele funkcji, zmiennych i wiele pętli wykonujących miliony operacji :) ) a na niej ma się opierać cały program więc wolę się upewnić, gdyż wypadałoby zastosować rozwiązanie optymalne... ;)

0

Globalne zmienne są złe ponieważ łatwo o kolizje nazw w wielu przypadkach.
Wyjściem jest:

  1. namespace
  2. statyczne pole w klasie
  3. to co opisałem wyżej, ewentualnie co na to samo wychodzi:
struct Dawac
  {
   moja_klasa *operator->()const
    {
     static moja_klasa obiekt_mojej_klasy;
     return &obiekt_mojej_klasy;
    }
  };

//użycie:
Dawac()->Metoda_z_moja_klasa();
Dawac()->Skladowa_z_moja_klasa=10;
0

Dzięki Ci @_13th_Dragon za pomoc! Kolejny całkiem ciekawy przykład ;).
Jeśli chodzi o moją klasę to raczej zbieżność nazw mi nie grozi :P. Ewentualnie rzeczywiście mogę profilaktycznie zastosować namespace.
Chciałem się jednak na koniec jeszcze upewnić czy jakbyś miał wybór zdefiniować globalnie wskaźnik i utworzyć obiekt wewnątrz funkcji main a utworzyć globalnie obiekt i się do niego bezpośrednio odwoływać to co byś wybrał? Czy są jakieś wady lub zalety któregoś z tych rozwiązań?
Niestety nie za bardzo rozumiem komentarz @ Furious Programming, który napisał tj.

Jeśli wskaźnik będzie globalny, to według mnie nie ma sensu go wykorzystywać;

Jeszcze raz dzięki!

0

@furious programming, odpowiedział ci na pytanie które teraz zadajesz.
Jeżeli masz globalny wskaźnik to już masz wszystkie wady zmiennej globalnej do których to (wad) jeszcze dokładasz podstawienie obiektu pod niego.
Więc gorszego rozwiązania niż - "globalnie wskaźnik i utworzyć obiekt wewnątrz funkcji main" - raczej nie istnieje.

0

Dziękuję Ci bardzo za pomoc @_13th_Dragon! Pozostałym osobom, mimo, że mnie aktywnym, również!

Mam teraz ostatnie pytanie, bo właśnie zauważyłem Twój komentarz pod moim 3 postem - gdzie umieściłem kod, który brzmi następująco:

Nie dasz rady poprawnie obsłużyć wszystkich komunikatów nie znając własnego uchwytu okna. Masz już błąd koncepcyjny.

Czyli chodzi Ci o to, by utworzyć uchwyt okna również globalnie?
Bo uchwyt okna jest! - najpierw go deklaruję a następnie przypisuję wynik funkcji CreateWindowEx (tuż za deklaracją mojego obiektu).
I teraz nie wiem czy ja znowu czegoś nie rozumiem, czy może Ty tego nie zauważyłeś i komentarz jest nieaktualny?
pozdrawiam

0

Dziękuję Ci jeszcze raz @_13th_Dragon!
pozdrawiam

0

Tak można przenieść wskaźnk z main do WndProc:

main:

	
	hWnd = CreateWindow(bla, bla, ..., bla, &obiekt_mojej_klasy); // ostatni parametr
	

WndProc:

		case WM_CREATE:
		{
			LPCREATESTRUCT cs = (LPCREATESTRUCT)lParam;
			moja_klasa *obiekt_mojej_klasy = (*obiekt_mojej_klasy)cs->lpCreateParams;
			...
		}

Haczyk jest w tym, że z lpCreateParams można skorzystać tylko w WM_CREATE - więc i tak trzeba tę wartość gdzieś zapisać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1