2011-05-16 111 views
7

好吧,你知道Windows Vista和Windows 7 MS如何改变手形光标(当您将鼠标悬停在超链接上时显示的手形光标),并添加了更多细节,因此它的抗锯齿性能以及边缘的光滑度和平滑度?Windows窗体应用程序中的Un-Antialiased手形光标!

那么,为什么它不是在Windows窗体应用程序?

我生病了,看着一个蹩脚的手形光标,看起来像是由穴居人绘制的,有没有一种方法可以通过编程的方式告诉它显示实际安装在系统中的光标?我查看了Windows目录下的Cursors文件夹,而旧的手形光标甚至没有在那里!那么为什么WinForms仍然使用旧版本呢?我怎样才能'升级'它?

回答

9

是的,WinForms控件仍然使用Windows 98/2000附带的旧式手形光标。它缺少Aero光标所包含的抗锯齿效果。这是因为.NET Framework包含自己的硬编码游标,而不是系统默认值。我认为这是因为早期版本的.NET针对Windows 95这样的操作系统,它并没有捆绑在这个游标上,而是没有通过考古来证明它。

幸运的是,很容易强制它使用正确的。您只需告诉操作系统您希望它使用默认的手形光标,然后无论用户运行程序的Windows版本如何,即使它们将鼠标光标从默认值更改为默认值主题。

这样做的最简单的方法是继承现有的控制,覆盖WndProc function拦截WM_SETCURSOR message,并告诉它使用的系统IDC_HAND光标。你只需要一点P/Invoke魔法。

下面的代码是如何可能看起来使用LinkLabel控制的例子:

public class LinkLabelEx : LinkLabel 
{ 
    private const int WM_SETCURSOR = 0x0020; 
    private const int IDC_HAND = 32649; 

    [DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
    private static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName); 

    [DllImport("user32.dll", CharSet=CharSet.Auto)] 
    private static extern IntPtr SetCursor(IntPtr hCursor); 

    protected override void WndProc(ref Message m) 
    { 
     if (m.Msg == WM_SETCURSOR) 
     { 
      // Set the cursor to use the system hand cursor 
      SetCursor(LoadCursor(IntPtr.Zero, IDC_HAND)); 

      // Indicate that the message has been handled 
      m.Result = IntPtr.Zero; 
      return; 
     } 

     base.WndProc(ref m); 
    } 
} 
+0

嗯。我感到震惊。吓坏了。困惑。松了一口气。那么,我应该在我的应用程序中对每个控件进行分类,以便我想要一个反锯齿的光标?这是不是有点矫枉过正? - 顺便说一句,感谢代码,它修复了它! :) – 2011-05-16 12:26:08

+0

@βӔḺṪẶⱫŌŔ:不可以。其他所有光标都完美无缺。 Windows应用程序需要显示一个手形光标非常罕见。关于唯一一次使用的是“LinkLabel”。因此,您只需创建一次自定义替换'LinkLabel'控件,然后在应用程序的任何位置使用它。 – 2011-05-16 12:27:35

+0

这就是我的意思。但我也有一个PictureBox(客户端的标志),点击它们将它们带到他们的网站,所以我也会显示手形光标以及 – 2011-05-16 12:32:26

7

请原谅我复活一个三岁的线程!

与原来的解决方案乱搞,并在reflected LinkLabel source code服用后一看,我“终于”找到这样做的一个快速又干净的方法:

using System.Runtime.InteropServices; 

namespace System.Windows.Forms { 
    public class LinkLabelEx : LinkLabel { 
     private const int IDC_HAND = 32649; 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     private static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName); 

     private static readonly Cursor SystemHandCursor = new Cursor(LoadCursor(IntPtr.Zero, IDC_HAND)); 

     protected override void OnMouseMove(MouseEventArgs e) { 
      base.OnMouseMove(e); 

      // If the base class decided to show the ugly hand cursor 
      if(OverrideCursor == Cursors.Hand) { 
       // Show the system hand cursor instead 
       OverrideCursor = SystemHandCursor; 
      } 
     } 
    } 
} 

该类实际上做我们想要的东西:它显示正确的系统手形光标不闪烁,并只在控件的LinkArea上进行。

+1

我建议每次鼠标移动时不要创建新的光标。这似乎是一个不必要的内存泄漏。相反,我会创建一个静态字段来设置静态只读游标变量,然后在需要时引用它。 – test 2015-05-20 21:16:54

+0

你说得对。不能相信我没有看到...编辑代码来修复它。 – 2015-09-04 22:11:00

+0

一个类似但更好的解决方案是设置游标以响应WM_SETCURSOR消息。这是[我的回答](http://stackoverflow.com/a/6017174/366904)的建议。没有理由对WM_MOUSEMOVE(OnMouseMove)做出响应,当有一个完美的消息专门用于此目的时,系统将只根据需要发送。 – 2016-06-02 14:01:11