【问题标题】:Draw Image with GDI functions使用 GDI 函数绘制图像
【发布时间】:2010-01-27 09:40:36
【问题描述】:

我在移动设备中有一个下载的图像应用程序。每次图像下载成功时,它都会自动绘制到临时位图上,然后 onPaint 方法绘制整个临时位图。这导致了很多事情发生。

每次加载一张图像时,我的导师建议我使用 GDI 函数将临时位图绘制到屏幕上。但是他的建议对于这两种方法是如此普遍。

    [DllImport("coredll.dll")]
    static extern IntPtr GetDC(IntPtr hwnd);

    [DllImport("coredll.dll")]
    static extern void ReleaseDC(IntPtr dc);

那么在这种情况下,他的建议对我有更明确的建议吗?提前致谢。

更新

    //This is my buffer bitmap
    private Graphics offGraph;
    private Bitmap offBitmap;

    //everytime an image is loaded, it raise an event and then I draw it on buffer.
    private void ImageLoadDone(object sender, EventArgs e)
    {
        ImageObj LoadedImg = (ImageObj)sender;
        LoadedImg.Render(offGraph);
        this.BeginInvoke(new EventHandler(ImageUpdate));
    }

    private void ImageUpdate(object sender, EventArgs myE)
    {
        this.Render();
    }

    //and then onPaint draw the offbitmap.
     private void Render()
    {
       CtrlGraph.DrawImage(offBitmap,0,0);
    }

【问题讨论】:

    标签: c# compact-framework gdi+


    【解决方案1】:

    是的 - 您需要进行双缓冲以防止闪烁问题,但您可以在 GDI+ 中执行此操作,而无需求助于 API。这基本上是您需要做的:

    private Bitmap backgroundBitmap;
    private Graphics backgroundGraphics;
    private Rectangle rect;
    private Rectangle srcRect;
    
    // create background bitmap the same size as your screen
    backgroundBitmap = new Bitmap(this.Width, this.Height);
    // create background buffer
    backgroundGraphics = Graphics.FromImage(backgroundBitmap);
    // get current screen graphics
    g = this.CreateGraphics();
    
    rect = new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height);
    srcRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
    
    
    Then when you receive your event and need to update the screen, call your own method:
    
    Render();
    
    private void Render()
        {            
            // draw your image onto the background buffer
            backgroundGraphics.DrawImage(bmp, rect, srcRect, GraphicsUnit.Pixel);
            // draw whatever you need to on the background graphics
        backgroundGraphics.DrawImage(.....)
    
    
            // after all images are drawn onto the background surface
            // blit back buffer to on the screen in one go
            g.DrawImage(backgroundBitmap, this.ClientRectangle,
                new Rectangle(0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height), GraphicsUnit.Pixel);
    
        }
    

    不要在尝试更新屏幕时调用 this.Refresh() 或绘制事件,因为这是导致闪烁的原因,只需在需要更新屏幕时直接调用 Render() 方法即可。 您只需在应用程序加载时首次绘制屏幕时调用 Paint 方法

    我从我的紧凑型框架游戏中获取了这段代码

    【讨论】:

    • 确保处置 IDisposable 对象。特别是位图。 blog.opennetcf.com/ctacke/…
    • 我刚刚更新了我的代码。这有很大帮助。顺便说一句,当我们想要避免闪烁时,this.CreateGraphics() 是不是最好的选择,忽略 onPaint 方法?
    • Thyphuong - 是的,忽略 onPaint 并在每次需要更新屏幕时调用 Render()... 唯一需要调用 onPaint 的时间是 a) 最初绘制屏幕 b) 如果窗口被调整大小 c) 如果另一个表单出现在它上面例如它可能在 onResize 或 onActivated 事件上被调用
    【解决方案2】:

    IIRC,如果您的标签是正确的,如果您使用的是 C#,那么您可以使用 GDI+。 GDI 来自 Win32,本质上是 WinForms 的遗留系统。

    Check this out for information on GDI+.

    而且,你描述的闪烁听起来像是没有双缓冲形式的产物。阅读here,了解如何对表单进行双重缓冲。

    【讨论】:

    • 也许我误解了你,但你的链接刚刚提到了 Graphics 中的绘图方法,这不是我需要的。我认为我想要的是我当前 Graphic 的 getDC 并用它来绘制临时位图,但不知道如何。正如我所说,我在使用 Onpaint 方法绘制之前将所有内容都绘制在一个临时位图中,所以我认为它已经具有双缓冲。
    • 双缓冲将您的位图绘制到缓冲区,而不是直接在 onPaint 期间。给文章读一读,你不会失望的。另外,我的第一点是,在使用 GDI+ 时不需要 getDC/releaseDC,而将 GDI 与 WinForms 一起使用是一个坏主意。
    猜你喜欢
    • 2021-11-09
    • 2014-01-15
    • 2022-01-17
    • 2010-09-16
    • 1970-01-01
    • 2012-03-31
    • 2011-11-10
    • 1970-01-01
    相关资源
    最近更新 更多