Zweites Fenster erzeugen
-
Hallo,
ich bin gerade dabei, mich in die Darstellung von Fenstern mit WinAPI einzuarbeiten. Das Darstellen eines Fensters mit anschließenden Dialogboxen, die sich auf Buttondruck öffnen, klappt auch bereits. Nur jetzt stehe ich vor dem Problem, dass ich nicht weiß, wie ich ein weiteres Fenster öffnen kann, wenn ein Button gedrückt wurde. Alle Beiträge zu dem Thema, die ich mir hier durchgelesen habe, haben mir leider nicht geholfen. Es will einfach nicht klappen und ich weiß nicht, wieso. Hier mal der Quelltext:
#include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain (HINSTANCE hI, HINSTANCE hPrI, PSTR szCmdLine, int iCmdShow) { char szName[] = "Window Class"; HBRUSH MyBrush = CreateSolidBrush(RGB(999, 999, 999)); WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hI; wc.hIcon = LoadIcon (NULL, IDI_INFORMATION); wc.hCursor = 0; wc.hbrBackground = MyBrush; wc.lpszMenuName = NULL; wc.lpszClassName = szName; RegisterClass (&wc); HWND hwnd = CreateWindow (szName, "Erstes Fenster", WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX, 380, // Erster Wert: Abstand des Fensters zum linken Bildschirmrand. 200, // Zweiter Wert: Abstand des Fensters zum oberen Bildschirmrand. 490, // Dritter Wert: Fensterbreite. 120, // Vierter Wert: Fensterhöhe. NULL, NULL, hI, NULL); ShowWindow (hwnd, iCmdShow); UpdateWindow (hwnd); hwnd2 = CreateWindow (szName, "Zweites Fenster", WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX, 380, // Erster Wert: Abstand des Fensters zum linken Bildschirmrand. 200, // Zweiter Wert: Abstand des Fensters zum oberen Bildschirmrand. 490, // Dritter Wert: Fensterbreite. 120, // Vierter Wert: Fensterhöhe. NULL, NULL, hI, NULL); ShowWindow (hwnd2, iCmdShow); UpdateWindow (hwnd2); // Message handeln START MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return msg.wParam; } // Message handeln ENDE LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; HWND hwndButton; switch (message) { case WM_PAINT: hdc = BeginPaint (hwnd, &ps); SetBkMode(hdc, TRANSPARENT); // Macht den weißen Texthintergrund transparent. SetTextColor (hdc, RGB(0, 0, 0)); // Mit den RGB-Werten wird die Textfarbe festgelegt. TextOut (hdc, 3, 5, "Test", 4); EndPaint (hwnd, &ps); case WM_CREATE: hwndButton = CreateWindow ("BUTTON", "-> Blub <-", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 155, 40, 170, 30, hwnd, (HMENU)2, (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL); return 0; case WM_COMMAND: ....... return 0; case WM_DESTROY: PostQuitMesage(0); return 0; } return DefWindowProc (hwnd, message, wParam, lParam); }
Sorry für diese vielleicht einfache Frage, aber ich zerbreche mir darüber nun schon stundenlang den Kopf und durchforste sämtliche Tutorials, die ich kenne und finde einfach keine nachvollziehbare Lösung dafür. Mein Compiler (Dev-C++) meckert jedes Mal rum. Ich bin für jeden Denkanstoß sehr dankbar
-
also ich hab sowas noch nicht gemacht aber ich denke, dass du 2 WindowProzeduren brauchst ( für jedes Fenster eine ), das heist auch 2 Fnesterklassen und momentan erstellst du 2 Fenster übereinander ( gleiche Koordinaten )
-> Das ist nur eine Annahme !
-
also das einfachste ist wenn du das zweite fenster als dialog darstellst
fuege deiner resourcen ein dialog hin, und gib diesen einen namendann rufst du diesen auf mit
::DialogBox(m_hInstance, MAKEINTRESOURCE(IDD_DIALOG), m_ParentWnd, (DLGPROC)DlgProg);
DlgProg ist fuer die messages vom dialog, wenn du ein parent uebergibst ist es modal {das parent ist derweile nicht benutzbar}
amsonsten machst du einfach NULL als parent, dann steht es allein und du kannst in beiden fenster interagierenein zweites "normales" fenster hab ich selber noch nicht gemacht, meistens nur dialog fuer die settings usw, und das geht so ja recht einfach
ich denk mir
ein "CreateWindow" auf eine neue registrierte klasse wie du es schon gemacht hast, und dann einfach aufrufen mit showwindow und positionieren und als parent wieder 0 uebergeben, aber wegen den messages weiss ich grad nicht
dialog ist hundert pro einfacher
-
Hallo,
danke für die Antworten, aber im Moment fällt es mir ziemlich schwer, das zu verstehen. Inwiefern soll ich meinen Ressourcen einen Dialog hinzufügen? Das klingt alles ziemlich kompliziert. Könntest du das etwas, nunja, genauer schreiben? Ich bin nämlich noch Anfänger und noch nicht so geübt im Umgang mit Fenstern ^^
-
Hi,
erstmal 7 Sachen vorweg :
1. Deine Anwendung ist nicht Zeichensatz unabhängig (ANSI/UNICODE).
2. Das hier ist falsch:Itachi schrieb:
CreateSolidBrush(RGB(999, 999, 999));
RGB-Farbwerte setzen sich aus Teilwerten im Bereich von 0-255 zusammen. 999 ist viel zu groß!
3. Von dieser Definition hier:Itachi schrieb:
HWND hwndButton;
in Deiner 'WndProc' hast Du rein gar nichts, da diese Variable nicht statisch ist und so ihren Wert nach WM_CREATE nicht behält.
4. Du musst den Brush 'MyBrush' auch wieder freigeben, sonst gibts ein GDI-Leak (siehe WinMain).
5. Es empfiehlt sich folgende Definitionen in den WM_PAINT-Handler mit hinein zunehmen, da diese Variablen auch nur als Reaktion auf WM_PAINT benötigt werden, nicht bei jeder Nachricht. Das ist etwas performanter.Itachi schrieb:
HDC hdc; PAINTSTRUCT ps;
6. Bei WM_PAINT fehlt das 'return (0);' .
7. Es empfielt sich ID's (von Child-Controls) via #define o.ä. vorher festzulegen; dann behält man leichter den Überblick.Hier mal eine korrigierte Version die auch 2 Fenster erstellt (ohne Dialoge); die Nachrichten werden getrennt in 2 Message-Loops abgehandelt (Der Code ist getestet und sollte einwandfrei funktionieren).
#include <windows.h> #define BTN_MAIN_BUTTON_ID 1 #define BTN_SUB_BUTTON_ID 2 // ID's können auch gleich sein, da getrennte WndProc's LRESULT CALLBACK MainWndProc(HWND,UINT,WPARAM,LPARAM); LRESULT CALLBACK SubWndProc (HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hI, HINSTANCE hPrI, PSTR szCmdLine, int iCmdShow) { TCHAR szMainClass[] = TEXT("Main Window Class"), szSubClass[] = TEXT("Sub Window Class"); HBRUSH hbBkgndBrush = CreateSolidBrush(RGB(0, 255, 255)); // Farbe: Magenta WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hI; wc.hIcon = LoadIcon(NULL, IDI_INFORMATION); wc.hCursor = 0; wc.hbrBackground = hbBkgndBrush; wc.lpszMenuName = NULL; wc.lpszClassName = szMainClass; if(!RegisterClass(&wc)) { MessageBox(NULL, TEXT("Fehler beim Registrieren der Fensterklasse!"), NULL, MB_OK | MB_ICONERROR); return (0); } // Hier Änderungen die das 2. Fenster betreffen: wc.lpfnWndProc = SubWndProc; wc.lpszClassName = szSubClass; if(!RegisterClass(&wc)) { MessageBox(NULL, TEXT("Fehler beim Registrieren der Fensterklasse!"), NULL, MB_OK | MB_ICONERROR); return (0); } HWND hWndMain = CreateWindow(szMainClass, TEXT("Erstes Fenster"), WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX, 50, // Erster Wert: Abstand des Fensters zum linken Bildschirmrand. 200, // Zweiter Wert: Abstand des Fensters zum oberen Bildschirmrand. 490, // Dritter Wert: Fensterbreite. 120, // Vierter Wert: Fensterhöhe. NULL, NULL, hI, NULL); ShowWindow(hWndMain, iCmdShow); UpdateWindow(hWndMain); HWND hWndSub = CreateWindow(szSubClass, TEXT("Zweites Fenster"), WS_BORDER | WS_SYSMENU | WS_MINIMIZEBOX, 50 + 490, // Erster Wert: Abstand des Fensters zum linken Bildschirmrand. 200, // Zweiter Wert: Abstand des Fensters zum oberen Bildschirmrand. 490, // Dritter Wert: Fensterbreite. 120, // Vierter Wert: Fensterhöhe. NULL, NULL, hI, NULL); ShowWindow(hWndSub, iCmdShow); UpdateWindow(hWndSub); // Message handeln START MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } DeleteObject(hbBkgndBrush); return (static_cast<int>(msg.wParam)); } // Window Procedure of the first window: LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam) { static HWND hWndButton; switch(uiMessage) { case WM_CREATE: hWndButton = CreateWindow(TEXT("BUTTON"), TEXT("-> Blub <-"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 155, 40, 170, 30, hWnd, reinterpret_cast<HMENU>(BTN_MAIN_BUTTON_ID), reinterpret_cast<HINSTANCE>(GetWindowLongPtr(hWnd, GWL_HINSTANCE)), NULL); return (0); case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); SetBkMode(hdc, TRANSPARENT); // Macht den weißen Texthintergrund transparent. SetTextColor(hdc, RGB(0,0,0)); // Mit den RGB-Werten wird die Textfarbe festgelegt. TextOut(hdc, 3, 5, TEXT("1. Fenster"), lstrlen(TEXT("1. Fenster"))); EndPaint(hWnd, &ps); return (0); } case WM_COMMAND: return (0); case WM_DESTROY: PostQuitMessage(0); return (0); } return (DefWindowProc(hWnd, uiMessage, wParam, lParam)); } // Window Procedure of the second window: LRESULT CALLBACK SubWndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam) { static HWND hWndButton; switch(uiMessage) { case WM_CREATE: hWndButton = CreateWindow(TEXT("BUTTON"), TEXT("-> Blah <-"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 155, 40, 170, 30, hWnd, reinterpret_cast<HMENU>(BTN_SUB_BUTTON_ID), reinterpret_cast<HINSTANCE>(GetWindowLongPtr(hWnd, GWL_HINSTANCE)), NULL); return (0); case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); SetBkMode(hdc, TRANSPARENT); // Macht den weißen Texthintergrund transparent. SetTextColor(hdc, RGB(0,0,0)); // Mit den RGB-Werten wird die Textfarbe festgelegt. TextOut(hdc, 3, 5, TEXT("2. Fenster"), lstrlen(TEXT("2. Fenster"))); EndPaint(hWnd, &ps); return (0); } case WM_COMMAND: return (0); case WM_DESTROY: PostQuitMessage(0); return (0); } return (DefWindowProc(hWnd, uiMessage, wParam, lParam)); }
Da drin sollten die oben aufgelisteten Fehler korrigiert sein. Guck Dir das mal an und versuch es auch zuverstehen .
Nochwas zum Code: 'GetWindowLongPtr' ist im Gegensatz zu 'GetWindowLong' eine 64-Bit kompatible Version dieser Funktion. Ein reinterpret_cast bzw. static_cast sind Cast-Operatoren aus C++ .-------------------------------------------
PS: @Mr Evil: Wenn Du es richtig gemacht hast, sollte dieser Cast unnötig sein und Du solltest ihn weglassen :
Mr Evil schrieb:
::DialogBox(m_hInstance, MAKEINTRESOURCE(IDD_DIALOG), m_ParentWnd, (DLGPROC)DlgProg);
-
Hallo CodeFinder,
du glaubst gar nicht, wie dankbar ich dir bin! Es funktioniert alles bestens. Genau so wollte ich das haben. Einige kleine Abschnitte des Codes verstehe ich zwar noch nicht ganz, aber im Großen und Ganzen ist alles nachvollziehbar.
Ich danke dir vielmals
Gruß,
Itachi (jetzt auch angemeldet *g*)
-
Jupp, kein Problem. Wenn Du willst kannst Du auch noch fragen, falls etwas unklar ist - oder einfach mal googeln .
-
CodeFinder schrieb:
Jupp, kein Problem. Wenn Du willst kannst Du auch noch fragen, falls etwas unklar ist - oder einfach mal googeln .
Hallo,
drei Fragen haben sich da noch aufgeworfen
1. Weißt Du, wie ich TextOut mehrzeilig machen kann?
2. Weißt Du auch, wie ich die Font und Schriftgröße des mit TextOut ausgegebenen Textes ändern kann?
3. Kannst Du mir sagen, wie ich Musik in ein Projekt integriere und sie auch von dort mit PlaySound abspiele?Das wäre dann auch alles. Würde mich über Hilfe freuen
Greetz
-
Itachi schrieb:
1. Weißt Du, wie ich TextOut mehrzeilig machen kann?
Ja es mehrfach, evtl. in einer Schleife, aufrufen. Alternativ kannst Du DrawText(Ex).
Itachi schrieb:
2. Weißt Du auch, wie ich die Font und Schriftgröße des mit TextOut ausgegebenen Textes ändern kann?
Jupp, via: CreateFont(Indirect), SelectObject (DeleteObject)
Itachi schrieb:
3. Kannst Du mir sagen, wie ich Musik in ein Projekt integriere und sie auch von dort mit PlaySound abspiele?
Entweder als Datei; dann den Dateinamen übergeben. Oder Du fügst eine WAVE-Resource in Dein Projekt ein und gibst dann diese Resource beim Funktionsaufruf an. Nähere Infos siehe: http://msdn2.microsoft.com/en-us/library/ms712879.aspx
-
lol? - das ganze nent sich child window aber egal ..
-
Kann ich das zweites Fenster, welches ich erstellt habe (ob obrigen Quellcodebeispiel) schließen, ohne das sich das erste Fenster (MainWindow) auch schließt.
Wenn ja, wie?
Bitte mit Quellcodebeispielen wenn möglichHG
BlackShadow281
-
Mal grundsätzlich:
Dein zweites Fenster schließt nihct. Die Ursache ist einfach, dass Dien Programm terminiert.
Wenn das erste Fenster geschlossen wird dann rufst Du PostQuitMessage(0); auf.
Das terminiert die Message Loop und damit das Programm.
Wenn also das Programm weiter laufen soll, darfst Du PostQuitMessage(0); nicht aufrufen.Dann stellt sich für mich die Frage wie regelst Du das Programmende... möglich wäre ein globaler Zähler, der die Instanzen von Fenstern zählt und wenn das letzte schließt, wird auch PostQuitMessage(0); ausgeführt.
-
Vielen Dank an Martin Richter.
Ich habe einfach den Aufruf der Methode PostQuitMessage(0); bei dem zweiten Fenster herausgenommen.
Nun klappt alles so, wie ich mir das vorgestellt habe.Sollte ich weitere Fragen haben, melde ich mich
Herzliche Grüße
BlackShadow281