Controls (Button etc.) in Klassen, Design Frage
-
Ich brauch mal eure Meinung.
Ich programmiere ein mittelgroßes Projekt, in dem einige Std. Controls sehr sehr Häufig Vorkommen. Meinen kompletten Wrapper dafür einzubinden finde ich Übertrieben, daher will ich nur das was ich brauch in Klassen packen, mit Subclassing der Controlls selbstverständlich.Da es nichts Aufwendiges ist, dachte ich, ich werde mal von meinem üblichen Still abweichen und die Klassenzeiger in einer Map packen, da ich diese eh benötige. Mein folgender Code funktioniert natürlich, aber ich habe ein ungutes Gefühl wegem den Design, vorallem benutze ich ungern Cast.
Was meint ihr, ist das OK und ich mache mir unnötig gedanken?
PS: Lehrlinge bekommen den Code auch Vorgelegt und sollen ihn Verstehen, meinem Wrapper würden die derzeit eh nicht verstehen.Der Code:
#include <windows.h> #include <map> static LRESULT CALLBACK MyControlProc (HWND, UINT, WPARAM, LPARAM); class MyControl; typedef void (*Event)(MyControl*); class MyControl { protected: HWND Handle; HINSTANCE AppInst; WNDPROC DefaultProc; /* weitere Parameter, ala left width etc. */ public: virtual void InitControl(HINSTANCE hinst, HWND hwnd) { /* Überschreiben in Erben */ } WNDPROC Get_DefaultProc() { return DefaultProc; } Event OnClick; Event OnMouseDown; Event OnMouseUp; Event OnKeyDown; Event OnKeyUp; /* u.s.w. */ }; std::map<HWND, MyControl*>MyControlMap; class MyWind : public MyControl { public: /* Members für diesen Control type */ void InitControl(HINSTANCE hinst, HWND hwnd) { /* Überschrieben */ } }; /* +++++++++++++++++++++++++++++++++++++++++++++ */ // Die WndProc der Controls: LRESULT CALLBACK MyControlProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { MyControl* obj = dynamic_cast<MyControl*>(MyControlMap[hwnd]); if (obj != 0) { switch (message) { case WM_KEYDOWN: if (obj->OnKeyDown) (*obj->OnKeyDown)(obj); break; /* etc. */Und? Ist der Codedesign ok, für einen eigentlich einfachen Zweck?
-
1. warum der cast überhaupt? in der map befinden sich doch ein pointer auf MyControl
2. wäre es nicht besser in der map über einen iterator zu suchen als darauf zurückzugreifen und einen pointer zu prüfen
typedef std::map<HWND, MyControl*> CtrlMap; CtrlMap MyControlMap; //---------------------------------- MyControl *pObj; CtrlMap::iterator it = m_MyControlMap.find(hwnd); if(it != m_MyControlMap.end()) pObj = it->second; else return 0;3. vom design her find ich es
wahrscheinlich machst du wirklich zu viele gedanken. 
-
Zu 1., stimmt ist mir nach dem Posten erst aufgefallen, ich werde alt

Das war ein Überbleibsel, da ich zuvor noch eine Klasse drüber hatte, namens MyObject, dessen Type in die Map sollte, das hatte ich aber abgeändert, da es überflüßig war und ich den DownCast einsparen wollte, nur das ich das geändert hatte um den Cast zu sparen, das hatte ich vergessen
Zu 2. Ja, wird in der endgültigen WndProc auch so geschehen, beim testen der Klassen reicht das aus.
zu 3. Danke, ja ich mach mir immer viele Gedanken am Anfang 1000 Blätter mit Notizen, dafür erlebe ich aber mitten drinn oder am Ende keine bösen Überraschungen

-
MichaM. schrieb:
zu 3. Danke, ja ich mach mir immer viele Gedanken am Anfang 1000 Blätter mit Notizen, dafür erlebe ich aber mitten drinn oder am Ende keine bösen Überraschungen

so ist es ja auch richtig als einfach darauf los zu [ironie]proggen[/ironie]

-
den pointer auf das objekt kannst übrigens mit SetWindowLong (...GWL_USERDATA mit dem hwnd verknüpfen. dann brauchste keine std::map mehr. vorteil daran ist, dass wenn das hwnd recycled wird keine fehler passieren können. sonst müssteste ja immer das hwnd/objektpointer aus der map löschen wenn das fenster gekillt wird.
-
net schrieb:
den pointer auf das objekt kannst übrigens mit SetWindowLong (...GWL_USERDATA mit dem hwnd verknüpfen. dann brauchste keine std::map mehr. vorteil daran ist, dass wenn das hwnd recycled wird keine fehler passieren können. sonst müssteste ja immer das hwnd/objektpointer aus der map löschen wenn das fenster gekillt wird.
Dann kommt der böße Micha und Macht: SetWindowLong(Object->Get_Handle(),GWL_USERDATA,123); und dann ist vorbei.
In meinem eigentlichen Wrapper benutze ich auch keine map, aber auch kein UserData.

Ich habe da auch "nicht Visuelle" Klassen, die keinen HWND haben.
-
In meinem eigentlichen Wrapper benutze ich auch keine map, aber auch kein UserData.
was denn?
-
HINSTANCE AppInst; /* weitere Parameter, ala left width etc. */Find ich nicht gut. Das kann man doch alles mit den Winapi Funktionen abfragen und setzen.
-
Und wie kommt man in OnKeyDown an WPARAM und LPARAM?
-
naja ich würd sagen den funktionpointer erweitern

typedef void (*Event)(MyControl*, WPARAM, LPARAM);
-
@pro...
das ist zu Umfassend um es kurz zu erwähnen@schlechtes design
ich speichere width height etc, da ich mit get_xxx dies Abfrage und mit set_xxxx setzte, die entsprechenden API Funktionen sitzen dann in diese, dafür ist OOP da, um einen guten Überblick zu bewahren.Der gezeigte Code ist ein Beispiel für das Design, das wird doch nicht so 1:1 Übernommen, zur Beruhigung:
typedef void (*MouseEvent)(MyControl*,int,int,WPARAM); //Klasse,x,y,Shift typedef void (*KeyEvent)(MyControl*,int,LPARAM); //Klasse,Keycode,Keydata //u.s.w.Also, den gezeigten code nicht als endcode ansehen
-
krieg ich auch kein stichwort?
-
ich speichere width height etc, da ich mit get_xxx dies Abfrage und mit set_xxxx setzte, die entsprechenden API Funktionen sitzen dann in diese, dafür ist OOP da, um einen guten Überblick zu bewahren.
versteh ich irgendwie nicht. warum sollen die daten an 2 plätzen gespeichert werden? einmal in windows und einmal in deinem programm. dann muss man die werte ja immer aktuell halten. das ist doch quatsch.
-
pro... schrieb:
krieg ich auch kein stichwort?
Bei Fenstern, auch Childwindows, kann man den Zusatzspeicher erweitern und bei standard controls kann man was nehmen, was sie nicht verwenden (z.b. Menu).
schlechtes design schrieb:
versteh ich irgendwie nicht. warum sollen die daten an 2 plätzen gespeichert werden? einmal in windows und einmal in deinem programm. dann muss man die werte ja immer aktuell halten. das ist doch quatsch.
Hmmm, hast recht. Danke, hatte ich so nicht darauf geachtet, ich muß meinen großen Wrapper angleichen, da der Programmierer die Möglichkeit hat durch das Handle eigene Operation durchzuführen, hatte ich die "get" Auslesung entsprechend angeglichen, so das es aus Windows gelesen wird, bei set aber in den Klassen Members geschrieben wird und z.B. mit MoveWindow() ausgeübt wird, demnach sind die Member nutzlos, wer hätte das gedacht.
Danke für den Tip, da kann man ja noch Speicher sparen, bevor 512MB voll sind.
-
hi,
wieso verwendest du statt der function pointer keine virtuellen Funktionen, mit Basisklasse/abgeleiteten Klassen etc., wäre eleganter meiner Meinung nach.
(ich denk du weißt was ich meine ;))Oder hast verhalten die sich alle unterschiedlich und du hast so sehr viele?
Naja, nur so als Einwurf, aber wahrscheinlich auch zu mühselig nochmal alles zu ändern

MfG
DDR-RAM
-
@DDR-RAM
Virtuelle Funktionen zu überschreiben wäre wesentlich aufwendiger bei der Masse, zumal einige Buttons etwas dürfen und andere nicht.