有没有一种方法可以使用PictureBox MouseMove事件,但仍然可以在整个屏幕上移动?

时间:2019-06-11 14:05:51

标签: c# winforms

我正在向鼠标方向移动PictureBox,但是它仅在PictureBox内部起作用。 PictureBox200x200,所以它引起了一些小故障,我猜是因为空间太紧。我还有一个使PictureBox跟随鼠标的功能。在PictureBox沿鼠标方向旋转的同时,有什么方法可以使鼠标在屏幕上移动吗?

private float _angle;

private void Spiller_MouseMove(object sender, MouseEventArgs e)
{
    (float centerX, float centerY) = GetCenter(spiller.ClientRectangle);
    _angle = (float)(Math.Atan2(e.Y - centerY, e.X - centerX) * 180.0 / Math.PI);
    spiller.Invalidate();
}

private void Spiller_Paint(object sender, PaintEventArgs e)
{
    Bitmap image = Resource1.spillerr;
    float scale = (float)spiller.Width / image.Width;

    (float centerX, float centerY) = GetCenter(e.ClipRectangle);

    e.Graphics.TranslateTransform(centerX, centerY);
    e.Graphics.RotateTransform(_angle);
    e.Graphics.TranslateTransform(-centerX, -centerY);
    e.Graphics.ScaleTransform(scale, scale);
    e.Graphics.DrawImage(image, 0, 0);
}

private static (float, float) GetCenter(Rectangle rect)
{
    float centerX = (rect.Left + rect.Right) * 0.5f;
    float centerY = (rect.Top + rect.Bottom) * 0.5f;
    return (centerX, centerY);
}

2 个答案:

答案 0 :(得分:0)

您可以使用间隔很小的Timer组件(16ms〜= 60fps)来创建sudo-active图形。然后在计时器的每个滴答声中调用Invalidate

为减少不断刷新的控件的闪烁,您可能需要如下设置其样式:

class CustomPictureBox : PictureBox
{
    public CustomPictureBox() {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
    }
}

// change the type of spiller in Form1.designer.cs
private System.Windows.Forms.PictureBox spiller;
// becomes
private CustomPictureBox spiller;
// and
spiller = new System.Windows.Forms.PictureBox();
// becomes
spiller = new CustomPictureBox();

可以通过Control.MousePosition在绘画例程中获取屏幕上鼠标的全局位置。

答案 1 :(得分:0)

一种方法是使用 WH_MOUSE_LL 钩子。

我刚刚通过在VS 2015中修改示例在Windows 10上进行了测试,它工作正常,没有任何闪烁,只需要 ScreenToClient 将屏幕坐标转换为图片坐标

主要声明:

public const int WH_MIN = (-1);
public const int WH_MSGFILTER = (-1);
public const int WH_JOURNALRECORD = 0;
public const int WH_JOURNALPLAYBACK = 1;
public const int WH_KEYBOARD = 2;
public const int WH_GETMESSAGE = 3;
public const int WH_CALLWNDPROC = 4;
public const int WH_CBT = 5;
public const int WH_SYSMSGFILTER = 6;
public const int WH_MOUSE = 7;
public const int WH_HARDWARE = 8;
public const int WH_DEBUG = 9;
public const int WH_SHELL = 10;
public const int WH_FOREGROUNDIDLE = 11;
public const int WH_CALLWNDPROCRET = 12;
public const int WH_KEYBOARD_LL = 13;
public const int WH_MOUSE_LL = 14;
public const int WH_MAX = 14;
public const int WH_MINHOOK = WH_MIN;
public const int WH_MAXHOOK = WH_MAX;

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MSLLHOOKSTRUCT
{
    public System.Drawing.Point pt;
    public int mouseData;
    public int flags;
    public int time;
    public uint dwExtraInfo;
}

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct KBDLLHOOKSTRUCT
{
    public int vkCode;
    public int scanCode;
    public int flags;
    public int time;
    public uint dwExtraInfo;
}

public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);

[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);


[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int x;
    public int y;

    public POINT(int X, int Y)
    {
        this.x = X;
        this.y = Y;
    }
}

[DllImport("User32.dll", SetLastError = true)]
public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);