|
JLI Spieleprogrammierung
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
51m0n JLI'ler
Alter: 33 Anmeldedatum: 06.01.2006 Beiträge: 167 Wohnort: Erkelenz Medaillen: Keine
|
Verfasst am: 21.05.2007, 19:31 Titel: Menüs erstellen ohne Resource Dateien |
|
|
Hi
Hab mich auf die Frage hin wie man ein Menü erstellt ohne eine Resource Datei schreiben zu müssen dazu entschlossen dieses kleine Tutorial zu schreiben.
Warum überhaupt?
Also es gibt sicher Leute die das ganze lieber mit einer Resource-Datei machen, ich allerdings gehöre nicht dazu, denn ich habe wie viele andere vielleicht auch die Express Version von Visual C++, die keinen Resource Editor besitzt. Außerdem ist so ein Menü, dass erst zur Laufzeit erzeugt wird wesentlich flexibler.
Wie funktioniert das?
Ganz einfach als erstes brauchen wir ein Fenster (Wenn ihr nicht wisst wie ihr eins erstellt, solltet ihr euch erstmal ein anderes Tutorial durchlesen).
Dann erstellen wir erstmal das Hauptmenu. Das ist sozusagen, dass Menü, welches alle anderen beinhaltet. Dies erstellen wir ganz einfach so:
CPP: | HMENU menu = CreateMenu(); |
So das war auch schon alles. Aber woher soll unser Fenster wissen, dass es dieses Menü verwenden soll? Dafür ist die Funktion SetMenu() da. Diese verlangt 2 Parameter. Als ersten das Handle von unserem Fenster und als zweites das Menü selbst.
CPP: | HMENU menu = CreateMenu();
SetMenu(MainWnd, menu); |
Wenn wir das Programm nun starten werden wir feststellen, dass sich nichts geändert hat. Logisch, denn wir haben ja auch noch keinen Inhalt festgelegt. Dazu benötigen wir die Funktion AppendMenu(). Dise verlangt vier Parameter:
1. das Menü, indem der Inhalt eingefügt werden soll
2. hier können erweiterte optionen für den Inhalt, das Item, festgelegt werden. Genaueres findet ihr hier: http://msdn2.microsoft.com/en-us/library/ms647616.aspx
Im moment kann der Parameter auf 0 gesetzt werden, wir brauchen den erst später.
3. entweder die ID des Items oder ein anderes Menu(genaueres dazu später)
4. der Name des Items
So könnte nun z.B. der Code aussehen:
CPP: | HMENU menu = CreateMenu();
AppendMenu(menu, 0, 1, TEXT("Datei"));
SetMenu(MainWnd, menu); |
So nun werden wir feststellen, dass in der Menüleiste ein Feld mit dem Namen "Datei" erschienen ist. Er ist sogar schon benutzbar, aber ist so ein Menü, dass aufklappt wenn man draufdrückt nicht viel schöner? Also müssen wir nochmal ran. Als erste benötigen wir noch ein weiteres Menü. Dort wird dann der Inhalt der aufklappbaren Box gespeichert. Dies geht genau so wie vorher mit AppendMenu().
CPP: | HMENU menu = CreateMenu();
HMENU datei = CreateMenu();
AppendMenu(datei, 0, 1, TEXT("Beenden"));
SetMenu(MainWnd, menu); |
So nun haben wir zwei Menüs, aber jetzt müssen wir das Neue ja irgendwie an das alte anhängen und das geht wieder mit AppendMenu().
Einfach als ersten Parameter das "Hauptmenu" angeben, beim zweiten die option "MF_POPUP" wählen und beim vierten wieder der Name. Der dritte Parameter ist hier nicht die ID, sondern das "Untermenü", welches man einfügen möchte. Der Code dürfte nun in etwa so aussehen:
CPP: | HMENU menu = CreateMenu();
HMENU datei = CreateMenu();
AppendMenu(datei, 0, 1, TEXT("Beenden"));
AppendMenu(menu, 0, reinterpret_cast<UINT_PTR>(datei), TEXT("Datei"));
SetMenu(MainWnd, menu); |
Nun haben wir ein aufklappbares, beliebig erweiterbares Menü erstellt und so schwer war das doch nicht oder?
Ach ja da gibt es ja noch die Funktion DestroyMenu(). Diese muss man aber nicht aufrufen, wenn das Menü mit SetMenu() einem Fenster zugeteilt wurde, denn dann wird es automatisch beim schließen des Fensters zerstört.
Da passiert ja gar nichts, wenn ich auf das Menü klicke
Dieses Thema werden wir jetzt behandeln.
Immer wenn ein Button gedrückt, ein Menüitem angeklickt wurde usw. wird die Message WM_COMMAND an das Programm geschickt. Diese werden wir jetzt behandeln. ihr müsst also in eurem MessageHandler die Nachricht WM_COMMAND abfangen, um dann zu überprüfen welcher Button betätigt wurde. Diese Information ist im Parameter wParam gespeichert. wParam beinhaltet nämlich die ID des Items, dass gedrückt wurde. Hierfür ist es wichig, dass keine ID mehrmals verwendet wurde. Der Code dürfte dann in etwa so aussehen:
CPP: | case WM_COMMAND: // Button wurde gedrückt
switch(wParam) // welcher Button?
{
case 0: // der Button mit der ID 0, dann mache folgendes
// mache irgendwas
break;
}
return 1; |
Das wars dann auch eigentlich schon. Auch nicht sonderlich schwer .
Einträge deaktivieren
Möchte man ein bestimmten Eintrag deaktivieren, sodass er nicht anklickbar ist, so muss man einfach das Flag MF_DISABLED beim einfügen setzen und schon bekommt man beim anklicken keine Nachricht mehr und der Eintrag wird anders dargestellt.
CPP: | HMENU File = CreateMenu();
AppendMenu(File, MF_DISABLED, 1, TEXT("New"));
|
Es nützt nur wenig, wenn man einen Eintrag deaktiviert, aber nicht wieder aktivieren kann. Hierzu kommen wir in später.
Trennlinien
Hat man viele Daten in einem Menü, wird das ganze schnell unübersichtlich. Trennlinien können uns helfen ein bisschen Strukur darein zu bringen. Um so eine Trennlinie einzufügen, mussen wir einfach beim einfügen eines neuen Items das Flag MF_SEPARATOR setzen:
CPP: | HMENU File = CreateMenu();
AppendMenu(File, 0, 1, TEXT("New"));
AppendMenu(File, 0, 2, TEXT("Open"));
AppendMenu(File, 0, 3, TEXT("Save"));
AppendMenu(File, MF_SEPARATOR, 0, NULL);
AppendMenu(File, 0, 4, TEXT("Page Setup"));
AppendMenu(File, 0, 5, TEXT("Print"));
AppendMenu(File, MF_SEPARATOR, 0, NULL);
AppendMenu(File, 0, 6, TEXT("Exit"));
|
Jetzt haben wir zwischen den Einträgen eine schöne Trennlinie. Dieser Menüeintrag hat bei einem "normalen" Menü keine Wirkung.
Bitmaps
Bitmaps ins Menü einzufügen ist nicht sonderlich schwer. Man muss einfach als Flag MF_BITMAP übergeben und anstatt des Textes das Handle zur Bitmap.
CPP: | HBITMAP Bitmap = static_cast<HBITMAP>(LoadImage(Instance, TEXT("meinebitmap.bmp"), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE));
HMENU File = CreateMenu();
AppendMenu(File, MF_BITMAP, 4, reinterpret_cast<TCHAR*>(Bitmap)); |
Das wars schon. Mehr braucht man nicht.
Was kann man noch machen?
Später werde ich noch zeigen, wie man die Menüeinträge nachträglich editieren kann und wie man Einträge mit einem Häkchen erstellt und damit umgeht.
Ein komplettes Beispiel
So hier habe ich nochmal ein komplettes Beispiel zusammengestellt. Aus übersichtigkeitsgründen ohne Error Handling und es ist auch nur den relevanten Teil kommentiert.
CPP: | #include <windows.h>
LRESULT CALLBACK WndProc(HWND, unsigned int, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, char *CmdLine, int Show)
{
const TCHAR MainWndClassName[] = TEXT("Runtime Menu");
HWND MainWnd = NULL;
WNDCLASSEX MainWndClass = {};
MSG MainWndMsg = {};
MainWndClass.cbSize = sizeof(WNDCLASSEX);
MainWndClass.style = CS_HREDRAW | CS_VREDRAW;
MainWndClass.lpfnWndProc = WndProc;
MainWndClass.cbClsExtra = 0;
MainWndClass.cbWndExtra = 0;
MainWndClass.hInstance = Instance;
MainWndClass.hIcon = LoadIcon(Instance, IDI_APPLICATION);
MainWndClass.hIconSm = LoadIcon(Instance, IDI_APPLICATION);
MainWndClass.hCursor = LoadCursor(Instance, IDC_ARROW);
MainWndClass.hbrBackground = reinterpret_cast<HBRUSH__*>(COLOR_3DFACE+1);
MainWndClass.lpszMenuName = 0;
MainWndClass.lpszClassName = MainWndClassName;
RegisterClassEx(&MainWndClass);
MainWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
MainWndClassName,
TEXT("Runtime Menu"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800, 650,
NULL,
NULL,
Instance,
NULL);
HMENU Menu = CreateMenu(); // das Hauptmenü erstellen
HMENU File = CreateMenu(); // und ein Untermenü erstellen
AppendMenu(File, 0, 1, TEXT("Save")); // das Untermenü füllen
AppendMenu(File, 0, 2, TEXT("Exit")); // ganz einfach und ohne schnick-schnak
AppendMenu(Menu, MF_POPUP, reinterpret_cast<UINT_PTR>(File), TEXT("File")); // das Untermenü an das Hauptmenü anhängen
AppendMenu(Menu, 0, 3, TEXT("Help")); // in das Hauptmenü können nicht nur popup-menüs eingefügt werden ;)
SetMenu(MainWnd, Menu); // das Hauptmenü dem Fenster zuteilen
ShowWindow(MainWnd, Show);
UpdateWindow(MainWnd);
while(GetMessage(&MainWndMsg, NULL, 0, 0))
{
TranslateMessage(&MainWndMsg);
DispatchMessage(&MainWndMsg);
}
UnregisterClass(MainWndClassName, Instance);
return 0;
}
LRESULT CALLBACK WndProc(HWND Window, unsigned int Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_CLOSE:
DestroyWindow(Window);
return 1;
case WM_COMMAND: // ein Button wurde gedrückt, ein Menüitem wurde angeklickt usw..
switch(wParam) // welche ID hatte das betätigte Objekt
{
case 3: // wenn Objekt mit ID 3 betätigt wurde, dann mache folgendes
MessageBox(Window, TEXT("Sie haben den \"Help\" Button gedrückt"), TEXT("Herzlichen Glückwinsch"), MB_OK);
break;
}
return 1;
case WM_DESTROY:
PostQuitMessage(0);
return 1;
default:
return DefWindowProc(Window, Message, wParam, lParam);
}
} |
So ich hoffe das Tutorial hat euch einigermaßen gefallen.
Mfg
Simon _________________ Teigwaren
heißen Teigwaren,
weil sie früher einmal Teig waren
Zuletzt bearbeitet von 51m0n am 29.05.2007, 12:08, insgesamt 8-mal bearbeitet |
|
Nach oben |
|
|
David Super JLI'ler
Alter: 39 Anmeldedatum: 13.10.2005 Beiträge: 315
Medaillen: Keine
|
Verfasst am: 28.05.2007, 18:32 Titel: |
|
|
Ganz nett, ja. Aber ich frage mich egtl warum man nicht Tools die es sowiso gibt (z.B. Visual Studio Menü Designer) verwenden sollte und auf die Resourcefiles zurückgreift statt das ganze hart zu coden. Das macht erstens den Code unschön und ist mehr Arbeit.
Was mir persönlich nicht gefällt, aber weniger mit dem Tutorial zu tun hat, ist dieses krankhafte versuchen vom Auflösen sämmtlicher Definitionen die es zulassen. Wieso zur Hölle machst du das? |
|
Nach oben |
|
|
GreveN JLI Master
Alter: 38 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 28.05.2007, 18:52 Titel: |
|
|
Ich glaube Patrick hat irgendwann mal behauptet, dass das "besser" wäre. Allerdings haben diese Typedefs etc. schon ihre Daseinsberechtigung, schon allein der Portabilität wegen, damit du dir keinen Kopf machen musst, wie groß nun eben gerade ein einfaches Integer auf der jeweiligen Plattform ist, neue Features in die Lib integriert werden können - die Funktionen und Datentypen betreffen - ohne das du Code neu schreiben musst usw. |
|
Nach oben |
|
|
David Super JLI'ler
Alter: 39 Anmeldedatum: 13.10.2005 Beiträge: 315
Medaillen: Keine
|
Verfasst am: 28.05.2007, 19:22 Titel: |
|
|
Weshalb man sie nicht auflösen sollte hast du ja eben schon gesagt. Und was Patrick für besser hält muss es nicht zwangsläufig sein. Was mir auffällt ist dieses Patrickversuchte Verhalten von vielen Anfängern... Die machen oft Dinge die sie nichtmal belegen können und wenn man fragt heists nach einigen seltsamen Erklärungsversuchen: "Keine Ahnung, hab mich halt dran gewöhnt"... Das ist traurig! |
|
Nach oben |
|
|
51m0n JLI'ler
Alter: 33 Anmeldedatum: 06.01.2006 Beiträge: 167 Wohnort: Erkelenz Medaillen: Keine
|
Verfasst am: 28.05.2007, 20:00 Titel: |
|
|
Hallo
Ich will einfach auf den ersten Blick sehen, dass der Typ mit dem ich arbeite ein Zeiger ist. Hier bei der WinAPI ist das nich ganz so wichtig aber wenn ich z.B. mit Direct3D mache dann finde ich es besser mir IDirect3D9* zu arbeiten als mit LPDIRECT3D9. Besonders wenn dann sowas kommt wie LPDIRECT3D9*. Das habe ich schon von Anfang an gemacht, bevor ich Patrik je gesehen hab. Auch habe ich nie mit DWORD usw gearbeitet, weil ich es unsinnig fand solche "Umschreibungen" zu benutzen. TCHAR hab ich allerdings wiederum benutz, weil man dann am code nichts ändern muss wenn man ihn von ANSI nach Unicode transferieren will. Dass ich das jetzt bei (fast) allen anderen Typen auch mache ist will:
1. Ich find es iwie schöner z.B. __stdcall anstatt WINAPI zu schreiben
2. Ich wollte alles einheitlich haben
3. Ja ich gebe zu das Patrick mich auch beeinflusst hat
Aber ich hab dann irgendwann auch eingesehn, dass dieses auflösen oftmals Quatsch ist und habe es inzwichen schon stark eingeschrängt.
(Den Quellcode hab ich aus nem anderen (älteren) Projekt genommen und hab das mit dem HMENU__* nur angepasst, ganz so extrem ist das heute bei mir nicht mehr ) _________________ Teigwaren
heißen Teigwaren,
weil sie früher einmal Teig waren |
|
Nach oben |
|
|
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 28.05.2007, 21:43 Titel: |
|
|
Ich finde, du slltest Punkt 2 nocheinmal genauer erklären, statt auf das MSDN zu verweisen. Weil, sonst hätte es gereicht "Schau mal nach CreateMenu, AppendMenu und SetMenu zu verweisen, man hätte sich das auch mit den Infos zusammen fuddeln können.
Natürlich muss nicht alles detailliert beschrieben sein, aber die groben Grundlagen, die du im Beispiel ja auch verwendet hast, sollten schon geklärt werden.
Achja: Wenn da schon LPDIRECT3D9 steht, und man weiß, dass dieses LP für long Pointer (dürfte IMHO ein Überbleibsel aus 16 bit Zeiten sein) steht, dann brauche ich persönlich wirklich kein IDirect3D9* um zu erkennen, dass das ein Zeiger ist. Aber jeder wie er meint^^ _________________ https://jonathank.de/games/ |
|
Nach oben |
|
|
Dragon Super JLI'ler
Alter: 38 Anmeldedatum: 24.05.2004 Beiträge: 340 Wohnort: Sachsen Medaillen: Keine
|
Verfasst am: 28.05.2007, 21:45 Titel: |
|
|
zu 1.
Das ist ja mal eine richtig geile Ausrede. Problem ist aber, dass du deinen Quellcode so nur mit VIsual Studio C++ compiliern kannst. Die ganzen __-Sachen sind nicht standardisiert und sollten eigentlich nicht genommen werden. Typedefs sind da um das Programmieren zu erleichtern, um den Programmiererschreibarbeit abzunehmen und kompatibilität zwischen Compilern zu gewährleisten. Das man auf die LP-Dinger verzichten kann, sehe ich vollkommen ein. Mach ich selber ja auch.
zu 2.
Das ist ja überhaupt nicht einheitlich. Pfui! Warum machst du nicht all deine Funktionen mit __, dann hast du sie wirklich einheitlich. (Ei, ich übertreibe langsam .....)
zu 3.
Es gibt aber sonst nur wenig Leute die sowas machen. Es sieht schon irgendwie krank aus. _________________ Nur wenn man ein Ziel sieht, kann man es auch treffen.
___________
Mein Leben, Freunde und die Spieleentwicklung |
|
Nach oben |
|
|
51m0n JLI'ler
Alter: 33 Anmeldedatum: 06.01.2006 Beiträge: 167 Wohnort: Erkelenz Medaillen: Keine
|
Verfasst am: 28.05.2007, 22:20 Titel: |
|
|
Dragon hat Folgendes geschrieben: | zu 1.
Das ist ja mal eine richtig geile Ausrede. Problem ist aber, dass du deinen Quellcode so nur mit VIsual Studio C++ compiliern kannst. Die ganzen __-Sachen sind nicht standardisiert und sollten eigentlich nicht genommen werden. Typedefs sind da um das Programmieren zu erleichtern, um den Programmiererschreibarbeit abzunehmen und kompatibilität zwischen Compilern zu gewährleisten. Das man auf die LP-Dinger verzichten kann, sehe ich vollkommen ein. Mach ich selber ja auch.
|
Das wusste ich net, dachte das ist bei allen compilern so. Ein gruter grund das zu ändern. Aber jeder hat eine andere Meinung was einem gefällt und was nicht.
Dragon hat Folgendes geschrieben: |
zu 2.
Das ist ja überhaupt nicht einheitlich. Pfui! Warum machst du nicht all deine Funktionen mit __, dann hast du sie wirklich einheitlich. (Ei, ich übertreibe langsam .....)
|
Das meinte ich nicht. Ich meinte wenn schon auflösen, dann alles, aber von dem trip bin ich schon wieder runter, da gabs schlimmere zeiten^^.
Dragon hat Folgendes geschrieben: |
zu 3.
Es gibt aber sonst nur wenig Leute die sowas machen. Es sieht schon irgendwie krank aus. |
Findeste du? Ich find diese komplett groß geschriebenen defines schlimmer.
@Jonathan
Ok werde den Teil dann noch etwas ausführlicher gestalten.
MfG 51m0n
edit:
Hab den Code oben mal editiert die ganzen Auflösungen weg und einen Fehler berichtigt. Besser jetzt? _________________ Teigwaren
heißen Teigwaren,
weil sie früher einmal Teig waren |
|
Nach oben |
|
|
DirectXer Dark JLI'ler
Anmeldedatum: 05.02.2005 Beiträge: 1201 Wohnort: Köln Medaillen: Keine
|
Verfasst am: 28.05.2007, 23:28 Titel: |
|
|
um jetzt auch nochmal meinen senf dazu geben zu müsse :
ich unterstütze simon in der hinsich: ich finde es generell auch schöner die internen bezeichungen zu nehmen (ausnahmen natürlich u.a. TCHAR), da ich dann immer direkt sehe, zu welchen c++-Typ die Variablen gehören. Dazu gehört, dass ich lieber unsigned long als ULONG, DWORD etc. schreibe, damit ich net jedesmal nachschauen muss, wofür das entsprechende typedef jetzt wieder steht. Auch die ganzen defines mit LPDIRECT3D usw. lasse ich lieber weg, damit ich wie gesagt bei IDirect3D* direkt sehe, dass es ein Pointer für das D3D-interface ist. Nebenbei ist auch bewiesen, dass Wörter die nur aus Großbuchstaben bestehen für das menschliche Auge schwieriger zu syntaktisieren sind als gemischte und haupts. klein geschriebene. Von diesen ganzen minimalen Vorlieben, die jeder Programmierer für sich hat, abgesehen, achte ich aber auf eines ganz besonders: Die C++-Casts zu benutzen(und das mit der WinAPI zu verbinden), vor allem in solchen Fällen wie es auch simon schon gemacht hat: Zitat: | CPP: | AppendMenu(Menu, MF_POPUP, reinterpret_cast<UINT_PTR>(File), TEXT("File")); |
| Es ist ja allgemein empfohlen und davor gewarnt, dass c-casts gegenüber c++-casts ziemlich ungeeignet für c++-Code sind, da sie in jeder Situation einfach bitweise reinterpretieren.
Gruß DXer |
|
Nach oben |
|
|
David Super JLI'ler
Alter: 39 Anmeldedatum: 13.10.2005 Beiträge: 315
Medaillen: Keine
|
Verfasst am: 29.05.2007, 05:32 Titel: |
|
|
Es geht nicht nur um den tollen visuellen Eindruck wenn du Typendefinitionen auflöst sondern um die daraus resultierende unportabilität. Die ganzen Typendefinitionen und Defines/Macros stellen eine gewisse Kapselung da. D.h. Microsoft (in dem Fall) nimmt sich u.U. heraus den Typ einer Definition zu ändern und sei es nur der Grund das ein Typ z.B. immer 32 Bit gewährleisten soll.
Wenn du deinen Code dann auf entsprechenden Platformen kompilieren willst siehst du ziemlich alt aus und hast viel Arbeit den ganzen Mist anzupassen.
Darum sollte man die Typendefinitionen eben nicht auflösen und die Vorgaben verwenden. Du erstellst ja auch nicht für jede Klasse eine Equivalente deren ganzen Membervariablen öffentlich sind. Nur weil du's toller findest. Durch auflösen der Typendefinitionen untergräbst du diese teilweise Kapselung die sich Microsoft als Puffer für interne Änderungen geschaffen hat. Und zwar nicht für sich sondern für den Programmierer der die APIs verwendet, um ihm Arbeit zu sparen.
Wegen der C++ Casts:
Das tun gewisse C++ Casts auch, bitweise reinterpretieren. Allerdings werden noch einige Sicherheitsfaktoren berücksichtigt und evtl Exceptions geworfen. Dafür sind C++ Casts teilweise viel langsamer als C Casts.
Ich denke aber nicht das C Casts ungeeignet für C++ Code sind sondern das Casts im allgemeinen ungeeignet für C++ Code sind und darum die Verwendung selbiger möglichst minimiert werden sollte.
grüße |
|
Nach oben |
|
|
Jonathan_Klein Living Legend
Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 29.05.2007, 08:42 Titel: |
|
|
Ein Vorteil an C++ Casts ist ja, das die viel länger und umständlicher sind. So wird man daran erinnert, wie böse es ist, die zu benutzen. _________________ https://jonathank.de/games/ |
|
Nach oben |
|
|
David Super JLI'ler
Alter: 39 Anmeldedatum: 13.10.2005 Beiträge: 315
Medaillen: Keine
|
Verfasst am: 29.05.2007, 08:54 Titel: |
|
|
Jonathan_Klein hat Folgendes geschrieben: | Ein Vorteil an C++ Casts ist ja, das die viel länger und umständlicher sind. So wird man daran erinnert, wie böse es ist, die zu benutzen. |
Ja, steht in Effektiv C++ Programmieren. |
|
Nach oben |
|
|
GreveN JLI Master
Alter: 38 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 29.05.2007, 08:56 Titel: |
|
|
Der Spruch war jawohl mal geil... ;) Danke Jona, du hast meinen Tag erheitert...
Steckt sogar irgendwie soviel Wahrheit drin... ;)
Tut mir Leid dieses OT-Postings wegen, aber das musste raus... ;) |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
Powered by phpBB © 2001, 2005 phpBB Group Deutsche Übersetzung von phpBB.de
|