加载中
加载中
表情图片
评为精选
鼓励
加载中...
分享
加载中...
文件下载
加载中...
修改排序
加载中...
VC提高GDI绘图速率的方法
acmilan2015/07/18软件综合 IP:四川
GDI绘图效率不高的主要解决方法:

1.不要想着用GDI或GDI+在绘图期间(比如OnPaint)做一些耗时动作,如高斯模糊等,这样会导致界面严重闪烁!

高斯模糊等耗时操作应该进行预处理,并在绘图时简单地转化为位图映射这种迅速高效的绘图操作,而不是在每次绘图时都处理一遍。
C++
// 错误的做法 void OnPaint() {      using namespace Gdiplus;      CPaintDC dc(this);      Graphics graphics(dc);      Image myImage(L"img1.jpg");                     REAL srcWidth = (REAL)myImage.GetWidth();      REAL srcHeight = (REAL)myImage.GetHeight();      RectF srcRect(0.0f, 0.0f, srcWidth, srcHeight);      Matrix myMatrix(1.0f, 0.0f, 0.0f, 1.0f, 200.0f, 20.0f);                     BlurParams myBlurParams;      myBlurParams.expandEdge = TRUE;      myBlurParams.radius = 3;                     Blur myBlur;      myBlur.SetParameters(&myBlurParams);                     // Draw the image without the blur effect.      graphics.DrawImage(&myImage, 20.0, 20.0, srcWidth, srcHeight);                     // Draw the image with the blur effect.      graphics.DrawImage(&myImage, &srcRect, &myMatrix, &myBlur, NULL, UnitPixel); }                        // 正确的做法 void OnPaint() {     using namespace Gdiplus;     CPaintDC dc(this);     Graphics graphics(dc);     Image myImage(L"img1.jpg");                            // 画出没有模糊效果的图片     graphics.DrawImage(&myImage, 20, 20);                            static Bitmap *g_bmp = NULL;     if (g_bmp == NULL) { // 如果图片还没有被模糊处理过,那么就先处理它,否则直接显示                                  REAL srcWidth = (REAL)myImage.GetWidth();         REAL srcHeight = (REAL)myImage.GetHeight();                          BlurParams myBlurParams;         myBlurParams.expandEdge = TRUE;         myBlurParams.radius = 3;                                Blur myBlur;         myBlur.SetParameters(&myBlurParams);                                g_bmp = ::new Bitmap(srcWidth, srcHeight, &graphics);         Graphics graphics2(g_bmp);                              // 在内存位图上画出高斯模糊过的图片         graphics2.DrawImage(&myImage, NULL, NULL, &myBlur, NULL, UnitPixel);     }                            // 画出已经处理过的图片     graphics.DrawImage(g_bmp, 500, 20); }

2.如果界面仍有闪烁,那么最好把OnEraseBkgnd重写成空函数,改在OnPaint中填充背景颜色,因为消息之间可能有延时。
Other
BOOL CChildView::OnEraseBkgnd(CDC* pDC) {     // 抗闪烁 - 不自动清空背景,务必在OnPaint中清空背景,否则易出现显示不正确!     return TRUE;     // 默认 - 自动清空背景,但是在某些情况下可能会闪烁     //return CWnd::OnEraseBkgnd(pDC); }

3.在OnPaint代码中加入这个CFastDC类,实现缓冲绘图,并自动清空背景:
Other
struct CFastDC : public CDC {     CDC *m_phydc;     CBitmap m_bitmap;     CRect m_rc;                                                            CFastDC() {         m_phydc = NULL;     }                                                            CFastDC(CDC *phyDC, CRect rc, COLORREF cr = RGB(255, 255, 255)) {         m_phydc = NULL;         BeginFastDC(phyDC, rc, cr);     }                                                            ~CFastDC() {         if (m_phydc != NULL)             EndFastDC();     }                                                            CDC *BeginFastDC(CDC *phyDC, CRect rc, COLORREF cr = RGB(255, 255, 255))     {         ASSERT(m_phydc == NULL);         m_phydc = phyDC;         m_rc = rc;         CreateCompatibleDC(phyDC); // 新建兼容DC         m_bitmap.CreateCompatibleBitmap(phyDC, m_rc.right-m_rc.left, m_rc.bottom-m_rc.top);         SelectObject(m_bitmap); // 新建承载图像的兼容位图并附着在兼容DC上         FillColor(cr);         return this;     }                                                            void FillColor(COLORREF cr)     {         CRect rc2;         rc2.top = rc2.left = 0;         rc2.right = m_rc.right - m_rc.left;         rc2.bottom = m_rc.bottom - m_rc.top;         FillSolidRect(rc2, cr); // 填充背景     }                                                            BOOL EndFastDC()     {         ASSERT(m_phydc != NULL);         return m_phydc->BitBlt(m_rc.left, m_rc.top,             m_rc.right-m_rc.left, m_rc.bottom-m_rc.top,             this, 0, 0, SRCCOPY);     } };

在OnPaint中需要绘图时,首先使用GetClientRect(rc)获得窗口客户区大小,然后用CFastDC包装住实体DC(如CClientDC、CPaintDC等),即可实现缓冲绘图。
Other
void OnPaint() {     CRect rc;     GetClientRect(rc); // 获取窗口大小     CPaintDC dc(this); // 获取绘图DC     CFastDC memdc(&dc, rc, GetSysColor(COLOR_3DFACE)); // 新建一个指定背景色和大小的内存DC                                                        // TODO: 使用memdc而不是dc作图     // ...                                                        // 当CFastDC析构时,它会自动尝试将自己的图像映射到物理DC上 }

CFastDC会建立一对兼容DC/Bitmap来承载绘图结果,并在析构时将图像映射到实体DC上,经过测试,使用这种方法很大程度上可以提高绘图速率。

[修改于 10年2个月前 - 2015/07/18 19:34:16]

来自:计算机科学 / 软件综合
2
新版本公告
~~空空如也
acmilan 作者
10年2个月前 IP:四川
779697
无论是GDI、GDI+还是DirectDraw还是Direct2D,如果不注意细节的话,都非常容易闪屏。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,6年7个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的