C#双缓冲导致涂料滞后

时间:2013-08-24 22:45:15

标签: c# performance double buffer lag

我一直在使用C#创建一个应用程序,它旨在模仿Windows的Snipping Tool应用程序的外观和行为。一切都很好,除了双缓冲(停止屏幕闪烁)显得缓慢和滞后的事实。它并没有多大的延迟,但它足以引人注意,特别是在比较我的程序和Snipping Tool之间的性能时。我还能做些什么来提高性能并让它看起来没有滞后,比如在Snipping Tool中?

    public Image Image { get; set; }

    private Rectangle selection;
    private Point startPoint;

    public static Image Snip()
    {
        using (var bmp = new Bitmap(SystemInformation.VirtualScreen.Width, SystemInformation.VirtualScreen.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb))
        {
            using (var graphics = Graphics.FromImage(bmp)) graphics.CopyFromScreen(SystemInformation.VirtualScreen.Left, SystemInformation.VirtualScreen.Top, 0, 0, bmp.Size);
            using (var snipper = new CaptureScreen(bmp, new Point(SystemInformation.VirtualScreen.Left, SystemInformation.VirtualScreen.Top)))
            {
                if (snipper.ShowDialog() == DialogResult.OK) return snipper.Image;
            }
            return null;
        }
    }

    public CaptureScreen(Image screenShot, Point startPos)
    {
        InitializeComponent();

        Cursor = Cursors.Cross;
        BackgroundImage = screenShot;
        ShowInTaskbar = false;
        FormBorderStyle = FormBorderStyle.None;
        StartPosition = FormStartPosition.Manual;
        Size = screenShot.Size;
        Location = startPos;
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left) return;
        startPoint = e.Location;
        selection = new Rectangle(e.Location, new Size(0, 0));
        Invalidate();
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left) return;
        var x1 = Math.Min(e.X, startPoint.X);
        var y1 = Math.Min(e.Y, startPoint.Y);
        var x2 = Math.Max(e.X, startPoint.X);
        var y2 = Math.Max(e.Y, startPoint.Y);
        selection = new Rectangle(x1, y1, x2 - x1, y2 - y1);
        Invalidate();
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        if (selection.Width <= 0 || selection.Height <= 0) return;
        Image = new Bitmap(selection.Width, selection.Height);
        using (var gr = Graphics.FromImage(Image))
        {
            gr.DrawImage(BackgroundImage, new Rectangle(0, 0, Image.Width, Image.Height),
                selection, GraphicsUnit.Pixel);
        }
        DialogResult = DialogResult.OK;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        using (var br = new SolidBrush(Color.FromArgb(127, Color.White)))
        {
            var x1 = selection.X;
            var x2 = selection.X + selection.Width;
            var y1 = selection.Y;
            var y2 = selection.Y + selection.Height;

            e.Graphics.FillRectangle(br, new Rectangle(0, 0, x1, Height));
            e.Graphics.FillRectangle(br, new Rectangle(x2, 0, Width - x2, Height));
            e.Graphics.FillRectangle(br, new Rectangle(x1, 0, x2 - x1, y1));
            e.Graphics.FillRectangle(br, new Rectangle(x1, y2, x2 - x1, Height - y2));
        }
        using (var pen = new Pen(Color.Red, 1))
        {
            e.Graphics.DrawRectangle(pen, selection);
        }
    }

我认为它滞后的原因是应用程序创建了一个屏幕截图并调整了捕获窗口的大小以匹配所有屏幕的尺寸。我有一种感觉,这就是Snipping Tool所做的,但它的执行速度仍然快得多。

2 个答案:

答案 0 :(得分:0)

每次进行鼠标移动时,不会使用会使控件的整个绘画区域失效的Invalidate(),从而导致更多的绘画工作......只有你才能提高效率使用指定Invalidate()的{​​{1}}使您需要更改的区域无效。

当调用Rectangle时...... OnPaint ...等同于需要更新的“脏”区域......你可以用它来优化你做的绘画工作在e.ClipRectangle

您还可以缓存红色OnPaint和白色Pen的创建,而不是每次SolidBrush发生时都创建它们......您可能会或可能看不到任何差异

以下是您的示例的更新:

OnPaint

答案 1 :(得分:0)

>>> res [['Abradolf Lincler', 32], ['Scary Terry', 20], ['Summer Smith', 20]] 使用时

Invalidate()

public async void name() { await Task.Run(() => { Invalidate(); }); } async等待完成,因此不会删除所有内容,而是实时进行绘制。