У меня есть настраиваемая кнопка подкласса, созданная в сообщении 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: при медленном нажатии на кнопку моего подкласса картина правильная. Как вы можете видеть из моего прикрепленного изображения, разница между моей и стандартной кнопкой большая при повторных нажатиях на них. Как сделать так, чтобы мой элемент управления был таким же отзывчивым, как стандартный?
Почему вы рисуете кнопку по индивидуальному заказу, не придавая ей стиль BS_OWNERDRAW
?
Поскольку такая кнопка будет разных размеров и с различными текстами, разделяющими эту подклассовую процедуру, я не могу использовать растровые изображения. Собственное рисование и пользовательское рисование здесь также не являются возможными. Изображение, которое вы видите, взято из сценария отладки. Вы имеете в виду, что я должен протестировать релиз? Я пробовал, но, к сожалению, "отставание" все еще есть
@RemyLebeau Я делю все на подклассы. Я не использую Owner-drawing или Custom-drawing, поскольку они в основном зависят от тем Windows. Должен ли я по-прежнему использовать BS_OWNERDRAW
при создании подклассов?
Приношу свои извинения за непонятность. Я не говорю о растровом файле. Нарисуйте один раз и закешируйте. Если размер объекта был изменен или изменен иным образом, вы снова рисуете и кешируете; в противном случае отобразите кеш.
@ user4581301 без проблем и большое спасибо за помощь! Вы имеете в виду, что я должен хранить растровое изображение в памяти, представляющее всю кнопку (с фоном и текстом) для каждого состояния, а затем только «вставлять» правильный из памяти при изменении состояния кнопки? Если я прав, не могли бы вы назвать некоторые функции, которые я мог бы использовать? Не нашел ссылок, погуглил
Если честно, то графики win32 не знаю. Это просто описание того, что я делал в Java Swing и играл в грязный прямоугольник на дисплеях для встраиваемых систем.
Поскольку вы не используете рисование владельцем или пользовательское рисование, система по-прежнему пытается визуализировать анимацию, которая мешает вашему собственному коду рисования. Сообщите системе, что вы этого не хотите, используя настраиваемую отрисовку (предпочтительный метод, потому что вы можете сохранить все флаги стиля окна). Пользовательское рисование нет зависит от тематики, когда вы рисуете все самостоятельно.
Обработайте NM_CUSTOMDRAW (кнопка) вместо WM_PAINT
. Не устанавливайте BS_OWNERDRAW
, который не нужен при использовании индивидуальный розыгрыш.
@ zett42 Я попробовал, и теперь эта проблема решена, но я все еще получаю анимацию, которая делает переход от одного цвета к другому при изменении состояния кнопки. Я бы хотел, чтобы вообще не было выцветания, а только изменение цвета фона. Как я могу этого добиться?
@ user4581301: "Трудный путь", как вы это описываете, является молниеносно. Это FillRect
, за которым следует DrawText
. Это может быть быстрее, чем копирование внеэкранного растрового изображения.
@ γηράσκωδ'αείπολλάδιδασκόμε да, я использовал NM_CUSTOMDRAW
в WM_NOTIFY
. В любом случае проблема была связана с WM_LBUTTONDBLCLK, который не был обработан. См. Принятый ответ
При быстром нажатии некоторые сообщения WM_LBUTTONDOWN
заменяются на WM_LBUTTONDBLCLK
(обработка двойного щелчка по умолчанию). Вам нужно обработать это так же, как вы обрабатываете сообщение WM_LBUTTONDOWN
.
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK: // <-- Added
{
state->pushed = true;
break;
}
Вы сделали мой день! Это решило проблему без использования NM_CUSTOMDRAW
.
Вместо того, чтобы рисовать жестко, быстрая кнопка может иметь кешированное растровое изображение, которое она может рисовать молниеносно. Кроме того, вы тестируете отладочную или оптимизированную сборку? Не тратьте зря время на тестирование оптимизированных сборок. Вызов кнопки библиотеки будет оптимизирован для жабр, и если у вас нет, вероятно, нет справедливого сравнения.