winforms 当前光标与this.Cursor

abithluo  于 2023-06-24  发布在  其他
关注(0)|答案(8)|浏览(129)

.Net中的Cursor.Currentthis.Cursor(其中this是WinForm)之间有什么区别吗?我一直使用this.Cursor,并且运气很好,但我最近开始使用CodeRush,只是在“等待光标”块中嵌入了一些代码,而CodeRush使用了Cursor.Current属性。我在互联网上和工作中看到其他程序员在Cursor.Current属性上遇到了一些问题。这让我想知道这两者之间是否有区别。先谢谢你了。
我做了个小测试。我有两个Winforms。我单击form1上的一个按钮,将Cursor.Current属性设置为Cursors.WaitCursor,然后显示form2。光标在两个窗体上都不会改变。它仍然是Cursors.Default(指针)光标。
如果我在form1和show form2上的按钮单击事件中将this.Cursor设置为Cursors.WaitCursor,则等待光标仅显示在form1上,默认光标在form2上,这是预期的。我不知道Cursor.Current是什么。

fv2wmkja

fv2wmkja1#

Windows向包含鼠标光标的窗口发送WM_SETCURSOR消息,使其有机会更改光标形状。像TextBox这样的控件利用了这一点,将光标更改为I栏。Control.Cursor属性确定将使用什么形状。
Cursor.Current属性直接更改形状,而不等待WM_SETCURSOR响应。在大多数情况下,这种形状不太可能长期存在。一旦用户移动鼠标,WM_SETCURSOR就会将其更改回Control.Cursor。
在. NET 2.0中添加了UseWaitCursor属性,以使显示沙漏更容易。不幸的是,它不太好用。它需要一个WM_SETCURSOR消息来更改形状,而当您将属性设置为true然后执行一些需要一段时间的操作时,这将不会发生。例如,尝试以下代码:

private void button1_Click(object sender, EventArgs e) {
  this.UseWaitCursor = true;
  System.Threading.Thread.Sleep(3000);
  this.UseWaitCursor = false;
}

光标永远不会改变。要把它塑造成形状,你需要使用光标。电流也是。这里有一个小助手类,可以让它变得简单:

using System;
using System.Windows.Forms;

public class HourGlass : IDisposable {
  public HourGlass() {
    Enabled = true;
  }
  public void Dispose() {
    Enabled = false;
  }
  public static bool Enabled {
    get { return Application.UseWaitCursor; }
    set {
      if (value == Application.UseWaitCursor) return;
      Application.UseWaitCursor = value;
      Form f = Form.ActiveForm;
      if (f != null && f.Handle != IntPtr.Zero)   // Send WM_SETCURSOR
        SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1);
    }
  }
  [System.Runtime.InteropServices.DllImport("user32.dll")]
  private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}

然后这样使用:

private void button1_Click(object sender, EventArgs e) {
  using (new HourGlass()) {
    System.Threading.Thread.Sleep(3000);
  }
}
gg0vcinb

gg0vcinb2#

我相信Cursor.Current是当前正在使用的鼠标光标(不管它在屏幕上的什么位置),而this.Cursor是当鼠标经过你的窗口时,它将被设置为的光标。

dwthyt8l

dwthyt8l3#

this.Cursor是当鼠标位于this所指的窗口上时使用的光标。Cursor.Current是当前鼠标光标,如果鼠标位于不同的窗口上,它可能与this.Cursor不同。

bgibtngc

bgibtngc4#

实际上,如果你想从另一个线程使用HourGlass,这将给予你返回一个跨线程异常,因为你试图从不同的线程访问f.Handle,而不是最初创建的表单。使用user32.dll中的GetForegroundWindow()。

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

然后

public static bool Enabled
{
    get
    {
        return Application.UseWaitCursor;
    }

    set
    {
        if (value == Application.UseWaitCursor)
        {
            return;
        }

        Application.UseWaitCursor = value;
        var handle = GetForegroundWindow();
        SendMessage(handle, 0x20, handle, (IntPtr)1);
    }
}
xdyibdwo

xdyibdwo5#

我注意到一个关于设置光标的有趣的事情,所以我想澄清一些我自己以前的误解,我希望它也能帮助其他人:
当您尝试使用
this. cursor = Cursors. Waitcursor
你实际上是为控件而不是整个窗体设置光标,因为光标是Control类的属性。
当然,只有当鼠标实际位于实际控件(明确地说是窗体的区域)上时,光标才会被更改为给定的光标
正如Hans Passant所说:
Windows向包含鼠标光标的窗口发送WM_SETCURSOR消息,使其有机会更改光标形状
我不知道Windows是否直接向控件发送消息,或者窗体是否根据鼠标位置将这些消息中继到它的子控件,我最有可能猜测第一种方法,因为当我用窗体控件的重写WndProc获取消息时,例如,当我在文本框上时,窗体没有处理任何消息。(请大家澄清一下)
基本上,我的建议是也不要使用这个. cursor,而是坚持使用这个. usewaitcursor,因为这会将所有子控件的cursor属性更改为waitcursor。
这个问题也与应用程序级Application. usewaitcursor相同,当您没有将光标移到窗体上时,Windows不会发送WM_SETCURSOR消息,因此如果您在将鼠标移到窗体区域之前启动了一个耗时的同步操作,则窗体只能在耗时的同步操作完成时处理此类消息。
(我不建议在UI线程中运行耗时的任务,主要是这就是导致这里问题的原因)
我对Hans Passant的答案做了一点改进,所以沙漏可以在应用程序级别或表单级别设置,也可以避免跨线程操作调用的InvalidOperationException:

using System;
using System.Windows.Forms;

public class HourGlass : IDisposable
{
    public static bool ApplicationEnabled
    {
        get{ return Application.UseWaitCursor; }
        set
        {
            Form activeFrom = Form.ActiveForm;
            if (activeFrom == null || ApplicationEnabled == value) return;
            if (ApplicationEnabled == value)return;
            Application.UseWaitCursor = (bool)value;

            if (activeFrom.InvokeRequired)
            {
                activeFrom.BeginInvoke(new Action(() =>
                {
                    if (activeFrom.Handle != IntPtr.Zero)
                    SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR
                }));
            }
            else
            {
                if (activeFrom.Handle != IntPtr.Zero)
                SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR
            }
        }
    }

    private Form f;

    public HourGlass() 
    {
        this.f = Form.ActiveForm;

        if (f == null)
        {
            throw new ArgumentException();
        }
        Enabled = true;
    }

    public HourGlass(bool enabled)
    {
        this.f = Form.ActiveForm;

        if (f == null)
        {
            throw new ArgumentException();
        }
        Enabled = enabled;
    }

    public HourGlass(Form f, bool enabled)
    {
        this.f = f;

        if (f == null)
        {
            throw new ArgumentException();
        }
        Enabled = enabled;
    }

    public HourGlass(Form f)
    {
        this.f = f;

        if (f == null)
        {
            throw new ArgumentException();
        }

        Enabled = true;
    }

    public void Dispose()
    {
        Enabled = false;
    }

    public bool Enabled
    {
        get { return f.UseWaitCursor; }
        set
        {
            if (f == null || Enabled == value) return;
            if (Application.UseWaitCursor == true && value == false) return;

            f.UseWaitCursor = (bool)value;

            if(f.InvokeRequired)
            {
                f.BeginInvoke(new Action(()=>
                {
                    if (f.Handle != IntPtr.Zero)
                    SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR
                }));
            }
            else
            {
                if (f.Handle != IntPtr.Zero)
                SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR
            }
        }
    }

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}

要在应用程序级别使用它:

try
{
  HourGlass.ApplicationEnabled = true;
  //time consuming synchronous task
}
finally
{
  HourGlass.ApplicationEnabled = false;
}

要在表单级别使用它,您可以对当前活动表单使用:

using (new HourGlass())
{
  //time consuming synchronous task
}

或者你可以初始化一个局部变量,格式如下:

public readonly HourGlass hourglass;

public Form1()
{
    InitializeComponent();
    hourglass = new HourGlass(this, false);
}

并在稍后的try catch finally块中使用它

n3schb8v

n3schb8v6#

当LongRunningOperation()处理消息时,这对我来说非常有效。

private void btnDoLongRunningOperation_Click(object sender, System.EventArgs e)
{
    this.Cursor = Cursors.WaitCursor;
    LongRunningOperation();
    this.Cursor = Cursors.Arrow;
}
mzmfm0qo

mzmfm0qo7#

来自VB.net VS 2012

Windows.Forms.Cursor.Current = Cursors.Default
4xy9mtcn

4xy9mtcn8#

Hans Passant的代码对我来说没有用,因为我经常在一个类中设置等待光标,然后在另一个类中重置它。
例如,用户点击按钮“连接”,显示等待光标,在后台线程中建立连接,并且当连接就绪时,光标必须重置为正常。
Hans的Hourglass类对于这种场景来说太不灵活了。此外,设置光标也不需要Windows消息。
我在一个类Utils中使用这个:

public class Utils
{
    static Form mi_WaitCursorForm;

    // i_Control may be a Control or a Form
    public static void ShowWaitCursor(Control i_Control)
    {
        // Wait cursor may still be set for another Form
        HideWaitCursor();

        Form i_Form = i_Control as Form;
        if (i_Form == null)
        {
            if (i_Control != null)
            {
                i_Form = (Form)i_Control.TopLevelControl;
            }
            else
            {
                Debug.Assert(false, "A control or Form should be specified!");
                i_Form = Form.ActiveForm;
            }
        }

        // i_Form.UseWaitCursor = true does NOT work always
        i_Form.Cursor = Cursors.WaitCursor;
        mi_WaitCursorForm = i_Form;
        Application.DoEvents();
    }

    public static void HideWaitCursor()
    {
        Form i_Form = mi_WaitCursorForm;
        if (i_Form == null)
            return;
            
        i_Form.Cursor = Cursors.Arrow;
        mi_WaitCursorForm = null;
       
        // Fix for bug in .NET framework: sometimes the wait cursor does not disappear.
        Cursor.Position = Cursor.Position;
        Application.DoEvents();
    }
}

相关问题