Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/magento/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 子类按钮不在每次重复单击时生成动画_C++_User Interface_Winapi_Button_Subclass - Fatal编程技术网

C++ 子类按钮不在每次重复单击时生成动画

C++ 子类按钮不在每次重复单击时生成动画,c++,user-interface,winapi,button,subclass,C++,User Interface,Winapi,Button,Subclass,我在我的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

我在我的
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);
}
子类程序编码如下:

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);
}
LRESULT回调BtnInstallProc(HWND HWND,UINT msg,WPARAM WPARAM,LPARAM LPARAM,UINT_PTR uIdSubClass,DWORD_PTR dwRefData)
{
按钮状态*状态=(按钮状态*)dwRefData;
//省略了我创建用于绘画的画笔和字体的部分
开关(msg)
{
案例WM_油漆:
{
PAINTSTRUCT-ps;
HDC HDC=开始喷漆(hwnd和ps);
RECT rc=ps.rcPaint;
点pt;
GetCursorPos(&pt);
屏幕客户端(硬件、硬件和pt);
BOOL hover=PtInRect(&rc,pt);
如果(状态->推送)
{
//推动
FillRect(hdc和rc、hBrPushed);
}
否则如果(悬停)
{
//滑过
FillRect(hdc和rc、hBrHover);
}
其他的
{
//正常的
FillRect(hdc和rc、hBrNormal);
}
SetBkMode(hdc,透明);
SetTextColor(hdc、RGB(255、255、255));
选择字体(hdc、SegoeUI);
静态LPCWSTR InstallBtnTxt=L“安装”;
static int InstallBtnTxtLen=static_cast(wcslen(InstallBtnTxt));//对于像这样的小数组,应该是安全的强制转换
DrawText(hdc、InstallBtnTxt、InstallBtnTxtLen和rc、DT|U单线| DT|U中心| DT|U VCENTER);
端漆(hwnd和ps);
返回0;
}
案例WM_LBUTTONDOWN:
{
状态->推送=真;
打破
}
案例WM_LBUTTONUP:
{
state->push=false;
打破
}
//省略了我处理WM_DESTROY进行清理的部分
}
返回DefSubclassProc(hwnd、msg、wParam、lParam);
}
为了比较我的按钮与标准按钮的行为,我创建了另一个按钮,没有子类化,只使用标准的
按钮
类和
WS_VISIBLE | WS_CHILD
属性

从附加的gif中可以看到,当我反复点击一个标准类按钮时,每次点击都会产生动画,而当多次点击我用此代码创建的按钮时,它似乎并没有捕捉到每次点击,但(如你所见)大约有50%的点击

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

TL;DR:当缓慢单击我的子类按钮时,绘画是正确的。正如你可以从我的附加图像中看到的那样,我的按钮和标准按钮之间的差异在重复点击它们时是巨大的。我如何使我的控制像标准控制一样灵敏


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

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

    break;
}
案例WM\u LBUTTONDOWN:
案例WM_lbuttondblck://push=true;
打破
}

快速按钮可能有一个缓存的位图,它可以以闪电般的速度绘制,而不是艰难地绘制。另外,您是在测试调试版本还是优化版本?不要浪费时间快速测试优化的构建。库按钮调用将根据gills进行优化,如果您的没有优化,则可能没有公平的比较。为什么您自定义绘制按钮而不提供
BS_OWNERDRAW
样式?对于不清楚,我深表歉意。我不是说位图文件。绘制一次并缓存。如果对象被调整大小或以其他方式更改,则重新绘制并缓存;否则,显示缓存。由于您不使用所有者绘制或自定义绘制,系统仍会尝试渲染动画,这会干扰您自己的绘制代码。通过使用自定义绘图(首选方法,因为您可以保留所有窗口样式标志),告诉系统您不希望这样做。当您自己绘制所有内容时,自定义绘制不受主题化的影响。使用Handle而不是
WM_PAINT
。不要设置
BS_OWNERDRAW
,这在使用自定义绘图时是不需要的。你让我开心了!这解决了问题,无需使用
NM\u CUSTOMDRAW