Как получить полезную ширину главного меню окна?

#c #windows #winapi #win32gui

#c #Windows #winapi #win32gui

Вопрос:

Допустим, у меня есть приложение Win32 с меню, добавленным в главное окно с помощью CreateWindowEx метода, и мне нужно знать его полезную ширину. Лучший способ проиллюстрировать ширину, о которой я прошу, с помощью этой диаграммы:

введите описание изображения здесь

Итак, как мне это рассчитать?

Когда я пытаюсь выполнить следующее, это дает мне ширину клиентской области:

 MENUBARINFO mbi = {0};
mbi.cbSize = sizeof(mbi);
if(::GetMenuBarInfo(hWnd, OBJID_MENU, 0, amp;mbi))
{
    int nUsableWifth = mbi.rcBar.right - mbi.rcBar.left;
}
  

Комментарии:

1. Что вы имеете в виду под полезной шириной? «Полезная» ширина — это клиентская область, и меню будет использовать всю ширину, если это необходимо. GetMenuItemRect() отобразит позицию определенного пункта меню.

2. Итак, если вам нужен правый край пункта «Справка», используйте GetMenuItemRect() .

3. Но ваша картинка недостаточно наглядна. Теперь звучит так, как будто вы хотите минимальную ширину, необходимую для отображения меню без переноса? Но я не уверен, мне приходится догадываться.

4. Какова ваша конечная цель?

5. Невозможно опубликовать решение, не разобравшись в вопросе, чего я не сделал (и, честно говоря, не уверен, что до сих пор понимаю).

Ответ №1:

Если вы хотите узнать ширину, которая используется для пунктов меню, вы можете либо:

  1. используйте GetMenuItemRect() , чтобы получить экранные координаты последнего пункта меню, а затем преобразовать их в координаты клиента в родительском окне. Преобразованная координата правого края даст вам ширину:

     HMENU hMenu = ::GetMenu(hWnd);
    int count = ::GetMenuItemCount(hMenu);
    RECT r;
    if (::GetMenuItemRect(hWnd, hMenu, count-1, amp;r))
    {
        ::MapWindowPoints(NULL, hWnd, (LPPOINT)amp;r, 2);
        int nUsedWidth = r.right;
        ...
    }
      
  2. вышесказанное предполагает, что меню начинается со смещения 0 в клиентской области окна. Если вы не хотите полагаться на это, вы могли бы вместо этого получить экранные координаты первого пункта меню и вычесть их из экранной координаты правого края последнего пункта меню:

     HMENU hMenu = ::GetMenu(hWnd);
    int count = ::GetMenuItemCount(hMenu);
    RECT rFirst, rLast;
    if (::GetMenuItemRect(hWnd, hMenu, 0, amp;rFirst) amp;amp;
        ::GetMenuItemRect(hWnd, hMenu, count-1, amp;rLast))
    {
        int nUsedWidth = rLast.right - rFirst.left;
        ...
    }
      

В любом случае, если вы хотите узнать ширину, которая не используется для элементов меню, просто получите общую ширину меню и вычтите указанную выше вычисленную ширину:

 MENUBARINFO mbi = {0};
mbi.cbSize = sizeof(mbi);
if (::GetMenuBarInfo(hWnd, OBJID_MENU, 0, amp;mbi))
{
    int nUsableWidth = (mbi.rcBar.right - mbi.rcBar.left) - nUsedWidth;
    ...
}
  

ОБНОВЛЕНИЕ: я не знал, что меню окна может переносить свои элементы по вертикали, если клиентская область слишком мала, чтобы отобразить их все в одной строке. В этом случае вам, возможно, придется сделать что-то более похожее на это вместо вычисления nUsedWidth :

 HMENU hMenu = ::GetMenu(hWnd);
int count = ::GetMenuItemCount(hMenu);
int nUsedWidth = 0;
RECT r;

for(int idx = 0; idx < count;   idx)
{
    if (::GetMenuItemRect(hWnd, hMenu, idx, amp;r))
    {
        ::MapWindowPoints(NULL, hWnd, (LPPOINT)amp;r, 2);
        if (r.right > nUsedWidth)
            nUsedWidth = r.right;
    }
}
...
  

Или:

 HMENU hMenu = ::GetMenu(hWnd);
int count = ::GetMenuItemCount(hMenu);
int nUsedWidth = 0;
RECT rFirst, r;

if (::GetMenuItemRect(hWnd, hMenu, 0, amp;rFirst))
{
    nUsedWidth = rFirst.right - rFirst.left;
    for (int idx = 1; idx < count;   idx)
    {
        if (::GetMenuItemRect(hWnd, hMenu, idx, amp;r))
        {
            int nWidth = r.right - rFirst.left;
            if (nWidth > nUsedWidth)
                nUsedWidth = nWidth;
        }
    }
}
...
  

Комментарии:

1. Спасибо. Можете ли вы объяснить, почему вы все же вызывали MapWindowPoints API для координат?

2. Потому что GetMenuItemRect() возвращает координаты экрана , поэтому я преобразовывал их в координаты клиента .