【问题标题】:Subclassed button not producing animation on every repeated click子类按钮不会在每次重复点击时产生动画
【发布时间】:2019-02-13 16:48:09
【问题描述】:

我在WindowProc 回调的WM_CREATE 消息中创建了一个自定义子类按钮。以下是创建和子类化指令,以及用于控制按钮状态的结构:

static button_state btnstateBtnInstall;
hBtnInstall = CreateWindow(WC_BUTTON, L"Button", WS_CHILD | WS_VISIBLE, (window_width / 2) - (btn_install_width / 2), window_height - (window_height / 6) - (btn_install_height / 2), btn_install_width, btn_install_height, hwnd, (HMENU)HMENU_btn_install, NULL, NULL);
SetWindowSubclass(hBtnInstall, BtnInstallProc, 0, (DWORD_PTR)&btnstateBtnInstall);

结构体定义如下:

struct button_state
{
    bool pushed;
    button_state() { pushed = false; }
};

子类过程编码如下:

LRESULT CALLBACK BtnInstallProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubClass, DWORD_PTR dwRefData)
{
    button_state* state = (button_state*)dwRefData;

    // Omitted part where I create brushes and font to be used for painting

    switch (msg)
    {
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        RECT rc = ps.rcPaint;

        POINT pt;
        GetCursorPos(&pt);
        ScreenToClient(hwnd, &pt);
        BOOL hover = PtInRect(&rc, pt);

        if (state->pushed)
        {
            // Pushed
            FillRect(hdc, &rc, hBrPushed);
        }
        else if (hover)
        {
            // Mouse over
            FillRect(hdc, &rc, hBrHover);
        }
        else
        {
            // Normal
            FillRect(hdc, &rc, hBrNormal);
        }

        SetBkMode(hdc, TRANSPARENT);
        SetTextColor(hdc, RGB(255, 255, 255));
        SelectFont(hdc, SegoeUI);
        static LPCWSTR InstallBtnTxt = L"Install";
        static int InstallBtnTxtLen = static_cast<int>(wcslen(InstallBtnTxt));  // Should be a safe cast, for small arrays like this one
        DrawText(hdc, InstallBtnTxt, InstallBtnTxtLen, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

        EndPaint(hwnd, &ps);
        return 0;
    }

    case WM_LBUTTONDOWN:
    {
        state->pushed = true;

        break;
    }

    case WM_LBUTTONUP:
    {
        state->pushed = false;

        break;
    }

    // Omitted part where I handle WM_DESTROY to do cleanup

    }

    return DefSubclassProc(hwnd, msg, wParam, lParam);
}

为了将我的按钮的行为与标准按钮的行为进行比较,我创建了另一个按钮,没有子类化并且只使用标准的BUTTON 类和WS_VISIBLE | WS_CHILD 属性。

从附加的 gif 中可以看出,当我反复点击标准类按钮时,每次点击都会产生动画,而多次点击我创建的按钮使用这段代码,它似乎没有捕捉到每一次点击,而是(如您所见)其中的 50%

我错过了什么?为什么我的按钮没有标准类附带的按钮那么灵敏?

TL;DR:当慢慢点击我的子类按钮时,绘画是正确的。正如您从我所附的图片中看到的那样,在重复点击它们时,我的按钮和标准按钮之间的差异很大。如何让我的控件与标准控件一样响应迅速?

【问题讨论】:

  • 快速按钮可能有一个缓存位图,它可以快速绘制闪电,而不是用硬方式绘制。另外,您是在测试调试版本还是优化版本?不要浪费您的时间来加速测试优化的构建。库按钮调用将针对鳃进行优化,如果您的不是,则可能没有公平的比较。
  • 为什么要自定义绘制按钮而不给它BS_OWNERDRAW 样式?
  • 我很抱歉不清楚。我不是在说位图文件。绘制一次并缓存。如果对象被调整大小或以其他方式更改,您将再次绘制并缓存;否则,显示缓存。
  • 由于你不使用自绘或自定义绘图,系统仍然会尝试渲染动画,这会干扰你自己的绘图代码。通过使用自定义绘制告诉系统您不希望这样(首选方法,因为您可以保留所有窗口样式标志)。当您自己绘制所有内容时,自定义绘制不受影响。
  • 处理 NM_CUSTOMDRAW (button) 而不是 WM_PAINT。不要设置BS_OWNERDRAW,使用自定义绘制时不需要。

标签: c++ user-interface winapi button subclass


【解决方案1】:

当您快速单击时,一些WM_LBUTTONDOWN 消息被WM_LBUTTONDBLCLK 替换(默认双击处理)。您需要像处理WM_LBUTTONDOWN 消息一样处理它。

case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK: // <-- Added
{
    state->pushed = true;

    break;
}

【讨论】:

  • 你成就了我的一天!不使用NM_CUSTOMDRAW 就解决了这个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-07
  • 1970-01-01
  • 2018-09-08
  • 1970-01-01
  • 2016-11-30
相关资源
最近更新 更多