pętle komunikatów jako metody klasy

0

Opakowując winapi w klasy doszedłem do problemu z pętlami komunikatów - w konstruktorze klasy c_window podaje

temp.lpfnWndProc = static_window_proc;

statyczną metodę w której to aby mieć dostęp do zmiennych w klasie które statyczne nie są przechodzę w taki sposób

LRESULT CALLBACK c_window::static_window_proc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{

    if (msg == WM_CREATE) {
        SetWindowLong(hwnd, GWL_USERDATA, lParam);
    }

    c_window* my_window = (c_window *) GetWindowLong(hwnd, GWL_USERDATA);
    if (my_window)
        return my_window->window_proc(hwnd, msg, wParam, lParam);

    return DefWindowProc(hwnd, msg, wParam, lParam);

}

do niestatycznej metody procedury okna i to załatwia problem z dostępem do zmiennych w klasie a teraz moje pytanie :: w jaki sposób w tej metodzie uzyskać dostęp do konkretnego obiektu jakiejś klasy np c_edit, c_button ?
Gdy np chce w procedurze jakiegoś okna ustawić....

case WM_KEYDOWN:
            if ( wParam == VK_TAB ) {
                main_edit->set_focus();   // jak uzyskać dostęp do obiektu main_edit który jest utworzony w funkcji WinMain
            }
0

Opakowując winapi w klasy doszedłem do problemu z pętlami komunikatów

Chyba mylisz pojęcia. "pętla komunikatów" to while(GetMessage()) DispatchMessage().
To jest właśnie ta magiczna pętla komunikatów.

WndProc to „procedura obsługi okna”, i wywoływana jest przez DispatchMessage().

    if (msg == WM_CREATE) {
        SetWindowLong(hwnd, GWL_USERDATA, lParam);
    }

To jest źle. Jeśli chcesz wykorzystać wartość podaną jako ostatni parametr w CreateWindow, to nie jest ona tak po prostu w lParam, ale w strukturze, do której wskaźnik podano w lParam.
Poza tym, jeśli kod ma być kompatybilny z architekturą 64-bitową (na przyszłość...) to nie SetWindowLong, a SetWindowLongPtr.

	if (msg==WM_NCCREATE)
		SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)LPCREATESTRUCT(lParam)->lpCreateParams);
	// użyłem `WM_NCCREATE` bo to on jest pierwszy. Ale `WM_CREATE` też jest prawidłowo.
    c_window* my_window = (c_window *) GetWindowLong(hwnd, GWL_USERDATA);

Tutaj też przerób na GetWindowLongPtr i GWLP_USERDATA.

main_edit->set_focus();   // jak uzyskać dostęp do obiektu main_edit który jest utworzony w funkcji WinMain

Nie rozumiem problemu. Jeśli main_edit jest polem klasy, to masz już dostęp przez pobrany wskaźnik c_window* my_window.
A jeśli nie jest polem, tylko zmienną lokalną w WinMain, to... uczyń ją polem?

PS. poza tym, jak już tworzysz klasę, to coś takiego jak otwieranie okna i tworzenie kontrolek powinno być w metodzie tej klasy (albo nawet w konstruktorze), a nie w osobnej globalnej funkcji (WinMain).

0

Masz racje, chodziło mi oczywiście o procedurę okna ;) Dzięki za wskazówki do tych fragmentów kodu ;) Problem z tym dostępem polega na tym że są to 2 oddzielne klasy - main_edit to obiekt klasy c_edit który kojarzę z konkretnym obiektem klasy c_window w funkcji WinMain fragment WinMain ::

c_window main_window;
main_window.set_title( "App : : " );

c_edit edit( main_window );

c_button process( main_window );
process.set_title( "process" );

main_window.out();

więc main_edit nie jest polem klasy c_window, i nie bardzo tym polem być może...

0

Nawet gdybym te wszystkie opcje ( tworzenie buttona, edita, statusbara ) zamknął w klasie c_window ( masakra ) to i tak problem zostaje np gdy w procedurze jednego okna na jakieś zdarzenie chce otworzyć inne okno do którego muszę się jakoś odwołać... może wiecie jak to jest rozwiązane w innych bibliotekach? MFC? VCL? globalna główna procedura?

0

Ale jaki widzisz problem, by klasa c_window (głównego okna) miała pole typu c_edit?

Tak to właśnie robią wszystkie biblioteki.

Wszystkie kontrolki twórz w metodzie albo konstruktorze klasy głównego okna, a nie w zewnętrznej funkcji.

0

Ok to w związku z tym co powiedziałeś jeszcze 2 pytania - każde okno może mieć różną ilość kontrolek rożnego typu jedno 2 inne 30 jak przechowywać te obiekty / uchwyty w klasie? np w vectorze< c_edit > ?

I drugie pytanie jeżeli aplikacja składa się z więcej niż 1 okna to te kolejne też tworzyć w klasie głównego okna i umieszczać w vectorze lub jakimś innym dynamicznym kontenerze?

Czy może w ogóle odpuścić sobie zabawę z pakowaniem funkcji winapi w klasy ( narzucone jest winapi, nie ma mowy o klasach więc ode mnie zależy jak to zrobię ) a jedynie jak już muszę wykorzystać winapi to zrobić to zgodnie z jego przeznaczeniem czyli proceduralnie z kilkoma klasami pomocniczymi

0

Nowy rodzaj okna --> nowa klasa.

Możesz mieć podstawową klasę c_window, tworzącą puste okno, i po niej dziedziczyć dodając kontrolki.

class c_windowMain : public c_window

jak przechowywać te obiekty / uchwyty w klasie? np w vectorze< c_edit > ?

Kontrolki też mogą mieć wspólną nadrzędną klasę, np. c_control, i po niej dziedziczą c_edit, c_button.
Potem robisz vector<c_control*>, albo coś tego typu.

I drugie pytanie jeżeli aplikacja składa się z więcej niż 1 okna to te kolejne też tworzyć w klasie głównego okna i umieszczać w vectorze lub jakimś innym dynamicznym kontenerze?
Zależy jak ma aplikacja wyglądać.
Chcesz mieć te kilka okien otwartych jednocześnie?
Dodatkowe okna otwierasz albo przez CreateWindow (oprogramowujesz je tak samo jak główne), albo DialogBox lub CreateDialog (na trochę innych zasadach, za to można skorzystać z designera dialogów).

Czy może w ogóle odpuścić sobie zabawę z pakowaniem funkcji winapi w klasy
Dobrze zacząłeś, zrób na klasach.
Możesz nawet rozbić WndProc na poszczególne komunikaty, z metodami np. OnMouseDown, OnCommand, OnCośtam...

0

zabijesz mnie ;d ale nie wiem czy dobrze to zrozumiałem.... główna klasa aplikacji / okna w której znajduje się główna procedura aplikacji z której obsługuje wszystko i w której przechowuje vectory na utworzenie ewentualnych kontrolek, okien pochodnych mogłaby wyglądać mniej więcej tak? ::

class c_window
{
    private:
        HWND main_window;
        
        std::vector< c_window * > child_window_list;
        std::vector< c_statusbar * > statusbar_list;
        std::vector< c_edit* > edit_list;
        std::vector< c_button * > button_list;
        
    public:
        c_window();
        
        static LRESULT CALLBACK static_window_proc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
        LRESULT CALLBACK window_proc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );

        void add_child_window();
        void add_statusbar();
        void add_edit();
        void add_button();
};

ale teraz i tak w każdej klasie c_edit, c_button, c_statusbar muszę zdublować 2 procedury obsługi okna jedna static a drugą nie które będą odpowiadały za obsługę tych okien?

może jesteś w stanie podesłać jakiegoś linka do strony gdzie mógłbym zobaczyć jak wygląda taka klasa okna, jak tworzone i przechowywane są w niej kontrolki oraz jak procedura tego okna obsługuje zdarzenia odnoszące się w tych kontrolkach bo chyba się już pogubiłem

1

Protip: ktoś już wpadł kiedyś na ten sam pomysł. Ze strony Microsoft masz dla rozwiązania dla C++: MFC i jego bardzo lekki brat WTL.

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