Кнопка с подклассом не воспроизводит анимацию при каждом повторном нажатии

У меня есть настраиваемая кнопка подкласса, созданная в сообщении WM_CREATE моего обратного вызова WindowProc. Вот инструкции по созданию и подклассу, а также структура, используемая для управления состоянием кнопки:

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.

Как вы можете видеть из прикрепленного рисунка, когда я многократно нажимайте кнопку стандартного класса, каждый щелчок вызывает анимацию при многократном ударе кнопка, которую я создал с этим кодом, кажется, что это не улавливает каждый щелчок, но (как видите) около 50% из них.

Что мне не хватает? Почему моя кнопка не так отзывчива, как кнопка стандартного класса?

TL; DR: при медленном нажатии на кнопку моего подкласса картина правильная. Как вы можете видеть из моего прикрепленного изображения, разница между моей и стандартной кнопкой большая при повторных нажатиях на них. Как сделать так, чтобы мой элемент управления был таким же отзывчивым, как стандартный?

Кнопка с подклассом не воспроизводит анимацию при каждом повторном нажатии

Вместо того, чтобы рисовать жестко, быстрая кнопка может иметь кешированное растровое изображение, которое она может рисовать молниеносно. Кроме того, вы тестируете отладочную или оптимизированную сборку? Не тратьте зря время на тестирование оптимизированных сборок. Вызов кнопки библиотеки будет оптимизирован для жабр, и если у вас нет, вероятно, нет справедливого сравнения.

user4581301 08.09.2018 19:38

Почему вы рисуете кнопку по индивидуальному заказу, не придавая ей стиль BS_OWNERDRAW?

Remy Lebeau 08.09.2018 19:43

Поскольку такая кнопка будет разных размеров и с различными текстами, разделяющими эту подклассовую процедуру, я не могу использовать растровые изображения. Собственное рисование и пользовательское рисование здесь также не являются возможными. Изображение, которое вы видите, взято из сценария отладки. Вы имеете в виду, что я должен протестировать релиз? Я пробовал, но, к сожалению, "отставание" все еще есть

user5752858 08.09.2018 19:47

@RemyLebeau Я делю все на подклассы. Я не использую Owner-drawing или Custom-drawing, поскольку они в основном зависят от тем Windows. Должен ли я по-прежнему использовать BS_OWNERDRAW при создании подклассов?

user5752858 08.09.2018 19:48

Приношу свои извинения за непонятность. Я не говорю о растровом файле. Нарисуйте один раз и закешируйте. Если размер объекта был изменен или изменен иным образом, вы снова рисуете и кешируете; в противном случае отобразите кеш.

user4581301 08.09.2018 19:51

@ user4581301 без проблем и большое спасибо за помощь! Вы имеете в виду, что я должен хранить растровое изображение в памяти, представляющее всю кнопку (с фоном и текстом) для каждого состояния, а затем только «вставлять» правильный из памяти при изменении состояния кнопки? Если я прав, не могли бы вы назвать некоторые функции, которые я мог бы использовать? Не нашел ссылок, погуглил

user5752858 08.09.2018 19:57

Если честно, то графики win32 не знаю. Это просто описание того, что я делал в Java Swing и играл в грязный прямоугольник на дисплеях для встраиваемых систем.

user4581301 08.09.2018 20:15

Поскольку вы не используете рисование владельцем или пользовательское рисование, система по-прежнему пытается визуализировать анимацию, которая мешает вашему собственному коду рисования. Сообщите системе, что вы этого не хотите, используя настраиваемую отрисовку (предпочтительный метод, потому что вы можете сохранить все флаги стиля окна). Пользовательское рисование нет зависит от тематики, когда вы рисуете все самостоятельно.

zett42 08.09.2018 22:09

Обработайте NM_CUSTOMDRAW (кнопка) вместо WM_PAINT. Не устанавливайте BS_OWNERDRAW, который не нужен при использовании индивидуальный розыгрыш.

zett42 08.09.2018 22:14

@ zett42 Я попробовал, и теперь эта проблема решена, но я все еще получаю анимацию, которая делает переход от одного цвета к другому при изменении состояния кнопки. Я бы хотел, чтобы вообще не было выцветания, а только изменение цвета фона. Как я могу этого добиться?

user5752858 09.09.2018 01:56
Я попробовал, и теперь проблема решена, но .... что вы на самом деле сделали, чтобы решить эту проблему? Правильно ли вы использовали NM_CUSTOMDRAW для рисования кнопки?
γηράσκω δ' αεί πολλά διδασκόμε 09.09.2018 03:39

@ user4581301: "Трудный путь", как вы это описываете, является молниеносно. Это FillRect, за которым следует DrawText. Это может быть быстрее, чем копирование внеэкранного растрового изображения.

IInspectable 09.09.2018 08:32

@ γηράσκωδ'αείπολλάδιδασκόμε да, я использовал NM_CUSTOMDRAW в WM_NOTIFY. В любом случае проблема была связана с WM_LBUTTONDBLCLK, который не был обработан. См. Принятый ответ

user5752858 09.09.2018 09:44
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
13
95
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

При быстром нажатии некоторые сообщения WM_LBUTTONDOWN заменяются на WM_LBUTTONDBLCLK (обработка двойного щелчка по умолчанию). Вам нужно обработать это так же, как вы обрабатываете сообщение WM_LBUTTONDOWN.

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

    break;
}

Вы сделали мой день! Это решило проблему без использования NM_CUSTOMDRAW.

user5752858 09.09.2018 09:49

Другие вопросы по теме