2013-08-24 2 views
0

Я делаю приложение на C#, которое предназначено для имитации внешнего вида и поведения приложения Windows Snipping Tool. Все в порядке, за исключением того факта, что двойная буферизация (чтобы остановить мерцание экрана) появляется медленно и лагги. Это немного отстает, но этого достаточно, чтобы быть заметным, особенно при сравнении производительности между моей программой и Snipping Tool. Что еще я могу сделать, чтобы улучшить производительность и создать впечатление, что нет отставания, например, в Snipping Tool?C# Двойная буферизация вызывает отставание от краски

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, но он все еще работает намного быстрее.

ответ

0

Вместо того, чтобы использовать Invalidate(), который аннулирует всю область рисования вашего контроля каждый раз, когда вы делаете mousemove .... и, таким образом, вы должны делать больше работ по рисованию ... вы можете быть более эффективными, только аннулируя область что вам необходимо изменить, используя Invalidate() с указанным Rectangle.

Когда OnPaint вызов ... e.ClipRectangle ... приравнивает к «грязной» зоне, нуждается в обновлении ..... вы можете использовать, чтобы оптимизировать малярные работы, которую вы делаете в OnPaint.

Вы также можете кэшировать создание вашего Red Pen и White SolidBrush вместо того, чтобы создавать их каждый раз, когда OnPaint случилось ... вы можете или не можете увидеть какая-то разница, что делать.

Вот обновление вашего примера:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace WindowsFormsApplication3 
{ 
    public partial class CaptureScreen : Form 
    { 
     public Image Image { get; set; } 

     private Rectangle selection; 
     private Rectangle previousselection; 
     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)); 
      previousselection = selection; 
      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); 
      Invalidate(previousselection); // invalidate old rect area so it gets blanked out 
      previousselection = selection; 
      selection = new Rectangle(x1, y1, x2 - x1, y2 - y1); 
      Invalidate(selection); // invalidate new rect area so it gets drawn 
     } 

     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))) 
      using (var pen = new Pen(Color.Red, 1)) 
      using (Region region = new Region(new Rectangle(0,0,Width,Height))) 
      { 
       region.Exclude(selection); 
       region.Intersect(e.ClipRectangle); 
       e.Graphics.FillRegion(br, region); 
       e.Graphics.DrawRectangle(pen, selection.X, selection.Y, selection.Width - 1, selection.Height - 1); 
      } 
     } 
    } 
} 
+0

Это, несомненно, увеличивает производительность в десятки раз. Единственное, что я замечаю сейчас, это то, что выбор начинает снова отставать, если он становится слишком большим. Я использую двойной монитор, и эффекты смутно начинают повторяться (не так уж плохо), когда я перетягиваюсь с обоих экранов. Это не так заметно, как раньше, но это определенно намного лучше. Благодаря! – Dragonphase

+0

На самом деле, поцарапайте это, я просто сравнил его с Windows Snipping tool, это практически то же самое! Еще раз спасибо! – Dragonphase

+0

См. Ревизию, в которой регион расположен с помощью функции «Использование». –

Смежные вопросы