【问题标题】:How to get the usable width of the window's main menu?如何获取窗口主菜单的可用宽度?
【发布时间】:2016-10-24 05:09:30
【问题描述】:

说,我有一个 Win32 应用程序,通过CreateWindowEx 方法将菜单添加到主窗口,我需要知道它的可用宽度。说明我要求的宽度的最佳方法是使用此图:

那么我该如何计算呢?

当我尝试执行以下操作时,它给了我客户区的宽度:

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

【问题讨论】:

  • 可用是什么意思? “可用”宽度客户区,如果需要,菜单将使用整个宽度。 GetMenuItemRect() 将为您提供特定菜单项的位置。
  • 因此,如果您想要“帮助”项的右边缘,请使用GetMenuItemRect()
  • 但是你的图片描述性不够。现在听起来您想要在不换行的情况下显示菜单所需的最小宽度?但我不确定,我不得不猜测。
  • 你的最终目标是什么?
  • 在不理解问题的情况下发布解决方案是不可能的,我没有(老实说我还不确定)。

标签: c++ windows winapi win32gui


【解决方案1】:

如果您想知道用于菜单项的宽度,您可以:

  1. 使用GetMenuItemRect() 获取最后一个菜单项的屏幕坐标,然后将它们转换为父窗口内的客户端坐标。转换后的右边缘坐标将为您提供宽度:

    HMENU hMenu = ::GetMenu(hWnd);
    int count = ::GetMenuItemCount(hMenu);
    RECT r;
    if (::GetMenuItemRect(hWnd, hMenu, count-1, &r))
    {
        ::MapWindowPoints(NULL, hWnd, (LPPOINT)&r, 2);
        int nUsedWidth = r.right;
        ...
    }
    
  2. 以上假设菜单从窗口客户区内的偏移量 0 开始。如果您不想依赖它,您可以改为获取第一个菜单项的 屏幕坐标,然后从最后一个菜单项的右边缘 屏幕坐标 中减去它菜单项:

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

无论哪种方式,如果您想知道不用于菜单项的宽度,只需获取菜单的总宽度并减去上面计算的宽度:

MENUBARINFO mbi = {0};
mbi.cbSize = sizeof(mbi);
if (::GetMenuBarInfo(hWnd, OBJID_MENU, 0, &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, &r))
    {
        ::MapWindowPoints(NULL, hWnd, (LPPOINT)&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, &rFirst))
{
    nUsedWidth = rFirst.right - rFirst.left;
    for (int idx = 1; idx < count; ++idx)
    {
        if (::GetMenuItemRect(hWnd, hMenu, idx, &r))
        {
            int nWidth = r.right - rFirst.left;
            if (nWidth > nUsedWidth)
                nUsedWidth = nWidth;
        }
    }
}
...

【讨论】:

  • 谢谢。你能解释一下你为什么在坐标上调用MapWindowPoints API 吗?
  • 因为GetMenuItemRect() 返回屏幕坐标,所以我将它们转换为客户端坐标
猜你喜欢
  • 2012-01-21
  • 2014-05-20
  • 1970-01-01
  • 1970-01-01
  • 2020-02-27
  • 2019-10-03
  • 2016-06-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多