<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Abhandeln bestimmter Ereignisse (Designfrage)]]></title><description><![CDATA[<p>Vorweg: ich bin der Meinung, dass ich im richtigen Unterforum bin, da es hier nicht speziell um die WinAPI geht.</p>
<p>Ich bin momentan dabei, mit einem Kumpel ein kleines Spiel zu programmieren. Das soll mit C++ und der WinAPI geschehen. Nun gibt es ja in jedem C++-Programm eine main (bei WinAPI eben die WinMain, aber das ist völlig irrelevant). Nun gibt es bei Windows auch die sogenannte WndProc (Window procedure), die von Windows aufgerufen wird und der bestimmte Parameter des aufgetretenen Events übergeben werden. Diese Events können Mausklicks, Tastendrücke oder sonst was sein.</p>
<p>Nun gibt es in dem Spiel zum einen ein paar Menüs, über die man Dinge konfigurieren kann, und zum anderen das eigentliche Spiel, in dem man die Spielfigur bewegen kann usw.</p>
<p>Das Menü besteht aus Buttons, von denen jeder eine ID (z. B. XYZ) hat. Bei Klick wird die WndProc z. B. mit der Nachricht &quot;Button XYZ wurde geklickt&quot; aufgerufen. Das wird dann per switch/case abgefragt und entsprechend darauf reagiert.</p>
<p>Nun mein Problem: Die ganze Logik, sowohl für Menü als auch für das eigentliche Spiel, befinden sich momentan in der WndProc. Ich möchte aber gerne abgrenzen, sodass diese beiden Bereiche voneinander abgegrenzt sind. Jetzt war meine Idee, dass ich mir jeweils eine Klasse schreibe (Menu und Game), die jeweils eine Methode &quot;WndProc&quot; implementieren. Je nachdem in welchem Spielstatus ich mich befinde, wird die WndProc des entsprechenden Objektes (Menu oder Game) aufgerufen. Allerdings finde ich dabei blöd, dass die Klassen dann jeweils nur genau eine Aufgabe erledigen (entweder die Menü- oder die Spiellogik abhandeln). Ich dachte mal gelesen zu haben, dass man das nicht so machen soll, sondern dass Klassen durch die Daten, die man ihnen gibt, ihren Zweck erfüllen. Meine Klassen hätten aber jeweils nur genau eine festgelegte Aufgabe.</p>
<p>Es geht hier lediglich um die Frage, ob die beschriebene Lösung designtechnisch gut ist und das der gängige Weg ist, oder ob man das eleganter lösen kann.</p>
<p>Ich hoffe, dass ihr mich verstanden habt und freue mich auf eure Antworten!</p>
]]></description><link>https://www.c-plusplus.net/forum/topic/305390/abhandeln-bestimmter-ereignisse-designfrage</link><generator>RSS for Node</generator><lastBuildDate>Sat, 08 Aug 2026 14:29:29 GMT</lastBuildDate><atom:link href="https://www.c-plusplus.net/forum/topic/305390.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 27 Jun 2012 19:37:29 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Wed, 27 Jun 2012 19:37:29 GMT]]></title><description><![CDATA[<p>Vorweg: ich bin der Meinung, dass ich im richtigen Unterforum bin, da es hier nicht speziell um die WinAPI geht.</p>
<p>Ich bin momentan dabei, mit einem Kumpel ein kleines Spiel zu programmieren. Das soll mit C++ und der WinAPI geschehen. Nun gibt es ja in jedem C++-Programm eine main (bei WinAPI eben die WinMain, aber das ist völlig irrelevant). Nun gibt es bei Windows auch die sogenannte WndProc (Window procedure), die von Windows aufgerufen wird und der bestimmte Parameter des aufgetretenen Events übergeben werden. Diese Events können Mausklicks, Tastendrücke oder sonst was sein.</p>
<p>Nun gibt es in dem Spiel zum einen ein paar Menüs, über die man Dinge konfigurieren kann, und zum anderen das eigentliche Spiel, in dem man die Spielfigur bewegen kann usw.</p>
<p>Das Menü besteht aus Buttons, von denen jeder eine ID (z. B. XYZ) hat. Bei Klick wird die WndProc z. B. mit der Nachricht &quot;Button XYZ wurde geklickt&quot; aufgerufen. Das wird dann per switch/case abgefragt und entsprechend darauf reagiert.</p>
<p>Nun mein Problem: Die ganze Logik, sowohl für Menü als auch für das eigentliche Spiel, befinden sich momentan in der WndProc. Ich möchte aber gerne abgrenzen, sodass diese beiden Bereiche voneinander abgegrenzt sind. Jetzt war meine Idee, dass ich mir jeweils eine Klasse schreibe (Menu und Game), die jeweils eine Methode &quot;WndProc&quot; implementieren. Je nachdem in welchem Spielstatus ich mich befinde, wird die WndProc des entsprechenden Objektes (Menu oder Game) aufgerufen. Allerdings finde ich dabei blöd, dass die Klassen dann jeweils nur genau eine Aufgabe erledigen (entweder die Menü- oder die Spiellogik abhandeln). Ich dachte mal gelesen zu haben, dass man das nicht so machen soll, sondern dass Klassen durch die Daten, die man ihnen gibt, ihren Zweck erfüllen. Meine Klassen hätten aber jeweils nur genau eine festgelegte Aufgabe.</p>
<p>Es geht hier lediglich um die Frage, ob die beschriebene Lösung designtechnisch gut ist und das der gängige Weg ist, oder ob man das eleganter lösen kann.</p>
<p>Ich hoffe, dass ihr mich verstanden habt und freue mich auf eure Antworten!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2227905</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2227905</guid><dc:creator><![CDATA[Abhandler]]></dc:creator><pubDate>Wed, 27 Jun 2012 19:37:29 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Wed, 27 Jun 2012 19:45:59 GMT]]></title><description><![CDATA[<p>idR macht man es so, dass du Funktionen mit Nachrichten verknuepfst. Das nennt sich dann signal/slot Konzept.</p>
<p>Du hast wahrscheinlich eine Klasse die Fenster repraesentiert. Wenn ich nun ein Fenster erstelle registriere ich beim Fensterobjekt einfach Nachrichten und Callbackfunktionen:</p>
<pre><code class="language-cpp">void menu_clicked(WPARAM wParam, LPARAM lParam) {
   if(lParam!=ID_MENU1) return;
   ...
}

Window wnd;
wnd.registerMessage(WM_COMMAND, menu_clicked);
</code></pre>
<p>In der WndProc wird dann die eben geschaut wer alles auf welche Message &quot;listened&quot; Deshalb nennt sich das Konzept auch oft &quot;Listener&quot; oder &quot;Observer&quot; bzw. &quot;Subscriber&quot;</p>
<p>Das Code Beispiel ist natuerlich absolut minimal und du solltest besser abstrahieren. Aber ich hoffe du hast erstmal genug Stoff zum googlen <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f642.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--slightly_smiling_face"
      title=":)"
      alt="🙂"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2227910</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2227910</guid><dc:creator><![CDATA[Shade Of Mine]]></dc:creator><pubDate>Wed, 27 Jun 2012 19:45:59 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Wed, 27 Jun 2012 20:02:22 GMT]]></title><description><![CDATA[<p>Dann hätte ich aber auch wieder das Problem, dass das Zeug nicht voneinander abgetrennt ist. Ich hätte dann für bestimmte/alle Messages eine eigene Funktion, aber nicht pro &quot;Zustand&quot; (Menü, Spiel).</p>
<p>Du meinst es wohl so, dass man zwei Funktionen hat: eine menu_clicked und eine game_clicked (nur als Beispiel). Nur finde ich die Abfrage am Anfang der Funktion dann auch unschön. Beispielsweise würde ich dann wohl sowas haben:</p>
<pre><code class="language-cpp">void game_clicked()
{
    if (state != STATE_GAME)
    {
        return;
    }

    // Messages abhandeln
}

void menu_clicked()
{
    if (state != STATE_MENU)
    {
        return;
    }

    // Messages abhandeln
}
</code></pre>
<p>Da finde ich das mit den Klassen aus meinem ersten Beitrag eleganter, da dann die Zuständigkeiten klar sind und bereits innerhalb der WndProc (in der Haupt-Klasse) abgefragt wird, in welchem Status das Spiel sich befindet und anhand dieser Information die Methode des richtigen Objektes aufruft. Was meinst du?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2227917</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2227917</guid><dc:creator><![CDATA[Nachdenker]]></dc:creator><pubDate>Wed, 27 Jun 2012 20:02:22 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Wed, 27 Jun 2012 20:09:26 GMT]]></title><description><![CDATA[<p>Nachdenker schrieb:</p>
<blockquote>
<p>Dann hätte ich aber auch wieder das Problem, dass das Zeug nicht voneinander abgetrennt ist. Ich hätte dann für bestimmte/alle Messages eine eigene Funktion, aber nicht pro &quot;Zustand&quot; (Menü, Spiel).</p>
</blockquote>
<p>Das ist nur eine Frage der Abstraktion. uU hilft dir hier das State Design Pattern.</p>
<blockquote>
<p>Du meinst es wohl so, dass man zwei Funktionen hat: eine menu_clicked und eine game_clicked (nur als Beispiel). Nur finde ich die Abfrage am Anfang der Funktion dann auch unschön. Beispielsweise würde ich dann wohl sowas haben:</p>
</blockquote>
<p>Google mal nach den Stichworten die ich dir gegeben habe. Mein Beispiel war minimalst. Normalerweise registrierst du das clicked Event nicht beim Fenster, sondern beim Knopf den du klicken willst.</p>
<blockquote>
<p>Da finde ich das mit den Klassen aus meinem ersten Beitrag eleganter, da dann die Zuständigkeiten klar sind und bereits innerhalb der WndProc (in der Haupt-Klasse) abgefragt wird, in welchem Status das Spiel sich befindet und anhand dieser Information die Methode des richtigen Objektes aufruft. Was meinst du?</p>
</blockquote>
<p>Du brauchst viel viel viel mehr Abstraktion. Die WndProc sollte nur deligieren und sonst nichts machen. Und was sie wohin deligiert wird per signal/slot Prinzip konfiguriert.</p>
<p>Schau dir dazu einfach ein beliebiges GUI Toolkit an zB FLTK.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2227922</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2227922</guid><dc:creator><![CDATA[Shade Of Mine]]></dc:creator><pubDate>Wed, 27 Jun 2012 20:09:26 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Thu, 28 Jun 2012 07:06:12 GMT]]></title><description><![CDATA[<p>falls ich das noch richtig auf die kette bekomme ist es ja so das die wndproc - funktionen eigentlich nur events filtern und irgendwelche &quot;aktionen&quot; auslösen sollen.<br />
falls das stimmt könntest du auch eine schicht zwischen die &quot;winapi - ebene&quot; und die spiellogik schieben die nichts anderes macht als daten anzunehmen und diese durchzureichen. das ganze nennt sich dann &quot;facade - pattern&quot;. wenn du dann iwann von winapi auf sagen wir mal qt oder dx oder sonstwas wechselt bleiben die aufrufe in der fasade die gleichen. nur die stellen, von wo sie aufgerufen werden sind dann eben andere. der &quot;trick&quot; hierbei ist der, das du &quot;komplexere&quot; abläufe in deiner logik hinter einem aufruf in der fasade &quot;verstecken&quot; kannst.<br />
ob sich das ganze dann aber in schlechterer performance auswirkt kann ich nicht sagen.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2228004</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2228004</guid><dc:creator><![CDATA[Psycho]]></dc:creator><pubDate>Thu, 28 Jun 2012 07:06:12 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Thu, 28 Jun 2012 09:07:54 GMT]]></title><description><![CDATA[<p>Danke für die Infos, ich denke damit kann ich erst mal was aufbauen und sehen ob es sich bewährt. Dass die WndProc die Ereignisse nur weiterleiten soll, habe ich verstanden und es macht für mich auch Sinn. Das Signal/Slot-Zeugs sieht auf den ersten Blick auch ganz vernünftig aus.</p>
<p>Das mit dem facade-Pattern werde ich mir bei Gelegenheit auch mal ansehen - danke dafür!</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2228073</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2228073</guid><dc:creator><![CDATA[Informator]]></dc:creator><pubDate>Thu, 28 Jun 2012 09:07:54 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Tue, 03 Jul 2012 16:33:31 GMT]]></title><description><![CDATA[<p>Ich hab mir ein paar Gedanken dazu gemacht und das Ganze dann in Code umgesetzt.</p>
<p>Das Prinzip ist so:</p>
<p>Die Klasse Window beinhaltet eine statische Funktion, die WncProc. In dieser WndProc werden die Nachrichten entsprechend an Funktionen weitergeleutet, die vorher registriert wurden. Die Methode zum Registrieren sieht so aus:</p>
<pre><code class="language-cpp">void Component::registerSignal(UINT message, Signal signal)
{
	this-&gt;signals[message].push_back(signal);
}
</code></pre>
<p>Wobei this-&gt;signals das hier ist:</p>
<pre><code class="language-cpp">std::map&lt;UINT, std::vector&lt;Signal&gt;&gt; signals;
</code></pre>
<p>und Signal das:</p>
<pre><code class="language-cpp">typedef void (*Signal)(WPARAM wParam, LPARAM lParam);
</code></pre>
<p>Die WndProc sieht dann so aus:</p>
<pre><code class="language-cpp">LRESULT CALLBACK Window::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	if (Window::windows.find(hWnd) == Window::windows.end())
	{
		Window::windows[hWnd] = Window::current;
	}

	Window *wnd = Window::windows[hWnd];

	// Funktionen fuer die Windows-Nachrichten aufrufen
	if (wnd-&gt;signals.find(message) != wnd-&gt;signals.end())
	{
		auto it = wnd-&gt;signals[message].begin();

		std::for_each(it, wnd-&gt;signals[message].end(), [wParam, lParam](const Signal &amp;signal)
		{
			(*signal)(wParam, lParam);
		});
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}
</code></pre>
<p>So weit, so gut. Nun kann man sich über eine Window-Instanz für jede Windows-Nachricht beliebig viele Funktionen registrieren, die dann entsprechend aufgerufen werden.</p>
<p>Jetzt gibt es noch die Klasse Button. Diese kann entweder mit einem Window als Parent erstellt werden oder auch ohne. Nimmt man den Konstruktor, der den Button mit einem Parent-Window erstellt, registriert sich der Button einen Handler für WM_COMMAND (die Nachricht, die bei Button-Klick gesendet wird):</p>
<pre><code class="language-cpp">Button::Button(Window &amp;parentWindow, int id, int top, int left, int width, int height, const std::string &amp;caption)
	: Component(parentWindow.getHandle(), parentWindow.getParentInstance(), id, top, left, width, height, caption, &quot;Button&quot;)
	, parentWindow(&amp;parentWindow)
{
	if (!Button::wmCommandHandlerAdded[parentWindow.getHandle()])
	{
		parentWindow.registerSignal(WM_COMMAND, Button::wmCommandHandler);
		Button::wmCommandHandlerAdded[parentWindow.getHandle()] = true;
	}

	this-&gt;initButton(id);
}
</code></pre>
<p>Über eine Methode &quot;registerClickHandler&quot; des Buttons kann man dann wiederum Handler registrieren, die beim Button-Klick aufgerufen werden:</p>
<pre><code class="language-cpp">void Button::registerClickHandler(ClickHandler clickHandler)
{
	this-&gt;clickHandlers.push_back(clickHandler);
}
</code></pre>
<p>Die clickHandler werden innerhalb der riseClickEvent() aufgerufen (siehe unten).</p>
<p>Zum Schluss noch der wmCommandHandler des Buttons:</p>
<pre><code class="language-cpp">void Button::wmCommandHandler(WPARAM wParam, LPARAM lParam)
{
	int id = LOWORD(wParam);

	if (Button::buttons.find(id) != Button::buttons.end())
	{
		Button::buttons[id]-&gt;riseClickEvent(wParam, lParam);
	}
}
</code></pre>
<p>Nun meine Frage: geht das völlig an dem vorbei, wie man es richtig macht oder bin ich auf nem guten Weg?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2229717</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2229717</guid><dc:creator><![CDATA[Gedankenmacher]]></dc:creator><pubDate>Tue, 03 Jul 2012 16:33:31 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Wed, 04 Jul 2012 15:41:16 GMT]]></title><description><![CDATA[<p>Hat keiner irgendwelche Anregungen?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2230062</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2230062</guid><dc:creator><![CDATA[Anreger]]></dc:creator><pubDate>Wed, 04 Jul 2012 15:41:16 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Fri, 06 Jul 2012 18:00:28 GMT]]></title><description><![CDATA[<p>Mach ich was falsch und ihr schreibt deswegen absichtlich nix? <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f615.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--confused_face"
      title=":confused:"
      alt="😕"
    /> <img
      src="https://www.c-plusplus.net/forum/plugins/nodebb-plugin-emoji/emoji/emoji-one/1f603.png?v=ab1pehoraso"
      class="not-responsive emoji emoji-emoji-one emoji--grinning_face_with_big_eyes"
      title=":D"
      alt="😃"
    /></p>
]]></description><link>https://www.c-plusplus.net/forum/post/2230683</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2230683</guid><dc:creator><![CDATA[Seinkanner]]></dc:creator><pubDate>Fri, 06 Jul 2012 18:00:28 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Sat, 07 Jul 2012 00:03:07 GMT]]></title><description><![CDATA[<p>Ne, das passt schon.<br />
Schoenheitspreis gewinnt es keinen, aber sieht OK aus.</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2230762</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2230762</guid><dc:creator><![CDATA[Shade Of Mine]]></dc:creator><pubDate>Sat, 07 Jul 2012 00:03:07 GMT</pubDate></item><item><title><![CDATA[Reply to Abhandeln bestimmter Ereignisse (Designfrage) on Sat, 07 Jul 2012 10:55:01 GMT]]></title><description><![CDATA[<p>Shade Of Mine schrieb:</p>
<blockquote>
<p>Ne, das passt schon.<br />
Schoenheitspreis gewinnt es keinen, aber sieht OK aus.</p>
</blockquote>
<p>Was meinst du denn mit Schönheitspreis?</p>
]]></description><link>https://www.c-plusplus.net/forum/post/2230805</link><guid isPermaLink="true">https://www.c-plusplus.net/forum/post/2230805</guid><dc:creator><![CDATA[Hässlicher]]></dc:creator><pubDate>Sat, 07 Jul 2012 10:55:01 GMT</pubDate></item></channel></rss>