65.9K
CodeProject 正在变化。 阅读更多。
Home

基于 CDialogResize 的类,无组框闪烁

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (14投票s)

2003年11月4日

4分钟阅读

viewsIcon

106438

downloadIcon

2798

去除使用可调整大小窗口时烦人的组合框闪烁;还影响可调整的最小和最大窗口大小。

引言

最近在一个项目上工作时,我碰巧使用了 WTL 的 CDialogResize 混合类,以及一个带有组合框的对话框。每当我调整对话框大小时,我都注意到组合框会出现恼人的闪烁,这极大地影响了整体的流畅效果。我在 CodeProject 和 Usenet 上搜寻解决方案,但一无所获,所以我决定自己解决这个问题。对于这样一个看似微不足道的问题,解决方案相当复杂,但最终结果是平滑无闪烁的调整大小。

使用代码

组合框的问题在于它们是(常见的)唯一可以包含其他控件的控件。因此,中间区域不会由控件本身绘制,顶部的两个区域也不会。

组合框依赖父窗口来填充这些区域,并使用默认的背景颜色。当您使用可调整大小的对话框时,CDialogResize 会强制父窗口具有 WS_CLIPCHILDREN 样式。这样做会排除父窗口的绘制区域中的所有子控件,以免背景被绘制,从而减少闪烁。在大多数情况下,这会起作用,因为子控件会覆盖其整个拥有的矩形,但在组合框的情况下,这会导致问题。通常的解决方法是为组合框设置 WS_EX_TRANSPARENT 扩展样式,这可以防止具有 WS_CLIPCHILDREN 样式的父窗口排除组合框的背景区域,从而允许背景被绘制。虽然这确实有效,但会在调整大小时产生烦人的闪烁。

我的解决方案是在后台绘制期间自行渲染组合框,并使用内存 DC 来减少闪烁。为此,我在初始化时枚举所有组合框并清除 WS_VISIBLE。这可以防止它们自行渲染。然后,我通过枚举除组合框之外的所有子控件来构建自己的有效更新区域,并用背景色填充该区域。最后,我枚举所有组合框并渲染它们,同时注意标志 BS_LEFT,BS_CENTER,BS_RIGHTBS_FLAT 的值,以确保它们以与原始控件完全相同的形式渲染。还考虑了字体度量,以确保组合框的顶部偏移量正确。在初始化时,代码会确定用户是否运行 XP 或更高版本,如果是,则渲染 XP 样式组合框(圆角、单线)。如果不是 XP,则渲染标准的方形 3D 矩形样式。

作为一些额外的奖励,我加入了在 W2000/9x 上渲染 XP 样式组合框(或在 XP 上渲染 W2000/9x 样式)的能力,通过调用 SetXPStyleGroupBoxes()。我还添加了设置最小和最大调整大小限制的能力。最小值已经存在,但默认情况下是对话框资源的当前设计大小。这可能是一个好主意,但如果您愿意,可以使用 SetMinTrackSize() 设置得更小。SetMaxTrackSize() 允许设置最大窗口大小。如果您不调用此函数,窗口可能会像平常一样最大化到全屏。

有些问题我没有解决。默认情况下,W2000/XP 在按下 ALT 键之前不会显示快捷键(例如:OK)下划线。我的替换组合框不会这样做,它们始终显示快捷键。另外,我只为普通的文本模式组合框进行了编码。我从未用过它们,但apparently 还有图标和位图组合框。那些没有被处理,所以它们应该会渲染,但会像往常一样闪烁。就我个人而言,我 15 年来从未用过这些样式。使用 MemDC 会稍微减慢调整大小的速度,因为每个 WM_ERASEBKGND 都会创建和销毁一个 MemDC。这在窗口客户区域变大时会更明显,但在我的 PC 上并不令人烦恼。对于 XP 组合框,我不知道它们是用标准的系统颜色渲染的。我使用了 COLOR_3DSHADOW,但它并不完全正确,但足够接近了。

用法与标准的 CDialogResize 混合类非常相似,只需将其替换为 CNoFlickerDialogResize。这是唯一的区别。确保在项目中包含 nfresize.h,并将 atlgdix.h (如下所述)放在包含路径中。

#include "nfresize.h"


class CMainDlg : 
    public CDialogImpl<CMainDlg>, 
    public CNoFlickerDialogResize<CMainDlg>
{

从那里开始,您将执行与使用标准 CDialogResize 相同的所有操作,设置 resize map 并在 OnInitDialog 中调用 DlgResize_Init()。Michael Dunn 有一篇关于 CDialogResize 的优秀教程文章 这里,如果您想了解用法。同样在 OnInitDialog 中,您可以根据需要调用 SetMinTrackSize() 和/或 SetMaxTrackSize()

没有实际用途,只是为了演示,但函数 DisableFlicker(bool) 设置为 false 时会将绘制恢复为正常的 Windows 默认设置,闪烁将重新出现。

演示应用

演示 zip 包 包含一个简单的应用程序,用于演示减少闪烁的整体效果。您可以打开和关闭抗闪烁,并显示 XP 样式或旧式组合框。可以更改字体以显示正确的字体处理。此对话框的最大上限尺寸为 800 x 600,因此这也得到了演示。

在此项目中,我使用了 Bjarke Viksoe 的 CMemDC 类,因此我将 atlgdix.h 包含在 zip 文件中。感谢 Bjarke 制作了这个优秀的插件。请查看他的网站以获取更多出色的内容。

© . All rights reserved.