简体   繁体   中英

C# large delay when drawing with graphics in a froms OnPaint method from OnMouseMove

My goal is to, on a form, draw an image (screenshot) and highlight a selected area using a rubberband rectangle. I want the image to be made darker and the selcted area to be normal.
I tried to achieve this by using the mouse events to get the area that the user selected, drawing the image on the form and then using a region (for the darkening / highlighting effect) to draw an opaque black overlay over the image, except for the selected area using the following code:

class ExampleForm : Form {

    private Bitmap screenshot;
    private Rectangle r;
    private Region reg;
    private SolidBrush brush;

    public ExampleForm() {
        r = Screen.PrimaryScreen.Bounds;
        screenshot = new Bitmap(r.Width, r.Height);
        Graphics.FromImage(screenshot).CopyFromScreen(r.Left, r.Top, 0, 0, r.Size);

        SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
        FormBorderStyle = FormBorderStyle.None;
        WindowState = FormWindowState.Maximized;

        TopMost = true;
        DoubleBuffered = true;
        ShowInTaskbar = false;

        reg = new Region(r);
        brush = new SolidBrush(Color.FromArgb(200, Color.Black));
    }

    private Point startDrag, endDrag;
    private bool mouseDown;

    protected override void OnMouseDown(MouseEventArgs e) {
        mouseDown = true;
        startDrag = e.Location;
    }

    protected override void OnMouseUp(MouseEventArgs e) {
        mouseDown = false;
    }

    protected override void OnMouseMove(MouseEventArgs e) {
        if (!mouseDown) return;
        endDrag = e.Location;
        UpdatePaint();
    }

    private void UpdatePaint() {
        Rectangle window = new Rectangle(
            Math.Min(startDrag.X, endDrag.X),
            Math.Min(startDrag.Y, endDrag.Y),
            Math.Abs(startDrag.X - endDrag.X),
            Math.Abs(startDrag.Y - endDrag.Y)
            );

        reg = new Region(ClientRectangle);
        reg.Xor(window);
        Invalidate();
    }

    protected override void OnPaint(PaintEventArgs e) {
        Graphics g = e.Graphics;
        g.DrawImage(screenshot, r);
        g.FillRegion(brush, reg);
    }
}

However when doing this, there is quite a large delay between when I move the mouse and the "highlighted" area updating to the mouse location.
I have tried to do the area highlighting without the image and even just drawing a rectangle without the image and area, and there is less delay, but when compared to something like the windows explorer highlighting or lightshot (thats the functionality that i am trying to recreate) there still is so much more delay between when the mouse is moved and what is displayed in the form.
I even tried to use 2 forms: one for the image and the other one for the darkening / highlighting effect so the image doesnt have to be repainted everytime, but wasnt able to make a form transparent while having an opaque color drawn over the top.
I have also tried OnPaintBackground, using a label or imagebox instead but all have thesame delay.

So is there a much more efficient way to do the drawing and / or the highlighting effect that im using?

Building on Taw's comments, here we set the BackgroundImage of the Form to the darkened version of the screenshot, and we only draw the original (the "lightened" one, not really) version in the OnPaint() where the current selection is. I also boiled down the code to the bare minimum that you actually need to accomplish the task:

public partial class ExampleForm : Form
{

    private Point startDrag;
    private SolidBrush brush;
    private Rectangle selectionRc;
    private Bitmap originalScreenShot;

    public ExampleForm()
    {
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
        this.FormBorderStyle = FormBorderStyle.None;
        this.WindowState = FormWindowState.Maximized;

        this.TopMost = true;
        this.DoubleBuffered = true;
        this.ShowInTaskbar = false;

        this.brush = new SolidBrush(Color.FromArgb(200, Color.Black));

        Rectangle screenRc = Screen.PrimaryScreen.Bounds;
        this.originalScreenShot = new Bitmap(screenRc.Width, screenRc.Height);
        using (Graphics G = Graphics.FromImage(this.originalScreenShot))
        {
            G.CopyFromScreen(screenRc.Left, screenRc.Top, 0, 0, screenRc.Size);
        }

        Bitmap darkenedScreenshot = new Bitmap(this.originalScreenShot);
        using (Graphics G = Graphics.FromImage(darkenedScreenshot))
        {
            G.FillRectangle(this.brush, screenRc);
        }
        this.BackgroundImageLayout = ImageLayout.None;
        this.BackgroundImage = darkenedScreenshot;                       
    }        

    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.startDrag = e.Location;
        }            
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            // ... do something with "selectionRc" in here? ...
        }            
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.selectionRc = new Rectangle(
                Math.Min(this.startDrag.X, e.Location.X),
                Math.Min(this.startDrag.Y, e.Location.Y),
                Math.Abs(this.startDrag.X - e.Location.X),
                Math.Abs(this.startDrag.Y - e.Location.Y)
                );

            this.Invalidate();
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        g.DrawImage(this.originalScreenShot, this.selectionRc, this.selectionRc, GraphicsUnit.Pixel);
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM