【发布时间】:2012-02-08 19:15:18
【问题描述】:
我正在开发我自己的基于 ATL 的私有 Windows 桌面应用程序用户界面框架,它应该具有与 AWT 几乎相同的类列表和编程结构。 (如果我使用 C#,我几乎在 WTL 或 WinForms 中完成了所有以前的 GUI 开发。)
我遇到了列表框类的问题。在我不参与 WM_PAINT 的情况下,所有其他控件都能够正确地重新绘制自己。列表框?没那么多。下面是它的外观:
由于我不知道实际问题出在哪里,这里是我能想到的所有涉及绘图的代码。 如果有任何其他源代码有帮助,请告诉我。
这是我的 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;
}
我曾经在 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 并在 OnRegistering 方法退出后对其调用 Register。
- _backMode 是基本“窗口”类的私有成员,并且是透明的或不透明的;在列表框的情况下,它目前被硬编码为不透明
- _backColor 和 _foreColor 是私有 COLORREF 成员。
- _backBrush 是一个私有 HBRUSH,它只是一个 _backColor 的画笔,并在解构控件类时销毁。
WM_PAINT 处理程序只是调用一个事件激活器(OnPaint),它完全不做任何事情; WM_PAINT 处理程序然后在处理为 false 时调用 DefWindowProc。
在创建之前,我在类样式上玩弄了 CS_HREDRAW 和 CS_VREDRAW,方法是手动对 WC_LISTBOX 进行超类化并在这些值中进行 OR'ing,但结果很糟糕(事实上,添加到列表框中的文本不会出现,尽管返回LB_GETCOUNT 返回正确数量的项目并且列表框不会重绘根本)所以我没有想法。
以前有没有人见过这样的事情,也许可以告诉我我错过了什么(或者我应该处理什么窗口消息)?
【问题讨论】:
-
在这里在黑暗中摸索,但我记得在尝试用 NULL_BRUSH 填充编辑框时看起来相似的背景。也许 CreateSolidBrush 在某处返回 NULL。另外,为什么要验证 WM_ERASEBACKGROUND 上的窗口?
-
解决了部分问题... _backBrush 仅检查 NULL 当且仅当 _backColor 被分配给不同于它已经设置的东西...我解决了这个问题,这就是现在的样子:i.imgur.com/ix1gM.png
-
@pezcode:
NULL_BRUSH不等同于NULL。 -
不管怎样,每次发送 WM_ERASEBKGND 时 _backBrush 都是 0,因此有助于缩小范围。