所謂“可拖動窗體”就是無需拖動標題欄就可以拖動的窗體,這在一個沒有標題欄的窗體上是一種非常有用的技術。關於這一方面的技巧,網上已經有很多介紹,但都不是很詳盡,有些實現也不夠簡潔。最主要的,這些介紹大多是大片大片的源代碼,很少講解;初學者學期來恐怕要費些力氣(我在學習這個技巧的時候就很痛苦)。在這裡,我對這個技巧進行了一個詳細的講解,相信各位初學者朋友可以學會如何制作可拖動窗體。
(注:本文期望的讀者是那些有一定用C#開發Windows程序基礎但暫時還不會制作可拖動窗體的朋友。)
首先,我們來復習一下一個Windows窗體的組成。請看這張圖:
圖1 Windows窗體構成
這是一個形式化的標准Windows窗體。首先,窗體的頂部是一個標題欄,其余的部分是窗體的主體,包圍在窗體主體外圍的是一個邊框,邊框內不就是我們放置控件或繪制圖形的用戶區。
圖中還標明了各種窗體構造元素的尺寸的獲得方法。對於用戶區,System.Windows.Forms.Form提供了實例屬性ClientSize,相信大家已經很熟悉了。而要想活棋一般性的窗體構造元素(如標題欄、邊框等)的尺寸,我們可以使用.NET類庫中提供的一個類:System.Windows.Forms.SystemInformation,這個類提供了一些靜態屬性如表示標題欄高度的CaptionHeight。有關SystemInformation類的信息可以在.NET SDK文檔目錄“.NET Framework SDK -> 參考 -> 類庫 -> System.Windows.Forms -> SystemInformation 類”處找到(注:這裡的超鏈接只在您安裝了.NET Framework 1.1簡體中文版並且安裝了配套文檔時才有效)。這是一個很有用的類,希望大家能夠記住它(可能您早就知道了,可我是才知道的-_-汗~~)。
接下來,我們來看看如何在在用戶區拖動鼠標時移動窗體。請看下面這張圖:
圖2 窗體的移動
我們來觀察鼠標在窗體內的位置和窗體的移動,很容易可以發現:在窗體被拖動的過程中,鼠標在窗體內的相對位置是始終不變的!那麼,我們只要檢測到鼠標在屏幕中的移動並修改窗體的位置就可以達到拖動窗體的目的!
我們知道,在鼠標消息/事件處理中,只能得到鼠標相對於窗體的位置。那麼,如何知道鼠標在屏幕中的位置呢?這裡又要提到一個類:System.Windows.Forms.Control類。也許你會很吃驚:這不是所有控件的基類麼?呵呵~是這樣di。不過,盡管是這樣,Control類卻沒有像其他廣泛使用的基類那樣被聲明為抽象類,而且它提供了一個靜態屬性:MousePosition,通過這個屬性可以得到鼠標相對於屏幕的位置。有關Control類的信息可以在.NET Framework文檔目錄“.NET Framework SDK -> 參考 -> 類庫 -> System.Windows.Forms -> Control 類”處找到(注:這裡的超鏈接只在您安裝了.NET Framework 1.1簡體中文版並且安裝了配套文檔時才有效)。
知道了如何獲取這些信息之後,制作移動窗體實際上就成了一個很簡單的問題了。基本過程是這樣的:首先,在鼠標(左鍵或一個你喜歡的鍵)按下時,// 示例代碼1
Form.Top = Control.MousePosition.Y - mousePosition.Y;
Form.Left = Control.MousePosition.X - mousePosition.X;
這樣還不行,因為我們的mousePosition表示的是鼠標在窗體用戶區內的相對坐標,但在移動窗體的時候還要考慮窗體標題欄和邊框的尺寸。在上面的基礎上,我們將代碼修正為:
// 示例代碼2
Form.Top = Control.MousePosition.Y - mousePosition.Y
- SystemInformation.FrameBorderSize.Height - SystemInformation.CaptionHeight;
Form.Left = Control.MousePosition.Y - mousePosition.Y
- SystemInformation.FrameBorderSize.Width;
也就是說,在高度上(縱坐標)要減去標題欄的高度和邊框的高度,而在寬度上(橫坐標)要減去邊框的寬度。然而,當制作一個既沒有標題欄也沒有邊框的可拖動窗體時,使用“示例代碼1”所示的代碼就可以了。
上面的代碼只是一個示范性代碼。具體的操作如下:
首先,為窗體添加一個私有域:
private System.Drawing.Point mousePoint;
然後,為窗體添加鼠標按下事件處理方法(我這裡是MainForm_MouseDown,別忘了將該方法鏈接到MainForm.MouseDown事件,這不用多說了吧?):
private void MainForm_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
if(e.Button == MouseButtons.Left) {
this.mousePosition.X = e.X;
this.mousePosition.Y = e.Y;
}
}
在這裡注意對鼠標按鍵進行篩選。
接下來,為窗體添加鼠標移動事件處理方法(我這裡是MainForm_MouseMove):
private void MainForm_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) {
if(e.Button == MouseButtons.Left) {
Form.Top = Control.MousePosition.Y - mousePosition.Y
- SystemInformation.FrameBorderSize.Height - SystemInformation.CaptionHeight;
Form.Left = Control.MousePosition.Y - mousePosition.Y
- SystemInformation.FrameBorderSize.Width;
}
}
這裡,如果窗體沒有標題欄,可以去掉“-SystemInformation.CaptionHeight”;如果窗體沒有邊框,還可以去掉“-SystemInformation.FrameBorderSize.Height”和“-SystemInformation.FrameBorderSize.Width”。
現在,您是不是已經很清楚地明白如何用C#制作可拖動窗口了?祝賀您!最後,送您一個小禮物——桌面時鐘。很簡潔、很有意思哦~~~
另外贈送小技巧三則:
如何制作不規則窗體
這個技巧我掌握的還不是很豐富,現在介紹一種最簡單的方法——通過設置窗體的Region屬性。首先,聲明一個System.Drawing.Drawing2D.GraphicsPath變量,在這個變量中添加您期望作為窗體輪廓的形狀組合;之後,從這個變量生成一個System.Drawing.Region實例,並賦給窗體的Region屬性即可。如:
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(0, 0, 120, 120);
Region r = new Region(gp);
this.Region = r;
將上述代碼添加到窗體的構造函數中,我們就能夠得到一個自定義的窗體了,這個窗體是一個直徑為120像素的圓形(也是我的時鐘的外觀哦)。
如何生成沒有邊框的窗體
將窗體的FormBorderStyle設置為None即可。這很簡單事麼?那麼
如何生成有邊框但沒有標題欄的窗體
首先將窗體的ControlBox屬性設置為false,也就是不要控制按鈕(窗體圖標、最大最小化按鈕和關閉按鈕)。按說這時就不應該有標題欄了,但我們還能看到它很煩人地待在那裡,因此,我們要把窗體的Text屬性設置為空(注意是String.Empty,而不是null)。
記錄鼠標位置;由於在移動的過程中,鼠標的屏幕坐標發生變化但窗體相對坐標不變,我們可以推算出窗體位置的變化為(假設mousePosition具有System.Drawing.Point類型,表示鼠標在窗體中的相對坐標):