1

所以我使用 Visual C++,并且创建了一个可拖动的无边框窗口。无论如何,顶部有一个工具栏,我希望能够通过该工具栏拖动窗口。我仍然希望工具栏能够正常工作,但我不知道如何能够通过它拖动窗口。这是我当前的窗口(参见顶部的工具栏):

窗户

这是我当前使其可拖动的代码:

case WM_NCHITTEST: {
    LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
    if(hit == HTCLIENT) hit = HTCAPTION;
    return hit;
}
break;
4

2 回答 2

1

钩住 WM_NCHITTEST,您走在了正确的轨道上。现在,您需要更改构成客户端点击与字幕点击的内容。如果我现在理解您的代码,那么您在窗口的客户区域内单击的任何位置(除了边框之外的所有内容)都将允许您将窗口拖到其他地方。这将使与您的应用程序的交互变得非常困难。相反,您应该仅在确定命中位于菜单栏区域内之后才返回 HTCAPTION。具体来说,菜单栏区域不包含文件/编辑/帮助按钮。

case WM_NCHITTEST: {
  LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
  if (hit == HTCLIENT) { // The hit was somewhere in the client area. Don't know where yet.
    // Perform your test for whether the hit was in the region you would like to intercept as a move and set hit only when it is.
    // You will have to pay particular attention to whether the user is actually clicking on File/Edit/Help and take care not to intercept this case.
    // hit = HTCAPTION;
  }
  return hit;
  break;
}

这里要记住一些事情:

  • 对于想要最小化、关闭或移动您的应用程序的用户来说,这可能会非常令人困惑。菜单栏不会向用户传达您可以通过拖动它们来移动窗口。
  • 如果您关心垂直像素,您可以考虑做 Windows 上的其他应用程序开始做的事情 - 将菜单栏功能移动到标题栏中绘制的单个按钮。(请参阅 Windows 8 中最新版本的 Firefox/Opera 或 Windows 资源管理器,了解将内容移至标题栏的一些想法。
于 2012-11-19T18:30:50.433 回答
0

在我的一个应用程序中,我还想让窗口成为​​我所说的“客户区可拖动”。不幸的是,上述解决方案(用 HTCAPTION 替换 HTCLIENT)确实存在严重缺陷:

双击客户区现在显示与双击标题相同的行为(即最小化/最大化窗口)!

为了解决这个问题,我在消息处理程序(摘录)中执行了以下操作:

        case WM_MOUSEMOVE:
            // Move window if we are dragging it
            if (mIsDragging) // variable: bool mIsDragging;
            {
                POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};

                mIsDragging = (ClientToScreen(hWnd, &mousePos) &&
                               SetWindowPos(hWnd,
                               NULL,
                               mDragOrigin.left + mousePos.x - mDragPos.x,
                               mDragOrigin.top + mousePos.y - mDragPos.y,
                               0,
                               0,
                               SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE));
            }
            break;

        case WM_LBUTTONDOWN:
            // Check if we are dragging and safe current cursor position in case
            if (wParam == MK_LBUTTON)
            {
                POINT mousePos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
                if (ClientToScreen(hWnd, &mousePos) &&
                    DragDetect(hWnd, mousePos))
                {
                    // Check if the cursor is pointing to your new caption here!!!!
                    mIsDragging = true;
                    mDragPos = mousePos;

                    GetWindowRect(hWnd, &mDragOrigin);
                    SetCapture(hWnd);
                }
            }
            break;

        // Remove this case when ESC key handling not necessary
        case WM_KEYDOWN:
            // Restore original window position if ESC is pressed and dragging active
            if (!mIsDragging || wParam != VK_ESCAPE)
            {
                break;
            }

            // ESC key AND dragging... we restore original position of window
            // and fall through to WM_LBUTTONUP as if mouse button was released
            // (i.o.w. NO break;)
            SetWindowPos(hWnd, NULL, mDragOrigin.left, mDragOrigin.top, 0, 0,
                         SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

        case WM_LBUTTONUP:
            ReleaseCapture();
            break;

        case WM_CAPTURECHANGED:
            mIsDragging = false;
    break;

(伪)代码省略了返回值(默认值:0)和变量定义,但无论如何都应该使过程清晰!?(如果不给我留言,我会添加更多或所有代码)。

ps:我刚刚找到了另一个全面的描述,它也解释了这两种解决方案的区别:http: //tinyurl.com/bqtyt3q

于 2012-12-10T21:51:29.640 回答