关于用GDI+ 画图,引起的画面闪烁

jackfrank078 2012-04-11 12:43:53
问题是这样的,我做了个基于对话框的工程,在工程里我想用GDI+里的方法,用DrawImage方法在窗口背景里画了一个jpg格式的图,用来当做背景,然后对话框上面我自画了很多按钮,为了避免窗口发生局部重绘时,导致其它按钮无法显示,所以我在
OnActivate //当CWnd要被激活或退出激活状态时调用这个函数
OnActivateApp //当应用程序要被激活或退出激活状态时调用这个函数
这两个函数里,都调用了
InvalidateRect(NULL,FALSE);//在当前的更新区域中加入给定的矩形,使客户区的给定矩形无效
工程中,每一次OnAntivate和OnActiveApp的调用,画面都出现闪烁 ,用鼠标拖标题栏的时候对话框上面只有一张图片,一个按钮都没显示 ;
其实,我主要就是想实现WINDOWS桌面背景那种功能,但我的工程画面闪烁有点太明显了,不知是不是按钮太多了;
双缓冲在这里好像不能用吧?
那位有实现类似的项目源码,给我发一个,小菜在这里谢过了
...全文
485 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
rickys2080 2012-04-16
  • 打赏
  • 举报
回复
双缓冲
jackfrank078 2012-04-15
  • 打赏
  • 举报
回复
我的本意是想按照给定的更新区域大小来贴图
jackfrank078 2012-04-15
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]
主要还是你启用有计时器!
[/Quote]
这跟定时器有什么关系
jackfrank078 2012-04-14
  • 打赏
  • 举报
回复
这个是我在OnPaint函数里写的:
void CMyDlg::OnPaint()
{
TRACE1("%d:OnPaint,",tracecount);
++tracecount;
GetUpdateRect(invalirect);
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

// 使图标在工作矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
if (!invalirect.IsRectNull())
{
TRACE3("left:%d,top:%d,wight:%d,",invalirect.left,invalirect.top,invalirect.Width());
TRACE1("height:%d\n",invalirect.Height());
CClientDC dc(this);
dc.BitBlt (invalirect.left,invalirect.top,invalirect.right,invalirect.bottom,&memDC,
invalirect.left,invalirect.top,SRCCOPY); //将兼容dc的内容贴到内存dc中
invalirect.SetRectEmpty();
}
CDialog::OnPaint();
}
TRACE1("%d:OnPaintEnd,",tracecount);
++tracecount;
}
jackfrank078 2012-04-14
  • 打赏
  • 举报
回复
我又有一个问题:在主窗口上移动弹出的消息对话框或者其它弹出的对话框的时候,为什么用GetUpdateRect函数,取得的更新区域,比那个消息框还要大很多,
绿茶加咖啡 2012-04-14
  • 打赏
  • 举报
回复
主要还是你启用有计时器!
jackfrank078 2012-04-14
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 的回复:]
我按你给出的函数编了,并没闪烁,移动对话框也没被盖住按钮.你把所有的引起重绘的先去掉试试,比如Invalidate什么的.
[/Quote]
那你方不方便把你写的,给我瞧瞧,我也不知我那错了
hdg3707 2012-04-14
  • 打赏
  • 举报
回复
我按你给出的函数编了,并没闪烁,移动对话框也没被盖住按钮.你把所有的引起重绘的先去掉试试,比如Invalidate什么的.
jackfrank078 2012-04-13
  • 打赏
  • 举报
回复
jackfrank078 2012-04-13
  • 打赏
  • 举报
回复
其实我的要求并不高,只是想把一个jpg格式的图片做成背景,但不知怎么做?
jackfrank078 2012-04-13
  • 打赏
  • 举报
回复
我重载了WM_ERASEBKGND消息,把每次要擦除的背景,先补上,图我先画在兼容DC里,但是,由于每一次窗口重绘的矩形大小不一样,但从兼容DC上拷贝过来的图都是一样大的,所以每一次重绘,无效矩形外的按钮都被覆盖了,然后我用GetUpdateRect函数取得要重绘的矩形大小,再从兼容DC相对位置拷贝过来,但这种方法碰到 MessageBox弹出的消息框时,就不管用了,不移动消息对话框时,没有问题,但当我移动消息对话框时,会有一些不相关的矩形区域被图片覆盖了,移动主对话框时和主对话框被其它窗口覆盖时还是一样的问题,总会有一些不相关的矩形区域也被图片覆盖了

代码如下:
BOOL CMyDlg::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值

//return CDialog::OnEraseBkgnd(pDC);
if (!bAllUpdate)//只进入一次
{
Image bk(L"2.jpg");
CDC *pDC = GetDC();

CRect rectwindow;

GetClientRect (&rectwindow);

memDC.CreateCompatibleDC (pDC);
bitmap.CreateCompatibleBitmap (pDC,rectwindow.Width(),rectwindow.Height());
memDC.SelectObject (&bitmap);

//创建Graphics对象
Graphics graphics(memDC.m_hDC);

graphics.DrawImage( &bk,RectF(rectwindow.left,rectwindow.top,rectwindow.Width(),rectwindow.Height()));
graphics.ReleaseHDC(memDC);
ReleaseDC(pDC);
bAllUpdate=true;
}

if (GetUpdateRect(NULL)){//判断是不有要重绘的矩形区域
CRect rect;

GetUpdateRect(&rect);
CClientDC dc(this);
dc.BitBlt(rect.left,rect.top,rect.right,rect.bottom,&memDC,rect.left,rect.top,SRCCOPY); //将兼容dc对应位置的内容贴到内存dc中
}
return TRUE;
}
Santa_q 2012-04-13
  • 打赏
  • 举报
回复
重载对话框类的WM_ERASEBKGND,函数里面直接返回TRUE;
DavidHsing 2012-04-13
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]
引用 2 楼 的回复:
双缓存能用

先画图,再在图上添按钮

首先我想问一个问题,函数的流程是怎样的,是不是先执行主窗口的OnPaint,然后是每个按钮的DrawItem,那么把兼容DC的图拷备到目的DC,是在那里执行的;
步骤是不是在主窗口创建一个兼容DC,然后在主窗口的OnPaint函数中,在兼容DC上面贴图,对于按钮我重新派生了一CButton类,重载了DraoItem函数,是……
[/Quote]


画面闪烁跟你的 CButton 多不多没关系,你要绘图到窗口,就只管你的窗口的 OnPaint;
你要是觉得默认的 CButton 不满足你的要求,可以派生,自绘,来达到你的要求。同样你只管这个派生类的 OnPaint

思路跟你描述的是大体一致的,除了把你的按钮也放到兼容 DC 上。
DavidHsing 2012-04-11
  • 打赏
  • 举报
回复
这跟是不是 GdiPlus 没关系,重点是你的 OnPaint 函数要使用双缓冲绘图。
  • 打赏
  • 举报
回复
RECT rc;
GetClientRect(g_hwnd,&rc);
Bitmap bmp(int(rc.right),int(rc.bottom));、
Graphics bmpGraphics(&bmp);
bmpGraphics.SetSmoothingMode(SmoothingModeAntiAlias);
/*Drawing on bitmap*/
SolidBrush bkBrush(Color(0,0,0));
bmpGraphics.FillRectangle(&bkBrush,0,0,rc.right,rc.bottom);
/*Drawing on DC*/
Graphics graphics(hdc);
/*Important! Create a CacheBitmap object for quick drawing*/
CachedBitmap cachedBmp(&bmp,&graphics);
graphics.DrawCachedBitmap(&cachedBmp,0,0);
向立天 2012-04-11
  • 打赏
  • 举报
回复
为主窗口设置WS_CLIPCHILDREN属性
hurryboylqs 2012-04-11
  • 打赏
  • 举报
回复
就是说你要在内存中先画好再一次性拷贝到屏幕上就不闪烁了
jackfrank078 2012-04-11
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]
这跟是不是 GdiPlus 没关系,重点是你的 OnPaint 函数要使用双缓冲绘图。
[/Quote]
首先我想问一个问题,函数的流程是怎样的,是不是先执行主窗口的OnPaint,然后是每个按钮的DrawItem,那么把兼容DC的图拷备到目的DC,是在那里执行的;
步骤是不是在主窗口创建一个兼容DC,然后在主窗口的OnPaint函数中,在兼容DC上面贴图,对于按钮我重新派生了一CButton类,重载了DraoItem函数,是不是直接把所有要自绘的按钮直接画到刚才在主窗口创建的兼容DC上面,而不是主窗口的当前窗口DC上,最后是在主窗口函数OnPaint里把这个DC拷备到当前的窗口DC中,还是在那里啊,具体怎么做啊,有参考吗?
jackfrank078 2012-04-11
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]
双缓存能用

先画图,再在图上添按钮
[/Quote]
首先我想问一个问题,函数的流程是怎样的,是不是先执行主窗口的OnPaint,然后是每个按钮的DrawItem,那么把兼容DC的图拷备到目的DC,是在那里执行的;
步骤是不是在主窗口创建一个兼容DC,然后在主窗口的OnPaint函数中,在兼容DC上面贴图,对于按钮我重新派生了一CButton类,重载了DraoItem函数,是不是直接把所有要自绘的按钮直接画到刚才在主窗口创建的兼容DC上面,而不是主窗口的当前窗口DC上,最后是在主窗口函数OnPaint里把这个DC拷备到当前的窗口DC中,还是在那里啊
lgstudyvc 2012-04-11
  • 打赏
  • 举报
回复
双缓存能用

先画图,再在图上添按钮

15,979

社区成员

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

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