Größenangabe beim Erstellen eines Fensters soll sich nur auf den Client-Bereich beziehen



  • Wie sieht denn diese dynamische Anpassung aus? Ist es das mit GetSystemMetrics oder die Sache mit GetWindowRect/GetClientRect oder etwas ganz anderes?
    Das Problem ist ja auch, daß man das eigentlich immer machen muß. Auch wenn ich ein festgelegtes Menü habe und das Fenster in der Größe nicht veränderbar ist. Denn dann kann es ja immer noch sein, daß jemand ein Layout "Extragroß" hat, bei dem das Menü dann nochmal vergrößert wird und so nur auf zwei Zeilen paßt.
    Wieso haben die das nicht gleich so gemacht, daß sich eine Größenangabe immer auf den Client-Bereich bezieht? Ich meine, gibt es überhaupt reale Fälle, wo man bei der Größenangabe tatsächlich die wirkliche Größe, inklusive der Titelleiste und des Menüs, haben will?



  • NES-Spieler schrieb:

    Wie sieht denn diese dynamische Anpassung aus? Ist es das mit GetSystemMetrics oder die Sache mit GetWindowRect/GetClientRect oder etwas ganz anderes?

    Jo Genau so...bzw. WM_SIZE.

    NES-Spieler schrieb:

    [...]Denn dann kann es ja immer noch sein, daß jemand ein Layout "Extragroß" hat[...]

    Huh?!, Wat dat denn ? 😕



  • Jo Genau so...bzw. WM_SIZE.

    Ja, welches ist jetzt besser. GetSystemMetrics oder GetWindowRect/GetClientRect?

    Layout "Extragroß": http://img243.imageshack.us/img243/6603/extragronx4.png (Der Link verweist direkt auf das Bild, nicht auf die Seite mit ihren ganzen Popups.)



  • NES-Spieler schrieb:

    Jo Genau so...bzw. WM_SIZE.

    Ja, welches ist jetzt besser. GetSystemMetrics oder GetWindowRect/GetClientRect?

    WM_SIZE

    NES-Spieler schrieb:

    Layout "Extragroß": http://img243.imageshack.us/img243/6603/extragronx4.png (Der Link verweist direkt auf das Bild, nicht auf die Seite mit ihren ganzen Popups.)

    💡 ➡ WM_SETTINGCHANGE oder WM_SIZE (bin mir da nit ganz so sicher; TryAndError)



  • Was WM_SIZE ist, weiß ich. Meine Frage war: Welche Funktion(en) soll ich zum Berechnen generell lieber nehmen?
    a) GetSystemMetrics
    b) GetWindowRect und GetClientRect

    char ErmittleAntwort ()
    {
        char antwort;
    
        do
        {
            cin>>antwort;
    
            antwort=tolower (antwort);
        }
        while (antwort!='a' && antwort!='b');
    
        return antwort;
    }
    

    😉



  • NES-Spieler schrieb:

    Was WM_SIZE ist, weiß ich. Meine Frage war: Welche Funktion(en) soll ich zum Berechnen generell lieber nehmen?
    a) GetSystemMetrics
    b) GetWindowRect und GetClientRect

    Wo ist dein Problem...? Da hast du doch alle Infos. Was willst du mit GetSystemMetrics ?

    WM_SIZE
    The WM_SIZE message is sent to a window after its size has changed.

    WM_SIZE
    fwSizeType = wParam; // resizing flag
    nWidth = LOWORD(lParam); // width of client area
    nHeight = HIWORD(lParam); // height of client area

    Parameters
    fwSizeType
    Value of wParam. Specifies the type of resizing requested. This parameter can be one of the following values: Value Meaning
    SIZE_MAXHIDE Message is sent to all pop-up windows when some other window is maximized.
    SIZE_MAXIMIZED The window has been maximized.
    SIZE_MAXSHOW Message is sent to all pop-up windows when some other window has been restored to its former size.
    SIZE_MINIMIZED The window has been minimized.
    SIZE_RESTORED The window has been resized, but neither the SIZE_MINIMIZED nor SIZE_MAXIMIZED value applies.

    nWidth
    Value of the low-order word of lParam. Specifies the new width of the client area.
    nHeight
    Value of the high-order word of lParam. Specifies the new height of the client area.
    Return Values
    If an application processes this message, it should return zero.

    Remarks
    If the SetScrollPos or MoveWindow function is called for a child window as a result of the WM_SIZE message, the bRedraw parameter should be nonzero to cause the window to be repainted.

    Although the width and height of a window are 32-bit values, the nWidth and nHeight parameters of the WM_SIZE message contain only the low-order 16 bits.

    QuickInfo
    Windows NT: Requires version 3.1 or later.
    Windows: Requires Windows 95 or later.
    Windows CE: Requires version 1.0 or later.
    Header: Declared in winuser.h.



  • Ich hab jetzt nicht den kompletten Thread gelesen, kann also sein, dass das schon mal jemand gepostet hat 😉

    Aber: Warum probierst du es nicht so:
    Du rechnest mit AdjustWindowRectEx deine Client-Größe aus. Damit erstellst du das Fenster. Dann guckst du mittels GetClientSize, wie groß deine Client-Area jetzt ist. Dann packst du drauf, was du noch brauchst.

    #define CLIENT_WIDTH    200 // Deine Client-Breite
    #define CLIENT_HEIGHT   300 // Deine Client-Höhe
    #define WINDOW_STYLE    WS_MODALWINDOW // Dein Window-Style
    #define WINDOW_STYLEEX  0 // Dein Window-ExStyle
    
    ... WinMain( ... )
    {
        RECT rcWnd = { 0, 0, 200, 300 };
        AdjustWindowRectEx( &rcWnd, WINDOW_STYLE, TRUE /*Wolltest ja ein Menü...*/, WINDOW_STYLEEX );
    
        // Jetzt ist in rcWnd deine Fenstergröße
        HWND hWnd = CreateWindow( ... );
    
        // Die Größe des Client-Bereiches
        RECT rcClientTooBig;
        GetClientRect( hWnd, &rcClientTooBig );
    
        // Wenn rcClientTooBig nicht deine geünschte Größe hat...
        if ( rcClientTooBig.right!=CLIENT_WIDTH && rcClientTooBig.bottom!=CLIENT_HEIGHT )
        {
            // Holen wir deine Größe vom ganzen Fenster
            RECT rcWndTooBig;
            GetWindowRect( hWnd, &rcWndTooBig );
    
            // Fenster-Größe richten
            rcWndTooBig.right += CLIENT_WIDTH - rcClientTooBig.right;
            rcWndTooBig.bottom += CLIENT_HEIGHT - rcClientTooBig.bottom;
            SetWindowPos( hWnd, NULL, 0, 0, rcWndTooBig.right-rcWndTooBig.left, rcWndTooBig.bottom-rcWndTooBig.top, SWP_NOZORDER|SWP_NOMOVE );
    
            // Jetzt sollte dein Fenster die richtige Größe haben  :+1: 
        }
    }
    


  • Vielen Dank. Ich kam bisher noch nicht dazu, mich selbst mit den Funktionen zu befassen, demnach hast Du mir also eine Menge Arbeit erspart. Doch jetzt hab ich noch immer ein kleines Problemchen. Hier der Code der WinMain (nur das nötigste):

    const DWORD STYLE=WS_OVERLAPPEDWINDOW,
                      EX_STYLE=0;
    const UINT WIDTH=200, HEIGHT=150; //Die gewünschte Client-Größe
    HWND window;
    
    //Registrieren der Fensterklasse (WNDCLASSEX)
    ...
    
    window=CreateWindowEx (...);
    /*Die Größenangaben sind hier erstmal CW_USEDEFAULT,
      da sie ohnehin geändert werden*/
    
    //Erstellen eines "Pseudomenüs"
    //-----------------------------
    
    HMENU menu=CreateMenu (),
          subMenu=CreatePopupMenu ();
    
    /*Je größer der Wert der Abbruchbedingung,
      desto größer und mehrzeiliger ist logischerweise das Menü*/
    for (UINT i=1; i<=3; i++)
    {
        AppendMenu (menu, MF_STRING|MF_POPUP,
                    reinterpret_cast<UINT> (subMenu),
                    "ABCDEFGHIJKLMNOP");
        AppendMenu (subMenu, MF_STRING, i, "Text");
    }
    
    SetMenu (window, menu);
    
    //Festlegen der korrekten Größe
    //-----------------------------
    
    RECT clientRect;
    bool firstTime=true;
    
    do
    {
        RECT rect={0, 0, WIDTH, firstTime?HEIGHT:HEIGHT+(HEIGHT-(clientRect.bottom-clientRect.top))};
        /*Beim erstem Mal bekommt das Rechteck die normale Höhe,
          beim zweiten Mal die normale Höhe plus das Stück,
          das durch das mehrzeilige Menü überdeckt wird*/
    
        firstTime=false;
    
        AdjustWindowRectEx (&rect, STYLE, GetMenu (window)?true:false, EX_STYLE);
    
        SetWindowPos (window, NULL, 0, 0, rect.right-rect.left, rect.bottom-rect.top, 0);
    
        GetClientRect (window, &clientRect);
    }
    while (clientRect.bottom-clientRect.top!=HEIGHT);
    /*Die Anpassung wird solange vorgenommen,
      bis der Client-Bereich tatsächlich so groß ist, wie gewünscht.*/
    
    //Anzeigen des Fensters etc.
    //...
    

    Das ganze funktioniert auch genau so, wie ich es mir vorstelle. Bis auf eine Ausnahme: Wenn das Menü so groß ist, daß es den Client-Bereich, der nach dem ersten Schleifendurchlauf (nach dem ersten Aufrufen von GetClientRect) existiert, komplett überdeckt (wenn man also bei der menüschleife den Wert zum beispiel auf 10 setzt), hängt sich das Programm in einer Endlosschleife auf, weil es irgendwie nie die korrekten Größenwerte erreicht. Wo liegt hier mein Fehler?



  • Badestrand schrieb:

    // Die Größe des Client-Bereiches
        RECT rcClientTooBig;
        GetClientRect( hWnd, &rcClientTooBig );
    
        // Wenn rcClientTooBig nicht deine geünschte Größe hat...
        if ( rcClientTooBig.right!=CLIENT_WIDTH && rcClientTooBig.bottom!=CLIENT_HEIGHT )
        {
            // Holen wir deine Größe vom ganzen Fenster
            RECT rcWndTooBig;
            GetWindowRect( hWnd, &rcWndTooBig );
    
            // Fenster-Größe richten
            rcWndTooBig.right += CLIENT_WIDTH - rcClientTooBig.right;
            rcWndTooBig.bottom += CLIENT_HEIGHT - rcClientTooBig.bottom;
            SetWindowPos( hWnd, NULL, 0, 0, rcWndTooBig.right-rcWndTooBig.left, rcWndTooBig.bottom-rcWndTooBig.top, SWP_NOZORDER|SWP_NOMOVE );
    
            // Jetzt sollte dein Fenster die richtige Größe haben  :+1: 
        }
    

    Warum nicht das statt deiner Schleife?



  • Stimmt, die Schleife ist überflüssig. Vielen Dank für den Impuls.

    Aber: Wenn ich einfach nur abfrage

    if (rcClientTooBig.bottom!=CLIENT_HEIGHT
    

    dann kann es immer noch zu Problemen kommen, wenn das Menü am Anfang so riesengroß ist, daß es das gesamte ursprüngliche Fenster verdeckt. Da muß dann am Ende doch noch eine Schleife her. Ich habe das funktionierende Programm mal hier aufgeschrieben, falls es jemanden interessiert:

    #include <windows.h>
    
    LRESULT CALLBACK WindowProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);
    
    int WINAPI WinMain (HINSTANCE instance, HINSTANCE, LPSTR, int cmdShow)
    {
    	const DWORD STYLE=WS_OVERLAPPEDWINDOW,
    	            EX_STYLE=0;
    	const UINT WIDTH=200, HEIGHT=150;
    	HWND window;
    
    	/*Punkt 1: Ermitteln der richtigen Fenstergröße
    	  ---------------------------------------------*/
    
    	RECT rect={0, 0, WIDTH, HEIGHT};
    
    	AdjustWindowRectEx (&rect, STYLE, true, EX_STYLE);
    
    	/*Punkt 2: Erstellen des Fensters
    	  -------------------------------*/
    
    	WNDCLASSEX wndClassEx={0};
    	MSG msg;
    
    	wndClassEx.cbSize=sizeof (WNDCLASSEX);
    	wndClassEx.lpfnWndProc=WindowProc;
    	wndClassEx.hInstance=instance;
    	wndClassEx.hIcon=LoadIcon (NULL, IDI_APPLICATION);
    	wndClassEx.hCursor=LoadCursor (NULL, IDC_ARROW);
    	wndClassEx.hbrBackground=reinterpret_cast<HBRUSH> (BLACK_PEN);
    	wndClassEx.lpszClassName="My Window Class";
    	wndClassEx.hIconSm=wndClassEx.hIcon;
    
    	RegisterClassEx (&wndClassEx);
    
    	window=CreateWindowEx (EX_STYLE, wndClassEx.lpszClassName, "Fenster", STYLE, CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, NULL, NULL, instance, NULL);
    
    	/*Punkt 3: Erstellen des Menüs
    	  ----------------------------*/
    
    	const UINT N=2;
        /*Diesen Wert ändern, um das Menü zu vergrößern.
          (Zum Beispiel mal auf 40 setzen.)*/
    
    	HMENU menu=CreateMenu (),
    	      subMenu=CreatePopupMenu ();
    
    	for (UINT i=1; i<=N; i++)
    	{
    		AppendMenu (menu, MF_STRING|MF_POPUP, reinterpret_cast<UINT> (subMenu), "ABCDEFGHIJKLMNOP");
    		AppendMenu (subMenu, MF_STRING, i, "Irgendwas");
    	}
    
    	SetMenu (window, menu);
    
    	/*Punkt 4: Korrigieren der Größe
    	  ------------------------------*/
    
    	do
    	{
    		GetClientRect (window, &rect);
    
    		if (rect.bottom!=HEIGHT)
    		{
    			RECT windowRect;
    
    			GetWindowRect (window, &windowRect);
    
    			windowRect.bottom+=HEIGHT-rect.bottom;
    
    			SetWindowPos (window, NULL, 0, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, SWP_NOMOVE);
    		}
    	}
    	while (rect.bottom!=HEIGHT);
    
    	/*Punkt 5: Start
    	  --------------*/
    
    	ShowWindow (window, cmdShow);
    	UpdateWindow (window);
    
    	while (GetMessage (&msg, NULL, 0, 0))
    	{
    		TranslateMessage (&msg);
    		DispatchMessage (&msg);
    	}
    
    	return msg.wParam;
    }
    
    LRESULT CALLBACK WindowProc (HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	switch(msg)
    	{
    	case WM_CLOSE:
    		DestroyWindow (wnd);
    		break;
    	case WM_DESTROY:
    		PostQuitMessage (0);
    		break;
    	default:
    		return DefWindowProc (wnd, msg, wParam, lParam);
    	}
    
    	return 0;
    }
    

Anmelden zum Antworten