2010-08-01 8 views
7

Chcę utworzyć własną klasę do obsługi tworzenia okien i procedury okna, ale zauważyłem, że procedura okna musi być statyczna! Zastanawiam się teraz, czy można uczynić obiekt okna obiektem zorientowanym? Czytałem kilka samouczków dotyczących okien zorientowanych obiektowo, ale one zawsze powodują, że procedura jest statyczna -.- Jakie jest tego zastosowanie? :/Object oriented C++ win32?

Wszelkie linki lub informacji o tym, jak ominąć ten problem byłoby mile widziane,

dzięki

+0

Zobacz najlepszą metodę przechowywania tego wskaźnika do użytku w WndProc ] (http://stackoverflow.com/questions/117792/best-method-for-storing-this-pointer-for-use-in-wndproc). –

+2

Z tego powodu zawsze chciałem, aby 'WndProc' miał parametr" void * user_data ". Dzięki temu tworzenie wrapperów opartych na obiektach byłoby o wiele łatwiejsze. –

+0

@Evan: Tak, ale wymagałoby to również kogoś * przy zdrowych zmysłach * do projektowania interfejsu API ... Win32 API byłby zupełnie inną bestią, gdyby tak było. – jalf

Odpowiedz

11

można obejść, że poprzez statyczne WndProc przekazać wszystko do członków:

// Forward declarations 
class MyWindowClass; 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 

std::map<HWND, MyWindowClass *> windowMap; 

// Your class 
class MyWindowClass { 
private: 
    HWND m_handle; 

    // The member WndProc 
    LRESULT MyWndProc(UINT message, WPARAM wParam, LPARAM lParam) { /* ... */ } 

public: 
    MyWindowClass() 
    { 
    /* TODO: Create the window here and assign its handle to m_handle */ 
    /* Pass &WndProc as the pointer to the Window procedure */ 

    // Register the window 
    windowMap[m_handle] = this; 
    } 
}; 

// The delegating WndProc 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    std::map<HWND, MyWindowClass *>::iterator it = windowMap.find(hWnd); 
    if (it != windowMap.end()) 
    return it->second->MyWndProc(message, wParam, lParam); 
    return 0; 
} 
+1

+1, ale możesz również chcieć sprawdzić WM_DESTROY i usunąć uchwyt z mapy. – SoapBox

+0

ładny przykład, wygląda świetnie. Spróbuję go zaimplementować w moim własnym, przyjemnym użyciu std :: map, aby znaleźć pasujący uchwyt. – Kaije

+0

@SoapBox Jest niekompletny pod wieloma względami, dziękuję za uwagę. –

3

Jeśli szukasz obiektowego Win32 API następnie należy spojrzeć na MFC i/lub WTL.

+0

Rozwiązania typu "Overkill" do wielu celów. MFC może być * względnie * cienki, ale wciąż jest dużym interfejsem API, a przełączanie się z jednego interfejsu API na drugi to dużo pracy. Jest również całkowicie niepotrzebne, jeśli chcesz tylko użyć kilku własnych klas C++ podczas kodowania Win32. Moja własna stara "struktura obiektowa" dla Win32 była prawdopodobnie około 2 lub 3 stronami kodu - niewiele więcej niż klasa podstawowa, inicjalizacja i główna pętla GetMessage/etc. – Steve314

+0

Materia opinii –

+0

MFC to nieprzyjemny framework, ale jest dobrze obsługiwany i stosunkowo dobrze znany w świecie Win32. – seand

1

Możesz użyć uchwytu okna przekazanego do WindowProc, aby pobrać obiekt utworzony dla tego konkretnego okna i przekazać obsługę zdarzeń do tego obiektu.

np.

IMyWindowInterface* pWnd = getMyWindowObject(hWnd); 
pWnd->ProcessMessage(uMsg, wParam, lParam); 
+0

Brzmi nieźle, zauważyłem, że jedyną unikalną rzeczą w procedurze jest uchwyt, ale nie byłem pewien, jak znaleźć moje okno przez to. jak w twoim przykładzie getMyWindowObject (hwnd), czy ta funkcja polegałaby na iteracji przez moje otwarte okna, aby sprawdzić, czy uchwyt pasuje? ponieważ jeśli tak, czy obsługiwał WM_MOUSEMOVE lub WM_TIMER, nie byłoby to nużące dla procesora? – Kaije

+0

Najlepiej, jeśli użyjesz jakiejś formy hashtable na hasz z HWND do wskaźników do obiektu-okna - to było szybkie wyszukiwanie. Jeśli nie masz dość dużej liczby otwartych okien, spodziewałbym się, że pętla przez wszystkie pary (HWND, obiekt *) będzie wystarczająco szybka ". –

6

Ogólna technika pozwala instancji okna mają być reprezentowane przez co klasy instancji jest do wykorzystania SetWindowLongPtr i GetWindowLongPtr do powiązania wskaźnika instancji klasy z uchwytem okna. Poniżej znajduje się przykładowy kod, aby rozpocząć. Może się nie skompilować bez kilku poprawek. To ma być tylko odniesienie.

Osobiście przestałem rozwijać własne klasy okienne kilka lat temu, kiedy odkryłem klasę szablonów ATW CWindow i CWindowImpl. Dbają o to, abyś zrobił to przyziemne kodowanie, więc możesz skupić się na pisaniu metod, które obsługują wiadomości w oknie. Zobacz przykładowy kod, który napisałem: here.

Mam nadzieję, że to pomoże.

class CYourWindowClass 
{ 
private: 
    HWND m_hwnd; 

public: 
    LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
     switch (uMsg) 
     { 
      case WM_CREATE: return OnCreate(wParam, lParam); 
      case wM_PAINT: return OnPaint(wParam, lParam); 
      case WM_DESTROY: 
      { 
       SetWindowLongPtr(m_hwnd, GWLP_USERDATA, NULL); 
       m_hwnd = NULL; 
       return 0; 
      } 
     } 
     return DefWindowProc(m_hwnd, uMsg, wParam, lParam); 

    } 

    CYourWindowClass() 
    { 
     m_hwnd = NULL; 
    } 

    ~CYourWindowClass() 
    { 
     ASSERT(m_hwnd == NULL && "You forgot to destroy your window!"); 
     if (m_hwnd) 
     { 
      SetWindowLong(m_hwnd, GWLP_USERDATA, 0); 
     } 
    } 

    bool Create(...) // add whatever parameters you want 
    { 
     HWND hwnd = CreateWindow("Your Window Class Name", "Your Window title", dwStyle, x, y, width, height, NULL, hMenu, g_hInstance, (LPARAM)this); 
     if (hwnd == NULL) 
      return false; 

     ASSERT(m_hwnd == hwnd); 
     return true; 
    } 


    static LRESULT __stdcall StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
     CYourWindowClass* pWindow = (CYourWindowClass*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 

     if (uMsg == WM_CREATE) 
     { 
      pWindow = ((CREATESTRUCT*)lParam)->lpCreateParams; 
      SetWindowLongPtr(hwnd, GWLP_USERDATA, (void*)pWindow); 
      m_hWnd = hwnd; 
     } 

     if (pWindow != NULL) 
     { 
      return pWindow->WndProc(uMsg, wParam, lParam); 
     } 

     return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    }; 


}; 
+0

Zawsze zastanawiałem się, na czym polegał lpParam w funkcji CreateWindowEx, ale obsługuję to może być sposób, który czyni go podatnym na zagrożenia, ponieważ ktoś mógłby użyć GetWindowLong, aby uzyskać dane użytkownika: P – Kaije

2

Wystarczy dodać do odpowiedzi Briana ale dla ram win32, który jest bardziej przyjazny Początkujący przyjrzeć Win32++. Sama biblioteka nie ma tak rozbudowanych funkcji w porównaniu do MFC czy QT, ale jest to kompromis, który projektant zrobił na początku, aby biblioteka była łatwa do zrozumienia i prosta w użyciu.

Jeśli nadal interesuje Cię ten temat, gorąco zachęcam do obejrzenia go, ponieważ używa on jeszcze innej techniki do zapisywania "tego" wskaźnika, wykorzystując pamięć lokalną wątku.

Powiązane problemy