场景
- 在使用
WTL的自定义按钮[1]时, 按钮在禁用后,接着弹出一个进度条。这时候按钮的禁用按钮并没有被绘制。显示的还是黑色矩形,怎么回事?
说明
- 在需要处理一些数据完成后才允许用户点击,这时候就需要禁用按钮。
解决的过程
- 按钮显示黑色的矩形就是它的
WM_PAINT或者WM_DRAWITEM并没有被执行。 原本重载的EnableWindow是以下写法。这里可以看出来在调用父类的EnableWindow之后,WM_PAINT并没有被执行。
BOOL BASSwitchButton::EnableWindow(BOOL bEnable)
{
status_ = (bEnable)?kButtonStatusNormal:kButtonStatusDisable;
return CWindowImpl::EnableWindow(bEnable);
}
- 改为修改按钮状态后发送绘制事件也不行,虽然没有黑色矩形框,但是按钮显示了原本的系统样式。结果还是需要在按钮启用之后鼠标移动到按钮上才会触发绘制事件。可以猜测出在调用系统的
EnableWindow时,系统按钮有自己的一套显示样式,这个样式覆盖了原本自定义的样式,所以自定义的禁用样式只是显示了一瞬。
BOOL BASSwitchButton::EnableWindow(BOOL bEnable)
{
status_ = (bEnable)?kButtonStatusNormal:kButtonStatusDisable;
Invalidate(FALSE);
UpdateWindow();
return CWindowImpl::EnableWindow(bEnable);
}
- 注意,这里只有按钮禁用操作和显示弹出进度条对话框在同一个线程才会出现按钮的绘制事件丢失的现象。应该是对话框启动时会启动自己的事件循环,而原来的事件循环里的事件丢失了,导致按钮的禁用操作并没有接着发送一次绘图事件。
正确的修改方式
- 在猜测
EnableWindow(FALSE)会显示系统禁用样式后,需要把绘制放在它之后再处理。
BOOL BASSwitchButton::EnableWindow(BOOL bEnable)
{
auto result = CWindowImpl::EnableWindow(bEnable);
status_ = (bEnable)?kButtonStatusNormal:kButtonStatusDisable;
Invalidate(FALSE);
UpdateWindow();
return result;
}
例子
- 代码使用自定义按钮1[1]里的自定义按钮类。
参考
-
自定义按钮1_infoworld的博客
-
自定义按钮2_infoworld的博客
-
NMCUSTOMDRAW (commctrl.h) - Win32 apps | Microsoft Learn