一、技術要點
就像本文開頭所說的"標註式消息提示窗口"其實就是一個具有不規則外形的窗體,但卻具備了更加複雜的屬性和行爲。標註的箭頭會根據不同控件指向不同的位置,當需要標註的控件過於接近屏幕的邊緣時,標註窗口還會自動調整顯示位置以及箭頭的長短和大小。
我們爲新創建的窗體取名爲InfoWindow。在類的頭部定義intArc和intArrowHeight兩個私有變量,可以適當調整它們的值來微調提示窗口的位置和箭頭的大小與位置。
提示窗口的箭頭位置無非具有左上、右上、左下和右下四個可能性,我們爲此定義了枚舉類型的變量ArrowLocation,根據提示窗口位於屏幕的不同位置,GetArrowLocation可以計算提示窗口的位置並且返回適當的ArrowLocation,定義如下:
…… public enum ArrowLocation { TopLeft, TopRight, BottomLeft, BottomRight } |
SetInfoWindowRegion函數非常重要,它在Form.Load事件即裝載和顯示提示窗體時被調用,當計算出新的提示窗口的位置和箭頭顯示位置後,調用SetBounds將更新後的位置和大小應用到提示窗口,gPath是GraphicsPath類型的私有變量,它表示標註式窗口的不規則圖形路徑,該圖行路徑也是根據提示窗口的位置和箭頭顯示的位置來創建,gPath.AddArc方法用來繪製提示窗口四個邊角的弧度部分,和AddLine方法一起描繪出提示窗口包括箭頭的輪廓,一切就緒後我們就用這個gPath對象傳遞給Region對象,當將這個Region對象賦給Form窗體的Region屬性後,窗體就具備了標註式提示窗口樣式的不規則外形了,部分代碼如下:
private void SetInfoWindowRegion() { if (!this.IsHandleCreated) return; System.Drawing.Size windowSize = this.Size; Point[] ArrowPoints = new Point[3]; Point topLeftPoint = Point.Empty; Point bottomRightPoint = (Point)windowSize; switch (this.GetArrowLocation) { case ArrowLocation.TopLeft: …… case ArrowLocation.TopRight: …… case ArrowLocation.BottomLeft: …… case ArrowLocation.BottomRight: …… } …… …… if ((this.GetArrowLocation == ArrowLocation.TopLeft) || (this.GetArrowLocation == ArrowLocation.TopRight)) { gPath.AddArc(topLeftPoint.X, rectY2 - arcRadius, arcDia, arcDia, 90, 90); gPath.AddLine(topLeftPoint.X, rectY2, topLeftPoint.X, rectY1); gPath.AddArc(topLeftPoint.X, topLeftPoint.Y, arcDia, arcDia, 180, 90); gPath.AddLine(rectX1, topLeftPoint.Y, ArrowPoints[0].X, topLeftPoint.Y); gPath.AddLines(ArrowPoints); gPath.AddLine(ArrowPoints[2].X, topLeftPoint.Y, rectX2, topLeftPoint.Y); gPath.AddArc(rectX2 - arcRadius, topLeftPoint.Y, arcDia, arcDia, 270, 90); gPath.AddLine(bottomRightPoint.X, rectY1, bottomRightPoint.X, rectY2); gPath.AddArc(rectX2 - arcRadius, rectY2 - arcRadius, arcDia, arcDia, 0, 90); gPath.AddLine(rectX2, bottomRightPoint.Y, rectX1, bottomRightPoint.Y); } else { gPath.AddLine(rectX1, topLeftPoint.Y, rectX2, topLeftPoint.Y); gPath.AddArc(rectX2 - arcRadius, topLeftPoint.Y, arcDia, arcDia, 270, 90); gPath.AddLine(bottomRightPoint.X, rectY1, bottomRightPoint.X, rectY2); gPath.AddArc(rectX2 - arcRadius, rectY2 - arcRadius, arcDia, arcDia, 0, 90); gPath.AddLine(rectX2, bottomRightPoint.Y, ArrowPoints[0].X, bottomRightPoint.Y); gPath.AddLines(ArrowPoints); gPath.AddLine(ArrowPoints[2].X, bottomRightPoint.Y, rectX1, bottomRightPoint.Y); gPath.AddArc(topLeftPoint.X, rectY2 - arcRadius, arcDia, arcDia, 90, 90); gPath.AddLine(topLeftPoint.X, rectY2, topLeftPoint.X, rectY1); gPath.AddArc(topLeftPoint.X, topLeftPoint.Y, arcDia, arcDia, 180, 90); } gPath.CloseFigure(); this.Region = new Region(this.gPath); } |
ShowInfoWindow函數用來將提示窗口顯示出來,該函數需要將提示窗口附着的控件和需要顯示的文本傳遞過來。然後,AnchorPointFromControl根據控件的位置返回提示窗口的箭頭應該顯示的座標,代碼如下:
public static Point AnchorPointFromControl(Control anchorControl) { if (anchorControl == null) throw new ArgumentException(); Point controlLocation = anchorControl.Location; System.Drawing.Size controlSize = anchorControl.Size; if (anchorControl.Parent != null) controlLocation = anchorControl.Parent.PointToScreen(controlLocation); return controlLocation + new Size(controlSize.Width / 2, controlSize.Height / 2); } |
PointToScreen表明將工作區點的位置映射成屏幕座標統一進行計算。上述代碼最後以行說明提示窗口的箭頭顯示在附着控件的中點。
將提示窗口的背景顏色設置成Info,外觀如下圖:
我們發現這樣的外觀有點彆扭,沒錯!因爲提示窗口缺少黑色邊框!所以,還需要在窗體的OnPaint事件中添加代碼,如下:
protected override void OnPaint(PaintEventArgs e) { Pen p = new Pen(Color.Black , 2); e.Graphics.DrawPath(p, gPath); base.OnPaint(e); } |
啓動Visual Studio 2005,新建Visual C#的Windows 應用程序項目,並取名爲ShowInfoWindow,添加4個Button組件、1個Label組件、1個textBox組件和3個Panel組件,其中3個Button用來顯示標註式消息提示窗口並分別附着在三個組件之上,代碼如下:
…… private InfoWindow iw; …… private void button1_Click(object sender, EventArgs e) { iw = new InfoWindow(); iw.ShowInfoWindow(label1, "關於標籤組件的提示說明。"); } private void button3_Click(object sender, EventArgs e) { iw = new InfoWindow(); iw.ShowInfoWindow(button2, "關於按鈕組件的提示說明。"); } private void button4_Click(object sender, EventArgs e) { iw = new InfoWindow(); iw.ShowInfoWindow(textBox1, "關於文本框組件的提示說明。"); } |
然後,我們在項目中添加新Windows窗體,取名爲InfoWindow,將InfoWindow的BackColor設爲Info,FormBorderStyle設爲None,將ShowIcon和ShowInTaskbar都設爲False,在窗體上放置1個Label組件和1個Button組件,分別用來顯示消息內容和關閉提示窗口的操作。具體實現請參見文章附帶的源碼,這裏不再詳述。
三、總結
本文演示了標註式消息提示窗口的創建和顯示,利用GraphicsPath對象、Region對象以及屏幕座標映射等方法有效的實現了提示窗口的外觀和樣式,提示窗口可以自動附着在相應控件之上,並且根據附着控件在屏幕上的位置自動調整提示窗口箭頭的位置和大小。演示程序在Windows XP SP2以及.Net 框架 2.0環境下運行通過。