2011-05-16 107 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