草庐IT

c++ - 使用GDI +和C++减少闪烁

coder 2023-05-31 原文

我在C++/MFC应用程序中使用GDI +,但无论何时调整窗口大小,我似乎都无法避免闪烁。

我已经尝试了以下步骤:

  • OnEraseBkGnd()上返回TRUE;
  • OnCtlColor()上返回NULL;
  • 根据此代码使用了双缓冲:

  • void vwView::OnDraw(CDC* pDC) 
    {
       CRect rcClient;
       GetClientRect(rcClient);
    
       Bitmap bmp(rcClient.Width(), rcClient.Height());
       Graphics graphics(&bmp);
    
       graphics.DrawImage(m_image, rcClient.left, rcClient.top);
    
       Graphics grph(pDC->m_hDC);
       grph.DrawImage(&bmp, 0, 0);
    }
    

    难道我做错了什么?还是有另一种方法来实现这一目标?

    最佳答案

    为了完全避免闪烁,您需要在屏幕更新之间的间隔内完成所有绘图。 Windows没有提供任何简单的方法来完成普通的窗口绘制(Vista通过DWM提供了合成图,但是即使在运行Vista的系统上也不能依靠它)。因此,最小化闪烁的最佳方法是尽快绘制所有内容(通过增加刷新周期内完成所有绘制的机会来减少撕裂),并避免过度绘制(绘制屏幕的一部分,然后再绘制其他内容)最上方:可能会向用户展示部分绘制的屏幕)。
    现在让我们讨论这里介绍的技术:

  • 不做任何事情OnEraseBkgnd():通过防止窗口的无效区域被窗口的背景色填充,有助于避免过度绘制。在无论如何都要在WM_PAINT处理期间再次绘制整个区域时(例如在双缓冲绘制的情况下)很有用...但是请参阅有关在WM_PAINT方法之后通过防止绘制来避免过度绘制的注意事项。
  • 返回OnCtlColor()的NULL :实际上,这不应做任何事情……除非您的表单上有子控件。在这种情况下,请参阅WM_PAINT方法之后的有关通过防止绘制来避免过度绘制的说明。
  • 双缓冲图形:通过将实际的屏幕图形缩减为单个BitBLT,有助于避免撕裂(以及可能过度绘制)。不过,这可能会损害绘图所需的时间:无法使用硬件加速(尽管使用GDI +,使用任何硬件辅助绘图的机会非常小),必须为每次重绘创建并填充屏幕外位图,并且每次重新绘制都必须重新绘制整个窗口。请参阅有关有效双缓冲的注释。
  • 对BitBlt使用GDI调用而不是GDI + :这通常是个好主意-Graphics::DrawImage()可能很慢。我什至发现在某些系统上,正常的GDI BitBlt() 调用速度更快。尝试一下,但只有先尝试其他一些建议后才能尝试。
  • 避免在每次调整大小时都强制完全重绘的窗口类样式(CS_VREDRAW,CS_HREDRAW):这会有所帮助,但前提是在大小更改时不需要重绘整个窗口。

  • 关于通过防止在WM_PAINT方法之前进行绘制来避免 overdraw 的注意事项
    当窗口的全部或一部分无效时,它将被擦除并重新绘制。如前所述,如果您打算重新粉刷整个无效区域,则可以跳过擦除。 但是,如果您正在使用子窗口,则必须确保父窗口不会同时擦除屏幕区域。应该在所有父窗口上设置WS_CLIPCHILDREN样式-这将防止在子窗口(包括您的 View )上绘制区域。
    关于通过在WM_PAINT方法之后防止绘制来避免 overdraw 的注意事项
    如果您的窗体上托管有任何子控件,则您将希望使用WS_CLIPCHILDREN样式来避免对其进行绘制(并随后被它们过度绘制。请注意,这会在一定程度上影响BitBlt例程的速度。
    关于高效双缓冲的注意事项
    现在,每次 View 绘制时都会创建一个新的后缓冲图像。对于较大的窗口,这可能表示分配和释放了大量内存,并且将导致严重的性能问题。我建议在 View 对象中保留一个动态分配的位图,并根据需要重新分配它以匹配 View 的大小。
    请注意,在调整窗口大小时,这将导致与当前系统一样多的分配,因为每个新大小都需要分配一个新的后缓冲区位图来匹配它-您可以通过向上舍入尺寸来减轻痛苦扩展到4、8、16等的下一个最大倍数,这样您就可以避免在每次微小更改时重新分配。
    请注意,如果自上次渲染到后缓冲区以来窗口的大小没有改变,则在窗口无效时无需重新渲染它-只需将已经渲染的图像弹出到屏幕。
    另外,分配与屏幕的位深度匹配的位图。您当前使用的Bitmap的构造函数将默认为32bpp,ARGB布局;如果与屏幕不匹配,则必须进行转换。考虑使用GDI方法 CreateCompatibleBitmap() 获得匹配的位图。
    最后...我假设您的示例代码就是这样,是一个说明性代码段。但是,如果您实际上除了在屏幕上渲染现有图像外什么也不做,那么您根本不需要维护后台缓冲区-只需直接从图像中进行Blt(并将图像格式提前转换为匹配屏幕)。

    关于c++ - 使用GDI +和C++减少闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/197948/

    有关c++ - 使用GDI +和C++减少闪烁的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

      我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

    3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    5. ruby - 在 Ruby 中使用匿名模块 - 2

      假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

    6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

      我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

    7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

      我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

    10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

      我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

    随机推荐