Why the new Form dosen't stick to the mouse movement position when moving the mouse fast?

StackOverflow https://stackoverflow.com/questions/16021176

  •  04-04-2022
  •  | 
  •  

Question

I have this event:

protected override void OnMouseDown(MouseEventArgs e)
{
    mOffset = new Point(Width / 2 - e.X, Height / 2 - e.Y);
    mCurrentPoint = PointToScreen(new Point(e.X + mOffset.X, e.Y + mOffset.Y));
    mTargetPoint = mCurrentPoint;
    mTimer.Enabled = true;
}

And this event:

protected override void OnMouseMove(MouseEventArgs e)
{
    mTargetPoint = PointToScreen(new Point(e.X + mOffset.X, e.Y + mOffset.Y));
    mTimer.Enabled = true;
}

If I just move the mouse fast I'm losing the focus on the form I'm moving and the form left on place only the mouse move.

But if i click mouse down button then move the mouse and fast the form is in focus all the way.

So i tried to copy the two lines from the OnMouseDown event to the OnMouseMove event:

mOffset = new Point(Width / 2 - e.X, Height / 2 - e.Y);
mTargetPoint = mCurrentPoint;

But once I moved this two lines to the Move event nothing happen. The form is not moving at all no matter im doing.

If it's needed then this is the complete form code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Drawing.Imaging;

namespace Magnifier20070401
{
    public partial class MagnifierForm : Form
    {
        public MagnifierForm()//Configuration configuration, Point startPoint)
        {
            InitializeComponent();

            //--- My Init ---
            //mConfiguration = configuration;
            FormBorderStyle = FormBorderStyle.None;

            ShowInTaskbar = false;//mConfiguration.ShowInTaskbar;
            TopMost = true;//mConfiguration.TopMostWindow;
            Width = 150;// mConfiguration.MagnifierWidth;
            Height = 150;// mConfiguration.MagnifierHeight;

            // Make the window (the form) circular
            GraphicsPath gp = new GraphicsPath();
            gp.AddEllipse(ClientRectangle);
            Region = new Region(gp);

            mImageMagnifier = ScreenVideoRecorder.Properties.Resources.magnifierGlass;

            mTimer = new Timer();
            mTimer.Enabled = true;
            mTimer.Interval = 20;
            mTimer.Tick += new EventHandler(HandleTimer);

            mScreenImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                                     Screen.PrimaryScreen.Bounds.Height);

            mStartPoint = new Point(500, 500);// startPoint;
            mTargetPoint = new Point(500, 500); // startPoint;

            /*if (mConfiguration.ShowInTaskbar)
                ShowInTaskbar = true;
            else
                ShowInTaskbar = false;*/
        }

        protected override void OnShown(EventArgs e)
        {
            RepositionAndShow();
        }

        private delegate void RepositionAndShowDelegate();

        private void RepositionAndShow()
        {
            if (InvokeRequired)
            {
                Invoke(new RepositionAndShowDelegate(RepositionAndShow));
            }
            else
            {
                // Capture the screen image now!
                Graphics g = Graphics.FromImage(mScreenImage);
                g.CopyFromScreen(0, 0, 0, 0, new Size(mScreenImage.Width, mScreenImage.Height));
                g.Dispose();                

                //if (mConfiguration.HideMouseCursor)
                  //  Cursor.Hide();
                //else
                    Cursor = Cursors.Cross;

                Capture = true;

                /*if (mConfiguration.RememberLastPoint)
                {
                    mCurrentPoint = mLastMagnifierPosition;
                    Cursor.Position = mLastMagnifierPosition;
                    Left = (int)mCurrentPoint.X - Width / 2;
                    Top = (int)mCurrentPoint.Y - Height / 2;
                }
                else
                {*/
                    mCurrentPoint = Cursor.Position;
                //}
                Show();
            }
        }

        void HandleTimer(object sender, EventArgs e)
        {
            float dx = /*mConfiguration.SpeedFactor*/ (float)0.35 * (mTargetPoint.X - mCurrentPoint.X);
            float dy = /*mConfiguration.SpeedFactor*/ (float)0.35 * (mTargetPoint.Y - mCurrentPoint.Y);

            if (mFirstTime)
            {
                mFirstTime = false;

                mCurrentPoint.X = mTargetPoint.X;
                mCurrentPoint.Y = mTargetPoint.Y;

                Left = (int)mCurrentPoint.X - Width / 2;
                Top = (int)mCurrentPoint.Y - Height / 2;

                return;
            }

            mCurrentPoint.X += dx;
            mCurrentPoint.Y += dy;

            if (Math.Abs(dx) < 1 && Math.Abs(dy) < 1)
            {
                mTimer.Enabled = false;
            }
            else
            {
                // Update location
                Left = (int)mCurrentPoint.X - Width / 2;
                Top = (int)mCurrentPoint.Y - Height / 2;
                mLastMagnifierPosition = new Point((int)mCurrentPoint.X, (int)mCurrentPoint.Y);
            }

            Refresh();
        }


        protected override void OnMouseDown(MouseEventArgs e)
        {
            mOffset = new Point(Width / 2 - e.X, Height / 2 - e.Y);
            mCurrentPoint = PointToScreen(new Point(e.X + mOffset.X, e.Y + mOffset.Y));
            mTargetPoint = mCurrentPoint;
            mTimer.Enabled = true;
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            //if (mConfiguration.CloseOnMouseUp)
            //{
             /*   Close();
                mScreenImage.Dispose();
            //}

            Cursor.Show();
            Cursor.Position = mStartPoint;   */         
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            //if (e.Button == MouseButtons.Left)
            //{
                mOffset = new Point(Width / 2 - e.X, Height / 2 - e.Y);
                mTargetPoint = PointToScreen(new Point(e.X + mOffset.X, e.Y + mOffset.Y));
                //mTargetPoint = mCurrentPoint;
                mTimer.Enabled = true;
            //} 
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            /*if (mConfiguration.DoubleBuffered)
            {
                // Do not paint background (required for double buffering)!
            }
            else
            {
                base.OnPaintBackground(e);
            }*/
            base.OnPaintBackground(e);
        }

        protected override void  OnPaint(PaintEventArgs e)
        {
            if (mBufferImage == null)
            {
                mBufferImage = new Bitmap(Width, Height);
            }
            Graphics bufferGrf = Graphics.FromImage(mBufferImage);

            Graphics g;

            /*if (mConfiguration.DoubleBuffered)
            {
                g = bufferGrf;
            }
            else
            {*/
                g = e.Graphics;
            //}

            if (mScreenImage != null)
            {
                Rectangle dest = new Rectangle(0, 0, Width, Height);
                int w = (int)(Width / 3.0);//mConfiguration.ZoomFactor);
                int h = (int)(Height / 3.0);//mConfiguration.ZoomFactor);
                int x = Left - w / 2 + Width / 2;
                int y = Top - h / 2 + Height / 2;

                g.DrawImage(
                    mScreenImage,
                    dest,
                    x, y,
                    w, h,
                    GraphicsUnit.Pixel);
            }

            if (mImageMagnifier != null)
            {
                g.DrawImage(mImageMagnifier, 0, 0, Width, Height);
            }

           //if (mConfiguration.DoubleBuffered)
            //{
                e.Graphics.DrawImage(mBufferImage, 0, 0, Width, Height);
            //}      
        }


        //--- Data Members ---
        #region Data Members
        private Timer mTimer;
        private Configuration mConfiguration;
        private Image mImageMagnifier;
        private Image mBufferImage = null;
        private Image mScreenImage = null;
        private Point mStartPoint;
        private PointF mTargetPoint;
        private PointF mCurrentPoint;
        private Point mOffset;
        private bool mFirstTime = true;
        private static Point mLastMagnifierPosition = Cursor.Position;
        #endregion

        private void MagnifierForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode.ToString() == "M")
            {
                this.Close();
            }
        }
    }
}

In Form1 I just make a new instance for the form then I can move it. Just why it's losing focus when moving the mouse fast when not making key down on mouse?

Was it helpful?

Solution

It is not an event, it is a method. And you don't get the default behavior (capturing the mouse) because you forgot to call base.OnMouseDown(). The MSDN library warns sternly about this:

Notes to Inheritors:

When overriding OnMouseDown in a derived class, be sure to call the base class's OnMouseDown method so that registered delegates receive the event.

Well, and the other things that the base class method does. Like capturing the mouse. Only skip calling the base class method when you Really Know What You Are Doing. Which is hard to figure out, you really need to know what the base classes methods do. It is not always only as simple as firing the events. Typically the more elaborate the class, the more likely it squirreled away some code in the base method. DataGridView is the squirrel king. You can get that info from the Reference Source.

Simply add this line at the bottom of the method to solve your problem:

   base.OnMouseDown(e);

And do the same in the OnMouseMove() override. Not because that's necessary to solve this particular problem, because the docs says you should.

OTHER TIPS

In your MouseDown you should put this.Capture = true; and in your MouseUp put this.Capture.false;

If you move the mouse quickly it is probably moving outside the window, and by default only the window that the mouse is over will get the mouse messages. Using Control.Capture fixes that problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top