MDI Child übermalt ToolBar



  • G' Abend,

    ich schreibe gerade an einem Programm und nutze die WinAPI. Ich nutze SDI und MDI Fenster inkl. ToolBar und Menuleiste.

    Wenn ich in meinem MDI Fenster ein Child erzeuge, so kann ich das über die ToolBar hinweg verschieben, so dass die ToolBar übermalt wird. Ich konnte im Netz dazu leider keine weiteren Informationen finden, da sich die Beispiele immer nur auf MDI ODER ToolBar beziehen.

    Weiß jemand, wie ich das Problem verhindern kann?

    Vielen Dank im Voraus

    MfG Torsten



  • Wie sieht denn bei dir die Hierarchie aus? Normalerweise erstellt das Framefenster Clientfenster und andere Fenster wie Toolbars/Statusbars etc. als Kindfenster.
    Die eigentlichen Childfenster („Dokumentenfenster”) haben als Elternfenster den Client, nicht das Framefenster:

    *********************************************************
    *					Frame			|			|		*
    *			|Toolbar|		|			|				*
    *		*************************************************
    *		*												*
    *		*		-------------							*
    *		*		-------------							*
    *	Fr	*		*			*		Client				*
    *		*		*	Child	*							*
    *		*		*			*							*
    *		*		-------------							*
    *		*												*
    *		*************************************************
    *						Frame							*
    *********************************************************
    

    Es sollte also gar nicht passieren können, dass die Dokumentenfenster über das Frame verschoben werden können.



  • Kindfenster können auch nicht außerhalb Ihres Frames liegen.

    Also 2 Ursachen:
    1. Das Child ist kein Kindfenster des MDI-Client.
    2. Das MDI-Client Fenster hat die falsche Größe oder Position.

    Lässt sich beides mit Spy++ kontrollieren.



  • Danke für die schnellen Antworten. Nur zur Kontrolle meinerseits:

    1. MDI Fenster mittels CreateWindowEx() erstellen (zuvor Klasse registrieren)
    2. MDI Clientbereich erstellen (in WinProc des MDI Fensters mit WM_NCREATE Message)
    3. ToolBar erstellen (mit Parenthandle des MDI Fensters)
    4. Kindfenster mittels SendMessage() erstellen (mit Parenthandle des Clientbereichs)

    Ist das so korrekt? Oder habe ich ein Problem mit der Reihenfolge?

    MfG Torsten



  • Toolbar ist Kind des Frames, liest sich bei Dir komisch.

    Ich würde nie in WM_NCCREATE das abhandeln. Immer erst in WM_CREATE



  • Hallo nochmal,

    ich habe die WM_NCCREATE rausgeschmissen, und verwende nun WM_CREATE. Danke für den Tip. Leider hat mich das nicht zum Ziel geführt, es muss noch ein Fehler in meinen Quelltexten enthalten sein.

    Ich habe mal ein neues Projekt mit schlichtem Quelltext erstellt, selbes Resultat. Die ToolBar wird übermalt. Kann da jemand helfen?

    lg Torsten

    #include <Windows.h>
    #include <CommCtrl.h>
    
    #define __FRAME__ "FRAME"
    #define __CHILD__ "CHILD"
    
    HWND frameHandle = 0;
    HWND clientHandle = 0;
    HWND childHandle = 0;
    HWND toolBarHandle = 0;
    signed imageListId = 0;
    
    void createChild();
    
    LRESULT CALLBACK windowProcedure_Frame(HWND _handle, UINT _message, WPARAM _wParam, LPARAM _lParam)
    {
    	switch (_message)
    	{
    		case WM_CLOSE:
    		{
    			PostQuitMessage(0);
    			break;
    		}
    		case WM_CREATE:
    		{
    			CLIENTCREATESTRUCT _clientCreateStructure = { 0, 0 };
    
    			clientHandle = CreateWindow(TEXT("MDICLIENT"), NULL,
    				(WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE), 0, 0, 0, 0, _handle, NULL, GetModuleHandle(NULL), (void*)&_clientCreateStructure);
    
    			toolBarHandle = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
    				(TBSTYLE_WRAPABLE | WS_CHILD), 0, 0, 0, 0, _handle, NULL, GetModuleHandle(NULL), NULL);
    
    			if (toolBarHandle)
    			{
    				SendMessage(toolBarHandle, TB_AUTOSIZE, 0, 0);
    				ShowWindow(toolBarHandle, TRUE);
    			}
    
    			createChild();
    
    			break;
    		}
    		case WM_SIZE:
    		{
    			SendMessage(toolBarHandle, TB_AUTOSIZE, 0, 0);
    			break;
    		}
    	}
    
    	return DefFrameProc(_handle, clientHandle, _message, _wParam, _lParam);
    }
    
    LRESULT CALLBACK windowProcedure_Child(HWND _handle, UINT _message, WPARAM _wParam, LPARAM _lParam)
    {
    	switch (_message)
    	{
    		case WM_CREATE:
    		{
    			break;
    		}
    	}
    
    	return DefMDIChildProc(_handle, _message, _wParam, _lParam);
    }
    
    void registerWindowClass_Frame()
    {
    	WNDCLASSEX _windowClass = { 0 };
    
    	_windowClass.cbSize = sizeof(WNDCLASSEX);
    	_windowClass.style = (CS_HREDRAW | CS_VREDRAW);
    	_windowClass.lpfnWndProc = windowProcedure_Frame;
    	_windowClass.hInstance = GetModuleHandle(NULL);
    	_windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    	_windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    	_windowClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
    	_windowClass.lpszClassName = (LPCSTR)__FRAME__;
    	_windowClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    
    	RegisterClassEx(&_windowClass);
    }
    
    void registerWindowClass_Child()
    {
    	WNDCLASSEX _windowClass = { 0 };
    
    	_windowClass.cbSize = sizeof(WNDCLASSEX);
    	_windowClass.style = (CS_HREDRAW | CS_VREDRAW);
    	_windowClass.lpfnWndProc = windowProcedure_Child;
    	_windowClass.hInstance = GetModuleHandle(NULL);
    	_windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    	_windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    	_windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    	_windowClass.lpszClassName = (LPCSTR)__CHILD__;
    	_windowClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    
    	RegisterClassEx(&_windowClass);
    }
    
    void initializeToolBar()
    {
    	HIMAGELIST imageListHandle = ImageList_Create(16, 16, (ILC_COLOR16 | ILC_MASK), 3, 0);
    
    	if (imageListHandle)
    	{
    		SendMessage(toolBarHandle, TB_SETIMAGELIST, (WPARAM)imageListId, (LPARAM)imageListHandle);
    		SendMessage(toolBarHandle, TB_LOADIMAGES, (WPARAM)IDB_STD_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
    
    		TBBUTTON tbButtons[3] =
    		{
    			{MAKELONG(STD_FILENEW,  imageListId), 0, TBSTATE_ENABLED, BTNS_AUTOSIZE,{ 0 }, 0, (INT_PTR)L"New" },
    			{MAKELONG(STD_FILEOPEN, imageListId), 1, TBSTATE_ENABLED, BTNS_AUTOSIZE,{ 0 }, 0, (INT_PTR)L"Open" },
    			{MAKELONG(STD_FILESAVE, imageListId), 2, 0,               BTNS_AUTOSIZE,{ 0 }, 0, (INT_PTR)L"Save" }
    		};
    
    		SendMessage(toolBarHandle, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
    		SendMessage(toolBarHandle, TB_ADDBUTTONS, (WPARAM)3, (LPARAM)&tbButtons);
    	}
    }
    
    void createChild()
    {
    	MDICREATESTRUCT _clientCreateStructure = { 0 };
    
    	_clientCreateStructure.szTitle = TEXT((LPCSTR)"Child");
    	_clientCreateStructure.hOwner = GetModuleHandle(NULL);
    	_clientCreateStructure.szClass = (LPCSTR)__CHILD__;
    	_clientCreateStructure.x = 50;
    	_clientCreateStructure.y = 50;
    	_clientCreateStructure.cx = 400;
    	_clientCreateStructure.cy = 300;
    	childHandle = (HWND)SendMessage(clientHandle, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&_clientCreateStructure);
    
    	if (childHandle)
    	{
    		ShowWindow(childHandle, SW_SHOW);
    	}
    }
    
    int WINAPI WinMain(HINSTANCE _applicationHandle, HINSTANCE /*_previousInstanceHandle*/, PSTR /*_szCmdLine*/, int /*_iCmdShow*/)
    {
    	registerWindowClass_Frame();
    	registerWindowClass_Child();
    
    	const HWND _handle = CreateWindowEx(WS_EX_WINDOWEDGE, (LPCSTR)__FRAME__, (LPCSTR)"Frame",
    		(WS_OVERLAPPEDWINDOW | WS_VISIBLE), 100, 100, 800, 600, NULL, NULL, _applicationHandle, 0);
    
    	initializeToolBar();
    
    	MSG _windowMessage = { 0 };
    
    	while (GetMessage(&_windowMessage, NULL, 0, 0))
    	{
    		bool _messageHandled = false;
    
    		if (!TranslateMDISysAccel(clientHandle, &_windowMessage))
    		{
    			TranslateMessage(&_windowMessage);
    			DispatchMessage(&_windowMessage);
    		}
    	};
    
    	return 0;
    }
    


  • Martin Richter schrieb:

    2. Das MDI-Client Fenster hat die falsche Größe oder Position.

    Das hat Martin Richter doch schon geschrieben. Du veränderst die Größe des Clients nicht (in WM_SIZE mit MoveWindow). DefFrameProc verschiebt den Client in das Clientrect des Frames, hierdurch hast du eben zwei Kindfenster, die sich überlappen.
    Generell solltest du alles noch einmal überarbeiten (Casts, defines, underscores...). Je größer das Programm wird, desto mehr Probleme wirst du bekommen, wenn du so weitermachst.