??? (注:本文期望的讀者是那些有一定用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簡體中文版并且安裝了配套文檔時才有效)。
??? 知道了如何獲取這些信息之后,制作移動窗體實際上就成了一個很簡單的問題了。基本過程是這樣的:首先,在鼠標(左鍵或一個你喜歡的鍵)按下時,記錄鼠標位置;由于在移動的過程中,鼠標的屏幕坐標發生變化但窗體相對坐標不變,我們可以推算出窗體位置的變化為(假設mousePosition具有System.Drawing.Point類型,表示鼠標在窗體中的相對坐標):
// 示例代碼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)。