Я работаю над своей собственной структурой пользовательского интерфейса для настольных приложений Windows, основанной на ATL, которая должна иметь почти такой же список классов и структуру программирования, как AWT.(Я сделал почти всю предыдущую разработку GUI в WTL или WinForms, если я использую C #.)
У меня возникла проблема, когда дело доходит до класса listbox.Любой другой элемент управления может перерисовывать себя правильно без моего участия в WM_PAINT.Listbox?Не так много.Вот как это выглядит:
Поскольку я не знаю, где происходит настоящая проблема, вот весь код, который я могу придумать, который включает рисование. Если любой другой исходный код поможет, пожалуйста, дайте мне знать.
Вот мой код для обработчика WM_CTLCOLORLISTBOX:
virtual LRESULT WmCtlColorListbox(MSG& msg, bool& handled)
{
handled = true;
return colorControl(msg.message, reinterpret_cast<HDC>(msg.wParam), reinterpret_cast<HWND>(msg.lParam));
}
LRESULT colorControl(UINT origMsg, HDC hdc, HWND window)
{
if (window == *this)
{
::SetBkMode(hdc, _backMode);
::SetBkColor(hdc, _backColor);
::SetTextColor(hdc, _foreColor);
return (LRESULT) _backBrush;
}
return ::SendMessage(window, origMsg, reinterpret_cast<WPARAM>(hdc), reinterpret_cast<LPARAM>(window));
}
Обработчик WM_PAINT:
inline virtual LRESULT WmPaint(MSG& msg, bool& handled)
{
OnPaint(handled);
return handled ? 0 : 1;
}
inline virtual void OnPaint(bool& handled) { }
Обработчик WM_ERASEBKGND:
virtual LRESULT WmEraseBkgnd(MSG& msg, bool& handled)
{
HDC hdcWindow = (HDC)msg.wParam;
RECT r;
this->GetWindowRect(&r);
::FillRect(hdcWindow, &r, _backBrush);
this->Invalidate(FALSE);
handled = true;
return 1;
}
Виртуальная функция, которая вызывается непосредственно перед регистрацией ATL класса:
virtual void OnRegistering(CreationParameters& createParams)
{
createParams.BaseClassName = WC_LISTBOX;
createParams.WindowExStyles |= WS_EX_CLIENTEDGE;
}
I используется для этот код внутри OnPaint:
PAINTSTRUCT ps;
HDC hdcWindow = this->BeginPaint(&ps);
// This class automatically handles the background
// drawing for any other window
if (_backBrush == NULL)
_backBrush = ::CreateSolidBrush(_backColor);
::FillRect(hdcWindow, &ps.rcPaint, _backBrush);
this->EndPaint(&ps);
, но никакой текст не будет отображаться, предположительно, потому что WM_PAINT был вызван после того, как текст был автоматически нарисован ...
Для небольшого пояснения:
CreationParameters превращается в соответствующий CWndClassInfo, и для него вызывается Register после выхода из метода OnRegistering.
- _backMode является закрытым членом для базового класса "окна" и может либоПРОЗРАЧНЫЙ или МЯГКИЙ;в случае списка это в настоящее время жестко закодировано, чтобы быть OPAQUE
- _backColor и _foreColor являются частными членами COLORREF.
- _backBrush является частным HBRUSH, который является просто кистью _backColor и егоуничтожается при деконструкции класса управления.
Обработчик WM_PAINT просто вызывает активатор события (OnPaint), который абсолютно ничего не делает;обработчик WM_PAINT затем вызывает DefWindowProc, если обработано значение false.
Я поиграл с CS_HREDRAW и CS_VREDRAW в стилях классов перед созданием, вручную переклассифицировав WC_LISTBOX и OR в этих значениях с ужасными результатами (как втот факт, что текст, добавленный в список, не отображается, несмотря на то, что он возвращается в LB_GETCOUNT, возвращающем правильное количество элементов, а список не перерисовывается вообще ), так что я не в курсе.
Кто-нибудь видел что-то подобное раньше и, может быть, может сказать мне, что мне не хватает (или какое оконное сообщение я должен обрабатывать)?