[WinAPI] Child-Fenster - Theorie? (evtl. mit Codebeispielen)

HCWD

Erfahrenes Mitglied
Hi Community.

Ich befasse mich seid einer Woche mit WinAPI und habe gleich eine Frage.
Wenn ich ein Hauptfenster erstellt habe und möchte per Menüklick (bsp. ein Login-) Fenster öffnen, dass jedoch im Arbeitsbereich des Hauptfensters erscheinen soll, wie gehe ich theoretisch vor beim Programmieren?

Reicht da die CreateWindowEx Funktion oder muss ich das komplette Konstrukt nocheinmal programmieren, nur dass ich bei der Parent angeabe nicht mehr Desktop sondern den hWnd vom Hauptfenster angebe.

Über Codebeispiele würde ich mich freunen, weil die vorhandenen in diesem Forum sind mir nicht ganz ersichtlich.

Greetz

HCWD
 
Im Prinzip ist ein Child Fenster ein ganz neues Fenster, sprich du fängst den ganzen Ramsch vom Hauptfenster nochmal von vorne an, nur dass ein paar Teile anderswo stehen

Zuerst brauchst du die WndProc fürs neue Fenster, als Prototyp direkt unterhalb vom Prototyp des Hauptfensters

Code:
LRESULT CALLBACK MyChildWindow (HWND, UINT, WPARAM, LPARAM);

Dann brauchst du ein Handle, also machst du aus

Code:
// vorher HWND hwnd;
// nachher
HWND hwnd, MyChild;

in der WinMain kommt dann unter RegisterClassEx(); nochmal die ganze Struktur für WNDCLASSEX, inkl einem zweiten RegisterClassEx();, man muss aber nur die Werte nochmal angeben, die im Child Fenster anders sind als im Hauptfenster, meist reicht es icon und name zu ändern

Code:
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.lpszClassName = "MyChildWindowname";
wc.lpfnWndProc = MyChildWindow;
RegisterClassEx (&wc);

Im Hauptfenster brauchst du dann das Event

Code:
case WM_CREATE:
{
MyChild = CreateWindow(
"MyChildWindowname",
NULL, // kein Titel
WS_CHILD | WS_VISIBLE, // Fenster Style
0,0,0,0, // Position des Fensters innerhalb des Hauptfenster
hwnd, // Handle des Hauptfensters
NULL, // kein HMENU
hinstance, // HINSTANCE des Hauptfensters
NULL
);
return 0;
}
break;

Immer noch im Hauptfenster ein weiteres Event, falls sich die Grösse des Hauptfensters ändert

Code:
case WM_SIZE:
{
MoveWindow(MyChild, 0,0,0,0, true); // Werte für Position eintragen
return 0;
}
break;

Und schliesslich brauchst du noch die echte WndProc

Code:
LRESULT CALLBACK MyChildWindow (HWND MyChild, UINT msg, WPARAM wParam, LPARAM lParam)
{

switch (msg)
{
case WM_PAINT:
{
// ....
// ....
// ....
}
break;

// usw

}

return DefWindowProc (MyChild, msg, wParam, lParam);

}

Sofern nicht zu viele Tippfehler drin sind, sollte das so funktionieren
 
Vielen Dank... werd ich gleich mal probieren... eine Frage von vorne rein:

wird dann dieses Childfenster im Pixelbereich des ersten Fensters sein oder wird man es am kompletten Bildschirm verschieben können?

2. Frage:

wird dann das 1. Fenster anwählbar sein? Also werden die Listeners weiter hinlaufen? Oder wird das Child-Fenster modular angezeigt?
 
Ein Child Fenster wird nur innerhalb des Parent Fensters angezeigt, verschiebt man es aus dem Parent hinaus, ist es nicht mehr sichtbar, auch nicht mehr anklickbar, aber sehr wohl noch vorhanden
Bei Klick ins Childfenster reagiert nur das Child Fenster
Falls das Child Fenster kleiner ist als das Parent oder so verschoben wird, dass ein Teil des Parent sichtbar ist, wird auf einen Klick dort das Parent Fenster reagieren
 
Ahhh.... Danke.... somit werde ich mich jetzt mal an das praktische ran machen mit genügend Vorwissen ^^

Eine Frage zu der MW_COMAND Zeile:

was muss ich genau da eintragen? den aufruf des Childs oder nur, dass es angezeigt wird?
 
Zuletzt bearbeitet:
Ich bekomm das einfach nicht gebacken. Wenn ich das Programm starte, sieht man es so wie es sein soll.... Jedoch sobald ich auf Login im Menü klicke, bricht das Programm sofort ab. Was ist am Code falsch?

Code:
#include <windows.h>
#include "resource.h"

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK LoginProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    HWND hWnd;
    MSG Msg;
    
	WNDCLASS WndClass, wc;
	
	WndClass.style = 0;
	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.lpfnWndProc = WndProc;
	WndClass.hInstance = hInstance;
	WndClass.hbrBackground = (HBRUSH) CreateSolidBrush (RGB ( 128, 128, 128));
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	WndClass.lpszMenuName = MAKEINTRESOURCE(IDMAINMENU);
	WndClass.lpszClassName = "WindowClass";
	
	RegisterClass(&WndClass);
	
	wc.style = 0;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.lpfnWndProc = LoginProc;
	wc.hInstance = hInstance;
	wc.hbrBackground = (HBRUSH) CreateSolidBrush (RGB ( 128, 128, 128));
	wc.hCursor = 0;
	wc.hIcon = 0;
	wc.lpszMenuName = NULL;
	wc.lpszClassName = "Login";
	
	RegisterClass(&wc);
	
    hWnd = CreateWindow("WindowClass","GenixX",
		WS_OVERLAPPEDWINDOW,
		0,0,800,600,NULL,NULL,
		hInstance, NULL);
	
    ShowWindow (hWnd, nCmdShow);
	UpdateWindow (hWnd);
	
	while (GetMessage(&Msg, NULL, 0, 0))
	{
		DispatchMessage(&Msg);
	}
	return (Msg.wParam);
}

LRESULT CALLBACK WndProc (HWND hWnd, UINT uiMessage, WPARAM wParam,LPARAM lParam)
{
    char string[255];
    HWND login;
    
	switch(uiMessage)
	{            
    case WM_COMMAND:
          switch(LOWORD(wParam))
             {
               case IDM_USER_LOGIN:
                {
                     login = CreateWindow(  "Login",
                                 NULL,
                                 WS_CHILD | WS_VISIBLE | WS_DLGFRAME,
                                 0,
                                 0,
                                 0,
                                 0,
                                 hWnd,
                                 NULL,
                                 ((LPCREATESTRUCT) lParam)->hInstance,
                                 NULL);
                     return 0;
                }  
               break;
               
               case IDM_CONN_CONNECT:
                 LoadString(GetModuleHandle(NULL),ID_STRING_CONNECT,string,sizeof(string));
                 MessageBox(hWnd,string,"Connect",MB_ICONINFORMATION);
               break;
               
               case IDM_CONN_DISCONNECT:
                 LoadString(GetModuleHandle(NULL),ID_STRING_DISCONNECT,string,sizeof(string));
                 MessageBox(hWnd,string,"Disconnect",MB_ICONINFORMATION);
               break;
               
               case IDM_HELP_ABOUT:
                 LoadString(GetModuleHandle(NULL),ID_STRING_ABOUT,string,sizeof(string));
                 MessageBox(hWnd,string,"Über",MB_ICONINFORMATION);
               break;
               
               case IDM_FILE_QUIT:
                  DestroyWindow(hWnd);
               break;
               }
         break;
         
    case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
		break;
		
	default: 
		return DefWindowProc (hWnd, uiMessage,
			wParam, lParam);
	}
}

LRESULT CALLBACK LoginProc (HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam)
{
	switch(uiMessage)
	{
    case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
		break;
		
	default: 
		return DefWindowProc (hWnd, uiMessage,
			wParam, lParam);
	}
}
 
Das Child hat keine Grösse, alle Werte im CreateWindow 0 und ein WM_SIZE ist im Hauptfenster nicht vorhanden
Ausserdem erstellt man ein Fenster unter WM_CREATE
Wenn es da noch nicht sichtbar sein soll, lässt man WS_VISIBLE im CreateWindow weg und macht später

Code:
case IDM_USER_LOGIN:
                {
                   ShowWindow(login, SW_SHOW);
                }

Ausserdem muss es heissen

LRESULT CALLBACK LoginProc (HWND login, UINT uiMessage, WPARAM wParam, LPARAM lParam)

Und dann gibt es in Child Fenstern kein WM_DESTROY

Mehr habe ich auf den ersten Blick nicht gesehen
 
ok danke für deine Antwort. Jedoch hab ich eine theoretische Frage:

Heißt das, dass alle Hilfsprogramme (Fenster) beim Beispiel "Microsoft Word" schon erstellt sind, nur durch das Menü ich diese anzeige und wieder verstecke?
 
Keine Ahnung was die Experten bei M$ machen
Natürlich gibt es auch Möglichkeiten Fenster in der runtime zu erstellen und wieder zu löschen, aber das erfordert schon ein paar Fachkenntnisse
Für Anfänger ist die Methode mit SW_SHOW und SW_HIDE sicher besser geeignet
 
Für "kleinere Dinge" wie zum Beispiel die Abfrage von Benutzernamen und Password benutzte ich Dialoge, welche ich als Resource erstellt habe.

Gruß
 

Neue Beiträge

Zurück