【问题标题】:Win32 C++ repaint the windowWin32 C++ 重绘窗口
【发布时间】:2013-07-22 20:48:43
【问题描述】:

我已经阅读了很多关于这个主题的文章,但要么

A.我不太确定如何使用该解决方案,或者 B. 解决方案不起作用。

为了我自己的学习,我正在尝试在 C++ 窗口中制作一个可拖动的框。我最初通过LRESULT CALLBACK WndProc中的WM_PAINT消息绘制矩形:

case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);

    DrawRect(hdc, 0, 0, width, 20, RGB(60, 60, 60));

    DrawRect(hdc, boxx, boxy, boxx + 100, boxy + 20, RGB(0, 100, 255));

    EndPaint(hWnd, &ps);
    break;

我很确定我的 DrawRect 函数工作得很好,因为它确实绘制了盒子。

为了让框可以拖动,我放了一个方法,我首先定义了光标相对于窗口的点:

POINT pt;
pt.x = ((int)(short)LOWORD(lParam));
pt.y = ((int)(short)HIWORD(lParam));
ScreenToClient(hWnd, &pt);

然后,在消息 WM_LBUTTONDOWN 中:我设置了框的 x 和 y 坐标:

case WM_LBUTTONDOWN:
    boxx = pt.x;
    boxy = pt.y;
    break;

虽然这确实设置了框的 x 和 y 坐标,但我开始意识到窗口永远不会再次尝试绘制框。所以为了解决这个问题,我尝试将InvalidateRect(hWnd, 0, NULL); 添加到我的代码中,但无济于事。

所以我的问题仍然存在,如何让程序重绘或重绘窗口?

编辑:我已更改我的代码来处理WM_MOUSEMOVEWM_LBUTTONUP,如下所示:

case WM_LBUTTONDOWN:
    boxdragmode = true;
    break;
case WM_MOUSEMOVE:
    if(boxdragmode)
    {
        boxx = pt.x;
        boxy = pt.y;
    }
    break;
case WM_LBUTTONUP:
    boxdragmode = false;
    InvalidateRect(hWnd, 0, TRUE);
    break;

它仍然不更新窗口,或者它可能不更新框坐标。我通过这个得到坐标:

POINT pt;
pt.x = ((int)(short)LOWORD(lParam));
pt.y = ((int)(short)HIWORD(lParam));
ScreenToClient(hWnd, &pt);

非常感谢您的帮助

【问题讨论】:

  • 您是否也在处理WM_MOUSEMOVE,以跟踪实际拖动?和WM_LBUTTONUP 释放按钮时停止拖动? InvalidateRect 是强制重新绘制窗口的正确方法,但您需要根据正确的输入来执行此操作。
  • 不,这两个我都没有处理。我的日志是,它何时被移动或释放并不重要,如果按钮被按下,它希望它将窗口设置到该位置
  • 还是不行....
  • 您似乎只设置了一次pt 的值,来自lParam - 但响应哪条消息? lParam 仅在鼠标消息时包含鼠标坐标。每次收到 WM_LBUTTONDOWNWM_MOUSEMOVE 时,您都应该更新 pt
  • 我每次收到 a 消息时都会更新 pt。

标签: c++ winapi visual-c++ user-interface


【解决方案1】:

当我基本上使用您编写的代码尝试它时,它对我有用。不过,有几件事。目前尚不清楚您在哪里设置 POINT 值。不过,你真的不需要打扰。包括 windowsx.h 并使用 GET_X_LPARAMGET_Y_LPARAM

case WM_LBUTTONDOWN:
    boxdragmode = true;
    break;

case WM_MOUSEMOVE:
    if(boxdragmode)
    {
        boxx = GET_X_LPARAM(lParam);
        boxy = GET_Y_LPARAM(lParam);
    }
    break;

case WM_LBUTTONUP:
    boxdragmode = false;
    InvalidateRect(hWnd, 0, TRUE);
    break;

您不需要调用ScreenToClient,因为来自WM_LBUTTONDOWNWM_MOUSEMOVEWM_LBUTTONUP 消息的鼠标坐标已经在客户端坐标中。只要定义了boxdragmodeboxxboxy,以便它们在WndProc 调用之间持续存在,就可以工作。但是,因为直到WM_LBUTTONUP 才使客户区无效,所以框不会用鼠标拖动。当你放开它时它会画出来。

【讨论】:

  • 哈哈!显然,当我调用case WM_NCHITTEST: 并返回HTCAPTION 如果它在标题栏中,我应该返回HTCLIENT 否则。这引出了我的下一个问题。当我质疑WM_NCHITTEST中点击的坐标时,我不得不做ScreenToClient(hWnd, &ps)否则它不能正常工作。为什么WM_NCHITTEST 需要ScreenToClient 而其他任何消息都不需要?
  • WM_NC* 鼠标消息(如WM_NCLBUTTONDOWN)也都给出了屏幕坐标。 “NC”部分代表非客户端。在客户端坐标中提供非客户端信息没有多大意义。
  • 乔尔 - 非常感谢。这非常很有帮助。乔纳森 - 这没有帮助。
猜你喜欢
  • 1970-01-01
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-13
  • 1970-01-01
  • 2013-04-09
  • 2015-10-12
相关资源
最近更新 更多