关于窗口缩放时刷新的问题

psbeond 2004-12-28 01:03:49
我在一个支持缩放的对话框CTestDlg中创建了一个派生自CWnd的窗口CThumbnailView(class CThumbnailView: public CWnd,变量为CThumbnailView m_view;),在CThumbnailView的OnPaint中绘制了一些东西,在CTestDlg的OnSizing中使用MoveWindow使CThumbnailView跟首对话框一些缩放。
void CTestDlg::OnSizing(UINT fwSide, LPRECT pRect)
{
CDialog::OnSizing(fwSide, pRect);

// TODO: Add your message handler code here
CRect rcClient;
GetClientRect( &rcClient );

CRect rcView;
rcView = rcClient;
rcView.right -= 50;
rcView.bottom -= 50;
m_view.MoveWindow( rcClient );
}
但在缩放时,CThumbnailView闪的厉害,我用CListCtrl测试后,发现CListCtrl跟着对话框缩放时不会闪,我把
m_view.MoveWindow( rcClient );
改成下面的
m_view.MoveWindow( rcClient, FALSE );
RedrawWindow( rcClient, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN );
,虽然不闪了,但这是在CTestDlg中设置的,我想使我的CThumbnailView直接就支持缩放时不闪的特性。请大家支人招。
...全文
544 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
wjlsmail 2005-03-02
  • 打赏
  • 举报
回复
Mark
psbeond 2005-01-01
  • 打赏
  • 举报
回复
解决了,就是在我的ThumbnailView的WindowPosChanging时把父窗口的属性设为WS_CLIPCHILDREN,在WindowPosChanged时把属性设回去。
fanqing 2004-12-31
  • 打赏
  • 举报
回复
解决Windows 程序界面闪烁问题的一些经验
一般的windows 复杂的界面需要使用多层窗口而且要用贴图来美化,所以不可避免在窗口移动或者改变大小的时候出现闪烁。

先来谈谈闪烁产生的原因

原因一:
如果熟悉显卡原理的话,调用GDI函数向屏幕输出的时候并不是立刻就显示在屏幕
上只是写到了显存里,而显卡每隔一段时间把显存的内容输出到屏幕上,这就是刷新周期。

一般显卡的刷新周期是 1/80秒左右,具体数字可以自己设置的。

这样问题就来了,一般画图都是先画背景色,然后再把内容画上去,如果这两次操作不在同一个
刷新周期内完成,那么给人的视觉感受就是,先看到只有背景色的图像,然后看到画上内容的图像,
这样就会感觉闪烁了。

解决方法:尽量快的输出图像,使输出在一个刷新周期内完成,如果输出内容很多比较慢,那么采用
内存缓冲的方法,先把要输出的内容在内存准备好,然后一次输出到显存。要知道一次API调用一般可以
在一个刷新周期内完成。

对于GDI,用创建内存DC的方法就可以了

原因二:

复杂的界面有多层窗口组成,当windows在窗口改变大小的时候是先重画父窗口,然后重画子窗口,子父
窗口重画的过程一般无法在一个刷新周期内完成,所以会呈现闪烁。

我们知道父窗口上被子窗口挡住的部分其实没必要重画的

解决方法:给窗口加个风格 WS_CLIPCHILDREN ,这样父窗口上被子窗口挡住的部分就不会重画了。

如果同级窗口之间有重叠,那么需要再加上 WS_CLIPSIBLINGS 风格

原因三:

有时候需要在窗口上使用一些控件,比如IE,当你的窗口改变大小的时候IE会闪烁,即使你有了WS_CLIPCHILDREN
也没用。原因在于窗口的类风格有CS_HREDRAW 或者 CS_VREDRAW,这两个风格表示窗口在宽度或者高度变化的时候
重画,但是这样就会引起IE闪烁

解决方法:注册窗口类的时候不要使用这两个风格,如果窗口需要在改变大小的时候重画,那么可以在WM_SIZE的时候
调用RedrawWindow。

原因四:

界面上窗口很多,而且改变大小时很多窗口都要移动和改变大小,如果使用MoveWindow或者SetWindowPos两个API来
改变窗口的大小和位置,由于他们是等待窗口重画完成后才返回,所以过程很慢,这样视觉效果就可能会闪烁。

解决方法:

使用以下API来处理窗口移动,BeginDeferWindowPos, DeferWindowPos,EndDeferWindowPos
先调用 BeginDeferWindowPos 设定需要移动的窗口的个数
使用DeferWindowPos,来移动窗口,这个API并不真的造成窗口移动
EndDeferWindowPos 一次性完成所有窗口的大小和位置的改变。

有个地方要特别注意,要仔细计算清楚要移动多少个窗口,BeginDeferWindowPos设定
的个数一定要和实际的个数一致,否则在Win9x下,如果实际移动的窗口数多于调用BeginDeferWindowPos
时设定的个数,可能会造成系统崩溃。在Windows NT系列下不会有这样的问题。

psbeond 2004-12-31
  • 打赏
  • 举报
回复
再up
psbeond 2004-12-30
  • 打赏
  • 举报
回复
自已up一下,100分只给回答正确的一个人。
psbeond 2004-12-30
  • 打赏
  • 举报
回复
我不只是在缩放完后重画,我要在缩放过程中也重画,大家打开“我的电脑”选“查看-缩略图”,然后缩放一下窗口看看就知道什么意思了
Auto_And_Elec 2004-12-30
  • 打赏
  • 举报
回复
在WM_SIZE消息中重画肯定会闪烁,你想办法在最后一个WM_SIZE消息画或者避开WM_SIZE消息
psbeond 2004-12-29
  • 打赏
  • 举报
回复
to hyamw:
OnEraseBkgnd()里面不要调用原来的OnEraseBkgnd();直接返回TRUE(忘了是TRUE还是FALSE了,好像应该是TRUE)。
====这早就试过了,问题不在这儿。

如果还不行。尝试一下这样:在拖动的过程中,并不真正的改变窗口的大小,只是绘制出窗口的边框矩形,只有停止拖动的时候才重新刷新窗口。
====治标不治本,我要在缩放时改变Thumbnail的排列


再有就是看看双缓冲看能不能行
====已经使用双缓存了,做这样的窗口不可能不使用的。
psbeond 2004-12-29
  • 打赏
  • 举报
回复
我准备在CThumbnailView中写一个MoveWindow函数,让外面调用我的MoveWindow,但这有点假
guangsan 2004-12-29
  • 打赏
  • 举报
回复
既然clistview不闪,干吗非要从cwnd继承,直接从clistview继承一个不就完了。
hyamw 2004-12-29
  • 打赏
  • 举报
回复
OnEraseBkgnd()里面不要调用原来的OnEraseBkgnd();直接返回TRUE(忘了是TRUE还是FALSE了,好像应该是TRUE)。
如果还不行。尝试一下这样:在拖动的过程中,并不真正的改变窗口的大小,只是绘制出窗口的边框矩形,只有停止拖动的时候才重新刷新窗口。
再有就是看看双缓冲看能不能行
  • 打赏
  • 举报
回复
源代码也可以给我一份: ukyo_wlp@163.com
aoosang 2004-12-29
  • 打赏
  • 举报
回复
不闪是不可能的,因为你每次拖动都会引发onpaint,相关的方法我也一直没有想到,
psbeond 2004-12-28
  • 打赏
  • 举报
回复
全不行,首先:OnEraseBkgnd返回的是BOOL值,最后:问题不在这儿。
老夏Max 2004-12-28
  • 打赏
  • 举报
回复
CThumbnailView?相册?查看图片?呵呵
如果可以的话,可以将程序源代码发到:xia_qingqi@broadxent.com.cn
我帮你看看!注明帖子的URL!
张佩 2004-12-28
  • 打赏
  • 举报
回复
什么都不作不行的,应当是返回值改为NULL(原来返回的是pDC),OnPaint根据返回的DC来重绘的,当返回NULL时,它对空区域进行重绘。
张佩 2004-12-28
  • 打赏
  • 举报
回复
楼上是说:OnEraseBkGnd()
I_Love_CPP 2004-12-28
  • 打赏
  • 举报
回复
重载CThumbnailView重绘背景的响应函数,让它什么都不做(其实就是不让它自动重绘背景);
然后,在需要的时候用Invalidate触发WM_PAINT的响应函数OnDraw().


15,978

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧