2010-08-01 22 views
7

Quiero crear mi propia clase para manejar la creación de ventanas y el procedimiento de ventana, pero he notado que el procedimiento de ventana debe ser estático. Ahora me pregunto si es posible orientar el procedimiento de ventana. He leído algunos tutoriales sobre ventanas orientadas a objetos, pero siempre hacen que el procedimiento sea estático. ¿Cuál es el uso en eso? :/Objeto orientado C++ win32?

Cualquier enlace o información sobre cómo solucionar este problema sería apreciada,

gracias

+0

Ver [ El mejor método para almacenar este puntero para usar en WndProc ] (http://stackoverflow.com/questions/117792/best-method-for-storing-this-pointer-for-use-in-wndproc) –

+2

Es por esta razón que siempre he deseado que 'WndProc' tuviera un parámetro' void * user_data'. Sería mucho más fácil crear un contenedor basado en objetos. –

+0

@Evan: sí, pero también habría requerido que alguien * cuerdo * se encargue de diseñar la API ... La API de Win32 habría sido una bestia muy diferente si ese hubiera sido el caso. – jalf

Respuesta

11

que le permite desplazarse de que al hacer que el WndProc estática delegar todo para los miembros:

// 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, pero es posible que también desee comprobar WM_DESTROY allí y quitar el controlador del mapa. – SoapBox

+0

buen ejemplo, se ve bien. Trataré de implementarlo en mi propio, buen uso de std :: map para encontrar el manejador correspondiente – Kaije

+0

@SoapBox. Está incompleto de muchas maneras, gracias por notar esto. –

3

Si está buscando orientado a objetos de la API de Win32 entonces usted debe buscar a MFC y/o WTL.

+0

soluciones de Overkill para muchos propósitos. MFC puede ser * relativamente * delgado, pero sigue siendo una API grande por derecho propio, y cambiar de una API a otra es mucho trabajo. También es completamente innecesario si lo único que quieres hacer es usar algunas clases de C++ propias mientras codifica Win32. Mi viejo "framework de objetos" para Win32 probablemente tenía 2 o 3 lados de código, poco más que una clase base, alguna inicialización y un bucle principal de GetMessage/etc. – Steve314

+0

Asunto de opinión –

+0

MFC es un marco desagradable, pero es bien compatible y relativamente bien conocido en el mundo de Win32. – seand

1

Puede usar el identificador de ventanas pasado a WindowProc para tomar un objeto que haya creado para esa ventana en particular y delegar el manejo de eventos a ese objeto.

p. Ej.

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

Suena bien, noté que la única cosa única en el procedimiento es el identificador, pero no estaba seguro de cómo encontrar mi ventana a través de él. como en su ejemplo, el getMyWindowObject (hwnd), ¿esa función consistiría en iterar a través de mis ventanas abiertas para ver si el identificador coincide? porque si es así, si estuviera manejando un WM_MOUSEMOVE o WM_TIMER, ¿no sería tedioso en el procesador? – Kaije

+0

Su mejor opción es utilizar alguna forma de hashtable para hacer hash desde HWND a punteros a su objeto de ventana, es decir, las búsquedas son rápidas. A menos que tenga un número bastante grande de ventanas abiertas, esperaría que un ciclo en todos los pares (HWND, objeto *) sea lo suficientemente rápido aunque. –

6

La técnica general de permitir que una instancia de la ventana a ser representado por ejemplo como clase es hacer uso de SetWindowLongPtr y GetWindowLongPtr para asociar el puntero de instancia de clase con el manejador de ventana. A continuación se muestra un código de muestra para comenzar. Puede no compilar sin algunos ajustes. Solo tiene la intención de ser una referencia.

Personalmente, dejé de rodar mis propias clases de ventana hace unos años cuando descubrí la clase de plantilla CWindow y CWindowImpl de ATL. Ellos se encargan de hacer toda esta codificación mundana para ti, así que puedes concentrarte solo en escribir métodos que manejen mensajes de ventana. Ver el código de ejemplo que escribí here.

Espero que esto ayude.

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

Siempre me pregunté para qué servía lpParam en la función CreateWindowEx, pero apoyo que podría ser la forma en que lo hace vulnerable, ya que alguien podría usar GetWindowLong para obtener sus datos de usuario: P – Kaije

2

sólo para añadir a la respuesta de Brian, pero para un marco de Win32 que es más amigable para los principiantes echar un vistazo a Win32++. La biblioteca en sí misma no es tan completa en características en comparación con MFC o QT, pero eso es una compensación que el diseñador hizo al principio para mantener la biblioteca fácil de entender y fácil de usar.

Si todavía está interesado en este tema, le recomiendo que lo revise, ya que utiliza otra técnica más para guardar el puntero "this" utilizando el almacenamiento local de subprocesos.

Cuestiones relacionadas