#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:
Если вы хотите узнать ширину, которая используется для пунктов меню, вы можете либо:
-
используйте
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; ... }
-
вышесказанное предполагает, что меню начинается со смещения 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()
возвращает координаты экрана , поэтому я преобразовывал их в координаты клиента .