Win32 API question regarding menu heights and client size/area

Discussion in 'Web development / Programming' started by Dax, Aug 19, 2014.

  1. Dax

    Dax ライチュウ|タオ

    Messages:
    4,016
    Likes Received:
    20
    Please read this entire post before suggesting AdjustWindowRect[Ex], as it does not work (it gives bogus values, only accounting for one row of menu items) for what I need.

    I've been fighting with this for over 5 hours now, and I just can't figure out how to set my client areas properly when a menu needs to have two or more "rows".

    Basically, my problem is, I want to have the client area of my application be properly calculated, regardless of the menu height (sometimes my menu creates a second row for whatever reason, it'd be nice if I could keep them all on one row with a scroll arrow or something. I've tried multiple methods with no success.

    Here's one example I tried (pulled from Google):
    Code:
    SetWindowSize(int width, int height)
    {
      RECT rcClient, rcWindow;
    
       POINT ptDiff;
    
       GetClientRect(hWnd, &rcClient);
    
       GetWindowRect(hWnd, &rcWindow);
    
       ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
    
       ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
    
       MoveWindow(hWnd, rcWindow.left, rcWindow.top, width + ptDiff.x, height + ptDiff.y, TRUE);
    
       GetClientRect(hWnd, &rcClient);
    }
    
    If I pass 160, 144, for example, the client area/size is correct, but if I make it something like 320, 288 (e.g. 160 and 144 doubled), it's wrong, set to 320, 307 on the first call, then the correct 320, 288 on the next call (presumably because on the first call, the menu is 2 rows, then it's 1 row on the next call).

    Also tried this:
    Code:
    void SetWindowSize(int width, int height)
    {
       RECT client, window;
    
       GetClientRect(hWnd, &client);
       GetWindowRect(hWnd, &window);
    
       long desWidth = 0;
       long desHeight = 0;
    
       const long windowWidth = window.right - window.left;
       const long windowHeight = window.bottom - window.top;
    
       const long clientWidth = client.right - client.left;
       const long clientHeight = client.bottom - client.top;
    
       const long totalBorderWidth = windowWidth - clientWidth;
       long menuHeight2 = windowHeight - clientHeight;
    
       desWidth = totalBorderWidth + width;
       desHeight = (windowHeight - clientHeight) + height;
    
       SetWindowPos(hWnd, nullptr, window.left, window.top, desWidth, desHeight, SWP_NOMOVE);
    }
    
    Is there some way to calculate what the menu height will be before actually adjusting the size of the window? :\

    Or, if that's not possible, can the menu somehow be forced to stay on one row?

    Edit: I noticed Qt keeps its menu bars on one row, but I'm assuming they use custom code for that.. *sigh*
    Last edited: Aug 19, 2014
  2. NGEmu.com Advertisement

  3. @ruantec

    @ruantec Crazy GFX coder Emu Author

    Messages:
    14,528
    Likes Received:
    988
    I know the api and as long as you provide the right handle i can tell you it delivers the correct size. What i think you are doing wrong is your calculation. I may be wrong but from what i can quickly see your X and Y calculations aren't right.

    (rcWindow.right - rcWindow.left) - rcClient.right;

    this part:
    (rcWindow.right - rcWindow.left)

    is the same as rcWindow.left as the right delivers the width starting from the left to the right and the same apply for the bottom and top so you are substracting the width and height sizes.

    Basically this:
    (rcWindow.right - rcWindow.left) - rcClient.right;

    can be written as:
    rcWindow.left - rcClient.right;

    which i don't think is what you want unless i'm missing something.
    Last edited: Aug 19, 2014
  4. Dax

    Dax ライチュウ|タオ

    Messages:
    4,016
    Likes Received:
    20
    I tried a slightly different method, and I'm still having issues.

    Actually, it doesn't. If you make a Visual C++ project in VS2013, then add a menu resource with long-ish menu items, and program the window such that it'll end up being pretty small, the menu will drop down into two or more rows, as it probably should. Then if you use a menu option, or whatever method to resize the window after that, AdjustWindowRect[Ex] will return a bogus value, because it only accounts for menus with one row of items. I'll upload a demonstration project to show you (most of the menu options don't work, it's just a sample).

    No, it's not. You have to subtract right - left during CreateWindowEx to get the proper size if the menu is one row, else you'll end up with an incorrect value.

    When the menu is two rows, like it will be with a client size of 160 x 144, AWREX will not work:

    Code:
      RECT desiredClientArea = { 0 };
       desiredClientArea.left = 0;
       desiredClientArea.top = 0;
       desiredClientArea.right = 160;
       desiredClientArea.bottom = 144;
    
       AdjustWindowRectEx(&desiredClientArea, style, TRUE, 0);
    
       g_hWnd = CreateWindowEx(0, g_className.c_str(), g_windowTitle.c_str(), style, 0, 0,
                   desiredClientArea.right,
                   desiredClientArea.bottom,
                   nullptr, nullptr, g_hInstance, nullptr);
    
      if (g_hWnd == nullptr)
       {
         MessageBox(NULL, "Unable to create window.", "Error", MB_OK | MB_ICONERROR);
         return false;
       }
    
       RECT actualClientArea = { 0 };
       GetClientRect(g_hWnd, &actualClientArea);
    
       // I know this isn't secure, it's meant to be only for this demo.
       // I don't use sprintf in 99% of my coding projects.
       char buffer[4096] = { 0 };
       sprintf(buffer, "My working/client area is %d by %d pixels", actualClientArea.right, actualClientArea.bottom);
    
       MessageBox(g_hWnd, buffer, "Info", MB_OK | MB_ICONINFORMATION);
    
    If I DON'T subtract, and just pass right and bottom as the width and height respectively, I get even less: 152 by 75.
    If I do, I get back 160 x 125 due to the menu being two rows high, and subtracting correctly.

    If you don't do right - left, and bottom - top when the menu is one row, you'll get the wrong size as well. Try it yourself in my sample project. If you use the double size window without subtracting, you get 312 by 238 instead of 380 by 288, even though the menu is one row. If you do use subtracting with the double size window, it's the correct 380x288.

    Therefore, unless I'm doing something extremely wrong, I say that AdjustWindowRectEx is not reliable for projects that have the possibility of the menu occupying two or more rows, and that's why I was asking for an alternative, or a way to force the menu bar to one row, or just something. I'd rather make my little application in pure win32 than Qt, mostly because of the dependency issue.

    Edit: I think I might just stick with Qt in the end. It's not my problem if people don't want to install Qt. :p

    Attached Files:

    Last edited: Aug 19, 2014
  5. @ruantec

    @ruantec Crazy GFX coder Emu Author

    Messages:
    14,528
    Likes Received:
    988
    Hmmmm that's an interesting scenario you have there. I have to admit that i used the api in the past but never to that extent... i will check the project this weekend.
  6. Hatorijr

    Hatorijr Emu Author

    Messages:
    613
    Likes Received:
    1
    i once had a similar issue to this, give me some time to tinker with it and i might be able to come up with a solution. i remember there was some trickery with menus when i developed a set of functions to auto generate my windows/menus using correct sizes.
  7. ntkoreanstyle

    ntkoreanstyle Nội thất koreanstyle

    Messages:
    2
    Likes Received:
    0
    Why ???
    if (g_hWnd == nullptr)
    {
    MessageBox(NULL, "Unable to create window.", "Error", MB_OK | MB_ICONERROR);
    return false;
    }

Share This Page