WM_PAINT с PROGRESS_CLASS

Я создаю элемент управления Win32:

m_progress = CreateWindowExW(0, PROGRESS_CLASSW, L"ProgressBar", WS_VISIBLE | WS_CHILD | WS_TABSTOP, 153, 339, 135, 33, m_window, (HMENU)0, m_instance, 0);
SendMessageW(m_progress, WM_SETFONT, (WPARAM)m_fontBold, TRUE);
SendMessageW(m_progress, PBM_SETRANGE, 0, MAKELPARAM(0, 100));

Это работает, но я также хочу рисовать текст с процентами на нем. Поэтому я создал подкласс управления прогрессом следующим образом:

m_progressPrevProc = (WNDPROC)SetWindowLongPtrW(m_progress, GWLP_WNDPROC, (LONG_PTR)ProgressMsgProcessor);
...
static LRESULT CALLBACK ProgressMsgProcessor(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    if (msg == WM_PAINT)
    {
        PAINTSTRUCT ps;
        RECT rc = { 5, 5, 135, 33 };
        //HDC hdc = BeginPaint(hwnd, &ps);
        //SelectObject(hdc, g_App.m_fontBold);
        //DrawTextA(hdc, "100 %", -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
        //EndPaint(hwnd, &ps);
    }

    return CallWindowProcW((WNDPROC)PrevWndProcProzess, hwnd, msg, wparam, lparam);
}

Но если раскомментировать хотя бы "HDC hdc = BeginPaint(hwnd, &ps);" затем появляется текст, но элемент управления по умолчанию полностью исчезает (как будто он не нарисован). Как я могу исправить это, чтобы отображать элемент управления окнами по умолчанию с текстом на нем, потому что мне не нужно рисовать настраиваемый элемент управления, только добавить наложенный текст? Спасибо


person Stormgate Studio    schedule 31.05.2018    source источник
comment
Кто-то назвал BeginPaint()/EndPaint() грязный регион проверенным, и повторный вызов вернет пустой регион. Правильный способ сделать это — сначала вызвать CallWindowProc, чтобы позволить элементу управления выполнить отрисовку по умолчанию, а затем вызвать GetDC() / ReleaseDC(), чтобы получить DC для рисования поверх.   -  person Jonathan Potter    schedule 31.05.2018
comment
@JonathanPotter Ах, побей меня, только что заметил.   -  person Paul Sanders    schedule 31.05.2018


Ответы (1)


Проблема здесь в том, что вы очистили область обновления своими вызовами BeginPaint и EndPaint, поэтому индикатор выполнения не думает, что должен что-то рисовать. Слабость способа работы WM_PAINT заключается в том, что вы не можете таким образом закрасить существующий элемент управления. Вместо этого вы должны сделать что-то вроде этого:

static LRESULT CALLBACK ProgressMsgProcessor(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    if (msg == WM_PAINT)
    {
        // Paint the control first
        CallWindowProcW ((WNDPROC)PrevWndProcProzess, hwnd, msg, wparam, lparam);

        // Then draw over it
        HDC hDC = GetDC (hwnd);
        HFONT hOldFont = (HFONT) SelectObject(hDC, g_App.m_fontBold);

        // Draw your own stuff into hDC

        SelectObject (hDC, hOldFont);
        ReleaseDC (hwnd, hDC);
        return 0;
    }

    return CallWindowProcW ((WNDPROC)PrevWndProcProgress, hwnd, msg, wparam, lparam);
}

Другие примечания:

  • Ваш код в том виде, в котором он опубликован, рисуется под контролем, а не над ним (!). Мой код исправляет это.
  • Если вы выберете и возразите в DC, вам следует снова выбрать старый, когда вы закончите. Опять же, мой код показывает, как это сделать.
person Paul Sanders    schedule 31.05.2018
comment
Просто придирка, но в этом примере вам не нужно вызывать CallWindowProcW() условно. Я бы переместил его над оператором if и сохранил возвращаемое значение в локальную переменную, а затем return эту переменную после завершения блока if, например: LRESULT lRes = CallWindowProcW((WNDPROC)PrevWndProcProzess, hwnd, msg, wparam, lparam); if (msg == WM_PAINT) { ... } return lRes; - person Remy Lebeau; 31.05.2018
comment
@RemyLebeau Да, здесь это было бы лучше, но (а) я в первую очередь стремился к ясности, и (б) в более общем случае вызов CallWindowProc перед выполнением чего-либо еще может не работать для всех типов сообщений, которые ProgressMsgProcessor хочет обработать (или возможно, в будущем захочется обращаться). - person Paul Sanders; 31.05.2018
comment
Это отличное решение, большое спасибо. Я наткнулся на это довольно давно. Теперь единственной проблемой остается то, что текст перерисовывается каждый раз, когда вы рисуете, по какой-то причине предыдущий текст всегда остается там. - person Norbert Boros; 20.04.2021