明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

ASP.NET可交互式位圖窗體設(shè)計(3)

[摘要]構(gòu)造函數(shù)   構(gòu)造函數(shù)傳遞三個參數(shù):包含圓的中心坐標的點、圓的半徑以及一個 System.Drawing.Color 結(jié)構(gòu)(包含用于繪制圓輪廓的顏色)。   然后我們根據(jù)中心和半徑計算邊框,并將筆顏色項設(shè)置為我們傳遞的顏色對象。   繪圖代碼   Draw 方法重載實際上非常簡單:它根...
 構(gòu)造函數(shù)
  構(gòu)造函數(shù)傳遞三個參數(shù):包含圓的中心坐標的點、圓的半徑以及一個 System.Drawing.Color 結(jié)構(gòu)(包含用于繪制圓輪廓的顏色)。 
  
  然后我們根據(jù)中心和半徑計算邊框,并將筆顏色項設(shè)置為我們傳遞的顏色對象。 
  
  繪圖代碼
  Draw 方法重載實際上非常簡單:它根據(jù)我們保存在構(gòu)造函數(shù)中的顏色對象創(chuàng)建一個筆對象,然后使用該筆,調(diào)用 Graphics.DrawEllipse 方法繪制圓,同時傳遞了我們早先創(chuàng)建的邊框。 
  
  圖形、筆和畫筆
  這里我們需要解釋一下 Graphics、Pen 和 Brush 對象。(在開始填充我們的可填充對象時,就會看到 Brush 對象。) 
  
  Graphics 對象代表一個與某個真實繪圖空間相關(guān)聯(lián)的虛擬化的繪圖空間。虛擬化是指,通過在 Graphics 對象上繪圖,我們可以使用相同的 Graphics 方法在與該對象相關(guān)聯(lián)的任何類型的實際表面上繪圖。對于那些習(xí)慣于使用 MFC 或 Microsoft Windows? SDK 編程的用戶,Graphics 對象相當(dāng)于 Windows 中稱為“設(shè)備上下文”(或 DC)的 .NET 版本。 
  
  在此 Windows 窗體應(yīng)用程序中,傳遞到 Draw 方法的 Graphics 對象將與屏幕上的一個窗口相關(guān)聯(lián) -- 這里是 PictureBox。在我們的 Microsoft ASP.NET 應(yīng)用程序中使用這一代碼時,傳遞給 Draw 方法的 Graphics 對象將與一個位圖圖像相關(guān)聯(lián)。它也可以和打印機或其他設(shè)備相關(guān)聯(lián)。 
  
  這個方案的優(yōu)點是我們可以使用相同的繪圖代碼在不同的表面上繪圖。在我們的繪圖代碼中,我們不需要知道任何有關(guān)屏幕、位圖、打印機等等之間的不同 -- .NET Framework(以及底層的操作系統(tǒng))可以為我們處理所有細節(jié)。 
  
  利用相同的標記,筆和畫筆成為虛擬化的繪圖工具。筆代表線條屬性 -- 顏色、寬度、樣式,甚至可以是用來繪制線的位圖。畫筆代表一個填充區(qū)域的屬性 -- 顏色、樣式,甚至可以是用來填充區(qū)域的位圖。 
  
  在使用 Using 后清除(或至少 Dispose)
  Graphics、Pen 和 Brush 對象都與相似類型的 Windows 對象相關(guān)聯(lián)。這些 Windows 對象分配在操作系統(tǒng)的內(nèi)存中 -- 這些內(nèi)存尚未被 .NET 運行時管理。長時間將這些對象駐留在內(nèi)存中會導(dǎo)致性能問題,并且在 Microsoft Windows 98 下,當(dāng)圖形堆填滿時會導(dǎo)致繪圖問題。因此,我們應(yīng)盡快釋放這些 Windows 對象。 
  
  當(dāng)相應(yīng)的 .NET Framework 對象完成操作并回收內(nèi)存后,.NET 運行時會自動釋放 Windows 對象。但回收內(nèi)存的時間會很長 -- 如果我們不迅速釋放這些對象,所有不幸的事情(包括填滿 Windows 堆)都可能發(fā)生。在該應(yīng)用程序的 ASP.NET 版本中,由于很多用戶在同一臺服務(wù)器上訪問該應(yīng)用程序,所以這種現(xiàn)象會更加嚴重。 
  
  因為這些對象與未管理的資源相關(guān)聯(lián),所以它們實現(xiàn) IDisposable 接口。該接口有一個方法,即 Dispose,它將 .NET Framework 對象從 Windows 對象中分離出來,并釋放 Windows 對象,從而使計算機處于良好的狀態(tài)。 
  
  這時您只需完成一項任務(wù):確保在使用完該對象后,調(diào)用 Dispose 方法。 
  
  Visual Basic .NET 代碼中顯示了這一內(nèi)容的經(jīng)典形式:首先創(chuàng)建對象,然后在一個 Try 塊中使用該對象,最后在 Finally 塊中清理該對象。Try/Finally 能夠確保即使出現(xiàn)異常也會清理對象。(在本例中,我們調(diào)用的繪圖方法可能不會引發(fā)異常,所以可能并不需要 Try/Finally 塊。但掌握這些技巧很有用,因此 Dr. GUI 也希望向您演示這一正確方法。) 
  
  這種形式很常見,因此 C# 為其提供了一個私有語句:using。C# 代碼中的 using 語句等同于 Visual Basic .NET 代碼中的聲明和 Try/Finally -- 但更為簡潔、方便,并減少了發(fā)生錯誤的可能性。(Dr. GUI 不清楚為什么 Visual Basic .NET 不包含一些諸如 using 的語句。) 
  
  接口
  有些(但不是全部)可繪制對象可以被填充。某些對象(如點和線)不能被填充,因為它們不是封閉的區(qū)域,而矩形和圓等對象可以是中空的,或者被填充。 
  
  另一方面,就象將所有可繪制對象作為多態(tài)處理一樣,我們也可以將所有可填充對象作為多態(tài)處理,這會很方便。例如,如同我們將所有可繪制對象放到一個集合中,通過遍歷集合并在每個對象上調(diào)用 Draw 來繪制對象一樣,我們可以將所有可填充對象放到一個集合中,而不考慮這些可填充對象的實際類型。因此,我們使用某種機制(如繼承)來獲得真正的多態(tài)。
  因為不是所有的可繪制對象都可以被填充,因此不能將 Fill 方法的聲明放在抽象基類中。.NET Framework 不允許類的多重繼承,所以也不能將其放在另一個抽象基類中。并且如果我們從不是非可填充類的其他基類中派生出可填充對象,則不能將所有可繪制對象作為多態(tài)處理。 
  
  但 .NET Framework 支持接口 -- 并提供了一個可實現(xiàn)任意數(shù)量的接口的類。接口不具有任何實現(xiàn) -- 沒有代碼,也沒有任何數(shù)據(jù)。因此,實現(xiàn)接口的類必須提供所有內(nèi)容。 
  
  接口所能包含的只有聲明。以下是我們在 C# 中的接口 IFillable。單擊此處在新窗口中查看全部源文件。
  
  
  
    C#
  public interface IFillable {
  void Fill(Graphics g);
  Color FillBrushColor { get; set; }
  } 
   
  
  以下是等同的 Visual Basic .NET 代碼。單擊此處在新窗口中查看全部源文件。
  
    Visual Basic .NET
  
  Public Interface IFillable
  Sub Fill(ByVal g As Graphics)
  Property FillBrushColor() As Color
  End Interface 
  
  我們不需要聲明方法或者 virtual/Overridable 或 abstract/MustOverride 屬性以及任何其他項,因為接口中的所有方法和屬性都自動設(shè)置為公開的和 abstract/MustOverride。 
  
  使用一個屬性:不能在接口中包含數(shù)據(jù)
  請注意,雖然我們不能在接口中聲明字段,但可以聲明一個屬性,因為屬性實際上是作為方法實現(xiàn)的。 
  
  但這樣做會給接口的實現(xiàn)者帶來負擔(dān),下面就會看到。實現(xiàn)者必須實現(xiàn) get 和 set 方法,以及實現(xiàn)該屬性所必需的任何數(shù)據(jù)。如果實現(xiàn)非常復(fù)雜,則可以編寫一個 helper 類以封裝某些部分。在本文稍后我們將就一個略微不同的上下文環(huán)境顯示如何使用 helper 類。 
  
  實現(xiàn)接口
  我們已經(jīng)定義了接口,現(xiàn)在可以在類中實現(xiàn)它了。請注意,我們必須提供所實現(xiàn)接口的完整實現(xiàn):不能只從中選取一部分。 
  
  下面我們看看 C# 中 DFilledRectangle 類的代碼。
  
  
    C#
  public class DFilledCircle : DHollowCircle, IFillable
  {
  public DFilledCircle(Point center, int radius, Color penColor,
  Color brushColor) : base(center, radius, penColor) {
  this.brushColor = brushColor;
  }
  
  public void Fill(Graphics g) {
  using (Brush b = new SolidBrush(brushColor)) {
  g.FillEllipse(b, bounding);
  }
  }
  protected Color brushColor;
  public Color FillBrushColor {
  get {
  return brushColor;
  }
  set {
  brushColor = value;
  }
  }
  public override void Draw(Graphics g) {
  Fill(g);
  base.Draw(g);
  }
  } 
  
  以下是 Visual Basic .NET 中 DFilledRectangle 類的代碼。
  
  
    Visual Basic .NET
  Public Class DFilledRectangle
  Inherits DHollowRectangle
  Implements IFillable
  Public Sub New(ByVal rect As Rectangle, _
  ByVal penColor As Color, ByVal brushColor As Color)
  MyBase.New(rect, penColor)
  Me.brushColor = brushColor
  End Sub
  Public Sub Fill(ByVal g As Graphics) Implements IFillable.Fill
  Dim b = New SolidBrush(FillBrushColor)
  Try
  g.FillRectangle(b, bounding)
  Finally
  b.dispose()
  End Try
  End Sub
  Protected brushColor As Color
  Public Property FillBrushColor() As Color _
  Implements IFillable.FillBrushColor
  Get
  Return brushColor
  End Get
  Set(ByVal Value As Color)
  brushColor = Value
  End Set
  End Property
  Public Overrides Sub Draw(ByVal g As Graphics)
  Dim p = New Pen(penColor)
  Try
  Fill(g)
  MyBase.Draw(g)
  Finally
  p.Dispose()
  End Try
  End Sub
  End Class 
   
  
  以下是有關(guān)這些類的注意事項。 
  
  從 HollowRectangle 中派生
  我們從這個類的空心版本中派生出填充類。這個類中的多數(shù)內(nèi)容都發(fā)生了改變:Draw 方法和構(gòu)造函數(shù)都是新的(但兩者都調(diào)用基類的版本),并且為 IFillable 接口的 Fill 方法以及 FillBrushColor 屬性添加了實現(xiàn)。 
  
  需要新構(gòu)造函數(shù)的原因是我們在這個類中包含了需要初始化的其他數(shù)據(jù),即填充畫筆。(您可以回顧我們前面討論的畫筆。)請注意此構(gòu)造函數(shù)是如何調(diào)用基類構(gòu)造函數(shù)的:在 C# 中,該調(diào)用被內(nèi)置到聲明 (: base(center, radius, penColor)) 中;在 Visual Basic .NET 中,我們將它明確放在 New 方法(即構(gòu)造函數(shù))的第一行 (MyBase.New(rect, penColor))。 
  
  因為我們已經(jīng)向基類構(gòu)造函數(shù)中傳遞了三個參數(shù)中的兩個,現(xiàn)在只需初始化最后的字段即可。