ASP.NET可交互式位圖窗體設(shè)計(jì)(3)
發(fā)表時(shí)間:2024-02-09 來(lái)源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]構(gòu)造函數(shù) 構(gòu)造函數(shù)傳遞三個(gè)參數(shù):包含圓的中心坐標(biāo)的點(diǎn)、圓的半徑以及一個(gè) System.Drawing.Color 結(jié)構(gòu)(包含用于繪制圓輪廓的顏色)。 然后我們根據(jù)中心和半徑計(jì)算邊框,并將筆顏色項(xiàng)設(shè)置為我們傳遞的顏色對(duì)象。 繪圖代碼 Draw 方法重載實(shí)際上非常簡(jiǎn)單:它根...
構(gòu)造函數(shù)
構(gòu)造函數(shù)傳遞三個(gè)參數(shù):包含圓的中心坐標(biāo)的點(diǎn)、圓的半徑以及一個(gè) System.Drawing.Color 結(jié)構(gòu)(包含用于繪制圓輪廓的顏色)。
然后我們根據(jù)中心和半徑計(jì)算邊框,并將筆顏色項(xiàng)設(shè)置為我們傳遞的顏色對(duì)象。
繪圖代碼
Draw 方法重載實(shí)際上非常簡(jiǎn)單:它根據(jù)我們保存在構(gòu)造函數(shù)中的顏色對(duì)象創(chuàng)建一個(gè)筆對(duì)象,然后使用該筆,調(diào)用 Graphics.DrawEllipse 方法繪制圓,同時(shí)傳遞了我們?cè)缦葎?chuàng)建的邊框。
圖形、筆和畫(huà)筆
這里我們需要解釋一下 Graphics、Pen 和 Brush 對(duì)象。(在開(kāi)始填充我們的可填充對(duì)象時(shí),就會(huì)看到 Brush 對(duì)象。)
Graphics 對(duì)象代表一個(gè)與某個(gè)真實(shí)繪圖空間相關(guān)聯(lián)的虛擬化的繪圖空間。虛擬化是指,通過(guò)在 Graphics 對(duì)象上繪圖,我們可以使用相同的 Graphics 方法在與該對(duì)象相關(guān)聯(lián)的任何類型的實(shí)際表面上繪圖。對(duì)于那些習(xí)慣于使用 MFC 或 Microsoft Windows? SDK 編程的用戶,Graphics 對(duì)象相當(dāng)于 Windows 中稱為“設(shè)備上下文”(或 DC)的 .NET 版本。
在此 Windows 窗體應(yīng)用程序中,傳遞到 Draw 方法的 Graphics 對(duì)象將與屏幕上的一個(gè)窗口相關(guān)聯(lián) -- 這里是 PictureBox。在我們的 Microsoft ASP.NET 應(yīng)用程序中使用這一代碼時(shí),傳遞給 Draw 方法的 Graphics 對(duì)象將與一個(gè)位圖圖像相關(guān)聯(lián)。它也可以和打印機(jī)或其他設(shè)備相關(guān)聯(lián)。
這個(gè)方案的優(yōu)點(diǎn)是我們可以使用相同的繪圖代碼在不同的表面上繪圖。在我們的繪圖代碼中,我們不需要知道任何有關(guān)屏幕、位圖、打印機(jī)等等之間的不同 -- .NET Framework(以及底層的操作系統(tǒng))可以為我們處理所有細(xì)節(jié)。
利用相同的標(biāo)記,筆和畫(huà)筆成為虛擬化的繪圖工具。筆代表線條屬性 -- 顏色、寬度、樣式,甚至可以是用來(lái)繪制線的位圖。畫(huà)筆代表一個(gè)填充區(qū)域的屬性 -- 顏色、樣式,甚至可以是用來(lái)填充區(qū)域的位圖。
在使用 Using 后清除(或至少 Dispose)
Graphics、Pen 和 Brush 對(duì)象都與相似類型的 Windows 對(duì)象相關(guān)聯(lián)。這些 Windows 對(duì)象分配在操作系統(tǒng)的內(nèi)存中 -- 這些內(nèi)存尚未被 .NET 運(yùn)行時(shí)管理。長(zhǎng)時(shí)間將這些對(duì)象駐留在內(nèi)存中會(huì)導(dǎo)致性能問(wèn)題,并且在 Microsoft Windows 98 下,當(dāng)圖形堆填滿時(shí)會(huì)導(dǎo)致繪圖問(wèn)題。因此,我們應(yīng)盡快釋放這些 Windows 對(duì)象。
當(dāng)相應(yīng)的 .NET Framework 對(duì)象完成操作并回收內(nèi)存后,.NET 運(yùn)行時(shí)會(huì)自動(dòng)釋放 Windows 對(duì)象。但回收內(nèi)存的時(shí)間會(huì)很長(zhǎng) -- 如果我們不迅速釋放這些對(duì)象,所有不幸的事情(包括填滿 Windows 堆)都可能發(fā)生。在該應(yīng)用程序的 ASP.NET 版本中,由于很多用戶在同一臺(tái)服務(wù)器上訪問(wèn)該應(yīng)用程序,所以這種現(xiàn)象會(huì)更加嚴(yán)重。
因?yàn)檫@些對(duì)象與未管理的資源相關(guān)聯(lián),所以它們實(shí)現(xiàn) IDisposable 接口。該接口有一個(gè)方法,即 Dispose,它將 .NET Framework 對(duì)象從 Windows 對(duì)象中分離出來(lái),并釋放 Windows 對(duì)象,從而使計(jì)算機(jī)處于良好的狀態(tài)。
這時(shí)您只需完成一項(xiàng)任務(wù):確保在使用完該對(duì)象后,調(diào)用 Dispose 方法。
Visual Basic .NET 代碼中顯示了這一內(nèi)容的經(jīng)典形式:首先創(chuàng)建對(duì)象,然后在一個(gè) Try 塊中使用該對(duì)象,最后在 Finally 塊中清理該對(duì)象。Try/Finally 能夠確保即使出現(xiàn)異常也會(huì)清理對(duì)象。(在本例中,我們調(diào)用的繪圖方法可能不會(huì)引發(fā)異常,所以可能并不需要 Try/Finally 塊。但掌握這些技巧很有用,因此 Dr. GUI 也希望向您演示這一正確方法。)
這種形式很常見(jiàn),因此 C# 為其提供了一個(gè)私有語(yǔ)句:using。C# 代碼中的 using 語(yǔ)句等同于 Visual Basic .NET 代碼中的聲明和 Try/Finally -- 但更為簡(jiǎn)潔、方便,并減少了發(fā)生錯(cuò)誤的可能性。(Dr. GUI 不清楚為什么 Visual Basic .NET 不包含一些諸如 using 的語(yǔ)句。)
接口
有些(但不是全部)可繪制對(duì)象可以被填充。某些對(duì)象(如點(diǎn)和線)不能被填充,因?yàn)樗鼈儾皇欠忾]的區(qū)域,而矩形和圓等對(duì)象可以是中空的,或者被填充。
另一方面,就象將所有可繪制對(duì)象作為多態(tài)處理一樣,我們也可以將所有可填充對(duì)象作為多態(tài)處理,這會(huì)很方便。例如,如同我們將所有可繪制對(duì)象放到一個(gè)集合中,通過(guò)遍歷集合并在每個(gè)對(duì)象上調(diào)用 Draw 來(lái)繪制對(duì)象一樣,我們可以將所有可填充對(duì)象放到一個(gè)集合中,而不考慮這些可填充對(duì)象的實(shí)際類型。因此,我們使用某種機(jī)制(如繼承)來(lái)獲得真正的多態(tài)。
因?yàn)椴皇撬械目衫L制對(duì)象都可以被填充,因此不能將 Fill 方法的聲明放在抽象基類中。.NET Framework 不允許類的多重繼承,所以也不能將其放在另一個(gè)抽象基類中。并且如果我們從不是非可填充類的其他基類中派生出可填充對(duì)象,則不能將所有可繪制對(duì)象作為多態(tài)處理。
但 .NET Framework 支持接口 -- 并提供了一個(gè)可實(shí)現(xiàn)任意數(shù)量的接口的類。接口不具有任何實(shí)現(xiàn) -- 沒(méi)有代碼,也沒(méi)有任何數(shù)據(jù)。因此,實(shí)現(xiàn)接口的類必須提供所有內(nèi)容。
接口所能包含的只有聲明。以下是我們?cè)?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 屬性以及任何其他項(xiàng),因?yàn)榻涌谥械乃蟹椒ê蛯傩远甲詣?dòng)設(shè)置為公開(kāi)的和 abstract/MustOverride。
使用一個(gè)屬性:不能在接口中包含數(shù)據(jù)
請(qǐng)注意,雖然我們不能在接口中聲明字段,但可以聲明一個(gè)屬性,因?yàn)閷傩詫?shí)際上是作為方法實(shí)現(xiàn)的。
但這樣做會(huì)給接口的實(shí)現(xiàn)者帶來(lái)負(fù)擔(dān),下面就會(huì)看到。實(shí)現(xiàn)者必須實(shí)現(xiàn) get 和 set 方法,以及實(shí)現(xiàn)該屬性所必需的任何數(shù)據(jù)。如果實(shí)現(xiàn)非常復(fù)雜,則可以編寫(xiě)一個(gè) helper 類以封裝某些部分。在本文稍后我們將就一個(gè)略微不同的上下文環(huán)境顯示如何使用 helper 類。
實(shí)現(xiàn)接口
我們已經(jīng)定義了接口,現(xiàn)在可以在類中實(shí)現(xiàn)它了。請(qǐng)注意,我們必須提供所實(shí)現(xiàn)接口的完整實(shí)現(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)這些類的注意事項(xiàng)。
從 HollowRectangle 中派生
我們從這個(gè)類的空心版本中派生出填充類。這個(gè)類中的多數(shù)內(nèi)容都發(fā)生了改變:Draw 方法和構(gòu)造函數(shù)都是新的(但兩者都調(diào)用基類的版本),并且為 IFillable 接口的 Fill 方法以及 FillBrushColor 屬性添加了實(shí)現(xiàn)。
需要新構(gòu)造函數(shù)的原因是我們?cè)谶@個(gè)類中包含了需要初始化的其他數(shù)據(jù),即填充畫(huà)筆。(您可以回顧我們前面討論的畫(huà)筆。)請(qǐng)注意此構(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))。
因?yàn)槲覀円呀?jīng)向基類構(gòu)造函數(shù)中傳遞了三個(gè)參數(shù)中的兩個(gè),現(xiàn)在只需初始化最后的字段即可。