2010-08-01 11 views
7

Ich möchte meine eigene Klasse erstellen, um Fenster und die Fensterprozedur zu erstellen, aber ich habe bemerkt, dass die Fensterprozedur statisch sein muss! Ich frage mich jetzt, ob es möglich ist, die Fensterprozedur objektorientiert zu machen? Ich habe ein paar Tutorials über objektorientierte Fenster gelesen, aber sie machen die Prozedur immer statisch - was ist der Nutzen darin? :/Objektorientiertes C++ win32?

Alle Links oder Informationen darüber, wie dieses Problem erkannt,

dank

+0

See [ Beste Methode für diesen Zeiger für die Verwendung in WndProc Speicherung ] (http://stackoverflow.com/questions/117792/best-method-for-storing-this-pointer-for-use-in-wndproc). –

+2

Aus diesem Grund habe ich mir immer gewünscht, dass 'WndProc' einen' void * user_data' Parameter hat. Es würde das Erstellen eines objektbasierten Wrappers einfach einfacher machen. –

+0

@Evan: yep, aber es hätte auch jemand * sane * benötigt, um die API zu entwerfen ... Die Win32 API wäre ein ganz anderes Biest gewesen, wenn das der Fall gewesen wäre. – jalf

Antwort

11

können Sie umgehen, dass die statische WndProc alles delegieren, indem sie an die Mitglieder:

// 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, aber Sie können auch dort nach WM_DESTROY suchen und das Handle aus der Karte entfernen. – SoapBox

+0

schönes Beispiel, sieht cool aus. Ich werde versuchen, es in meiner eigenen, netten Verwendung von std :: map zu implementieren, um das passende Handle zu finden – Kaije

+0

@SoapBox Es ist unvollständig in vielerlei Hinsicht, danke für das Bemerken dieses eine obwohl. –

3

Wenn Sie objektorientierte Win32-API suchen, dann sollten Sie auf MFC und/oder WTL aussehen würde zu bekommen.

+0

Overkill-Lösungen für viele Zwecke. MFC ist möglicherweise * relativ * dünn, aber es ist immer noch eine große API, und der Wechsel von einer API zur anderen ist eine Menge Arbeit. Es ist auch völlig unnötig, wenn Sie nur ein paar eigene C++ - Klassen verwenden möchten, während Sie für Win32 codieren. Mein eigenes altes "Objektrahmenwerk" für Win32 war wahrscheinlich 2 oder 3 Seiten Code - wenig mehr als eine Basisklasse, einige Initialisierungen und eine Haupt-GetMessage/etc-Schleife. – Steve314

+0

Meinung –

+0

MFC ist ein fieses Framework, aber es ist gut unterstützt und relativ gut in der Win32-Welt bekannt. – seand

1

Sie können das WindowProc-Fensterhandle verwenden, um ein Objekt, das Sie für dieses bestimmte Fenster erstellt haben, zu übernehmen und die Ereignisbehandlung an dieses Objekt zu delegieren.

z.B.

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

Klingt gut, ich bemerkte, dass das einzige einzigartige Ding in der Prozedur der Griff ist, aber war nicht sicher, wie man mein Fenster dadurch findet. Wie in Ihrem Beispiel, dem getMyWindowObject (hwnd), würde diese Funktion darin bestehen, durch meine offenen Fenster zu iterieren, um zu sehen, ob das Handle übereinstimmt? Wenn ja, wenn ich einen WM_MOUSEMOVE oder WM_TIMER handle, wäre das nicht mühsam auf dem Prozessor? – Kaije

+0

Ihre beste Wette, es zu verwenden, irgendeine Art von Hashtabelle, um von HWND zu Zeigern-zu-Ihrem-Fenster-Objekt zu haseln - das war die Nachschläge sind schnell. Wenn Sie nicht eine ziemlich große Anzahl von Fenstern geöffnet haben, würde ich erwarten, dass eine Schleife durch alle (HWND, Objekt *) Paare schnell genug wäre. –

6

Die allgemeine Technik ein Fenster Instanz ermöglicht, indem sie als Klasseninstanz dargestellt werden soll, Gebrauch machen SetWindowLongPtr und GetWindowLongPtr, um den Klasseninstanzzeiger mit dem Fensterhandle zu verknüpfen. Unten finden Sie einen Beispielcode, mit dem Sie beginnen können. Es kann nicht ohne ein paar Optimierungen kompilieren. Es soll nur eine Referenz sein.

Ich persönlich habe vor ein paar Jahren aufgehört, meine eigenen Fensterklassen zu erstellen, als ich ATLs CWindow- und CWindowImpl-Vorlagenklasse entdeckte. Sie kümmern sich darum, all diese alltägliche Kodierung für Sie zu tun, und können sich darauf konzentrieren, nur Methoden zu schreiben, die Fenstermeldungen verarbeiten. Siehe den Beispielcode, den ich geschrieben habe here.

Hoffe, das hilft.

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

Ich habe mich immer gewundert, wofür das lpParam in der CreateWindowEx Funktion verwendet wurde, aber ich unterstütze das so, dass es verwundbar wird, da jemand GetWindowLong benutzen könnte, um seine Benutzerdaten zu bekommen: P – Kaije

2

Nur um Brians Antwort hinzuzufügen, aber für einen win32-Framework, das auf Win32++ mehr Anfänger freundlich einen Blick ist. Die Bibliothek selbst ist im Vergleich zu MFC oder QT nicht so umfangreich in den Funktionen, aber das ist ein Kompromiss, den der Designer zu Beginn gemacht hat, um die Bibliothek einfach zu verstehen und einfach zu verwenden.

Wenn Sie immer noch an diesem Thema interessiert sind, empfehlen wir Ihnen, einen Blick darauf zu werfen, da es noch eine andere Technik zum Speichern des "This" -Zeichens durch lokalen Threadspeicher verwendet.