構建一個彈出式圖象按鈕

來源:互聯網
上載者:User
按鈕 構建Windows控制項並不是一件特別複雜的事情。我曾在以前的文章中講過如何通過最專業的技術來構建複雜的控制項,但這並不意味著構建所有控制項都是那麼複雜。本文我將用一種曾在我的工作中遇到的簡單方法來解決一個真實領域中的問題。就算你只有一些或者完全沒有什麼構建控制項的經驗,你也可以用它來實現在你的傳統型應用程式中加入複雜的功能。

我需要一個帶有不同圖象的彈出式按鈕,用於實現常規的、mouse-hover和mouse-down狀態。我可以用一個常規的WinForm按鈕來實現大多數我想要的效果,但卻不能實現給邊框加上顏色。我還想要讓圖象移到按鈕的右邊緣,就象功能表按鈕那樣。確切地說,我是需要一個能夠代表其本身功能的功能表按鈕。

你可以用大約150行的代碼來構建這個控制項;最長的過程包含約25行代碼。這個方法是一個很好的起點;你可以給它添加許多效能並可以將它當作一個其他類型控制項的模式。該過程的屬性或許是這個項目中最為複雜的一個地方了――對.NET提供的經過深思熟慮的基類的一個確實的證明。

基本的方法是以一個已經存在的控制項開始並通過繼承來添加或改變其行為。控制項的Paint事件允許你在表單中進行隨意繪製。對listbox或treeview來說,完成這個功能可能需要做很多工作,但對按鈕來說,只需用圖象作為表面就可以了。你可以通過從Button類中派生出你所需要的ImageButton類,用一個Button控制項的Paint事件來繪製出適當的圖象。然而,對於一個彈出式按鈕來說,象Image、FlatStyle和AutoSize這樣的Button屬性是沒有意義的。作為替代,你可以從Control基類中派生它並自己為它加上邊框。這樣做並不需要你編寫額外的代碼,它會產生一個更有效控制項和一個用於構建其他控制項表單的通用模板。

一個彈出式按鈕的行為是很簡單的。它有三種狀態,每種狀態都帶有一個邊框和一個圖象。Control基類支援一組可以被覆蓋(override)的Mouse過程,以及Paint程式。你可以通過簡單地從Windows.Forms.Control派生來開始一個程式。奇怪的是,Control基類不是一個“必須繼承類”(通常被成為抽象類別),就是說以該類為基類進行派生時,你無需覆蓋任何方法。覆蓋是指Windows和.NET允許你在某人或某個東西(即系統)調用了基類的方法時執行你自己的代碼。這一點非常有用。

在繪製時進行選擇
當一個終端使用者切換到另一個頁面時, ImageButton、Windows以及.NET會通知Control類。Control類將Windows的資訊傳遞給繼承者的OnPaint程式。在編寫覆蓋程式時你可以運行自己的代碼,而不需要完全按照基類的做法。儘管Control類不是一個抽象基類,但它自己並不完成任何繪製。然而,在你需要繼承一個類時,――比如Button或Label類,通常你會取代基類的painting,而不是將它添加到你的程式中。OnPaint 覆蓋中包括一個對MyBase的調用,這不是因為基類需要進行處理來實現繪製,而是為了給使用者提供一個自己的Paint事件。繼承類不會直接代表其基類來觸發事件,對MyBase.OnPaint的調用導致基類觸發用戶端Paint事件。

這一點會對你將來構建控制項有所影響,因此為了讓你有更全面的瞭解我將從另一個角度對它進行講述。如果你通過覆蓋一個OnPaint 來支援你自己的作品(就是說用於一個標準的Button基類),而且你不僅僅想要實現基類所完成繪製,那麼你的OnPaint覆蓋中就不應該包含MyBase.OnPaint調用。在這個情境中,如果你還想為使用派生控制項的開發人員提供一個Paint事件,則必須在基類中提供一個Paint事件聲明。如果基類中已存在了一個Paint事件,你則必須用Shadows關鍵字來聲明你自己的事件從而將基類的事件隱藏起來。不要輕易嘗試使用Shadows,因為它容易讓使用該控制項的開發人員搞糊塗,雖然在一個事件中使用這種方法看起來似乎更安全。

Shadows只是用一個和基類相似的名稱向使用者顯示一種方法的派生版本。它所存在的潛在問題是使用者仍然可以通過用CType將你的類中的對象轉化為基類來得到基類中的方法。Control類中的一些方法對ImageButton來說是沒有用的。比如,不需要Text屬性。你可以在Visual Studio的 Properties視窗中將Control.Text用一個ReadOnly屬性替換掉,返回一個空串。使用者可能會覺得很麻煩,但這樣卻能避免出現一些問題:Dim pop1 As New ImageButton
CType(pop1, Control).Text = "Hi"





前面這段代碼不會導致出錯,但卻不會真正起什麼作用;ImageButton不會通過其基類的Text屬性來繪製控制項。然而,如果使用者嘗試填寫ImageButton的Text屬性則會導致產生一個design-time(編譯)唯讀錯誤:Dim pop1 As New ImageButton
pop1.Text = "Hi" 'Error





最後,通過將<Browsable(False)>屬性添加到聲明中來把Text屬性隱藏起來。它還要求你給使用者提供一個新的預設屬性,否則是無效的,因為Control的預設屬性是Text。通過將<DefaultProperty("DisplayImageIndex")>添加到類聲明中來將DisplayImageIndex屬性作為新的預設屬性。

塗成藍色
和功能表按鈕一樣,ImageButton必須帶有不同的圖象和邊框式樣,這取決於滑鼠的位置。和功能表按鈕不同的是,ImageButton必須能夠獲得焦點並顯示焦點矩形框。所有的特性都必須通過代碼來實現,因為Control類不會處理。然而,你只需一小段代碼就可以實現它,就像你從OnPaint過程中看到的那樣。

你可以通過OnMouseEnter、Leave、Up和Down覆蓋過程從系統中獲得滑鼠通知。你可以象使用一般的mouse事件一樣來使用它們,但是用覆蓋意味著你能夠在基類提供行為之前或之後添加新的行為,或者取代基類的行為。通過設定一個MouseButtonState變數,你可以用每個過程來決定將哪個圖象拖到控制介面。OnMouseDown還會設定焦點: Overrides Sub OnMouseDown(ByVal ma As _
MouseEventArgs)
MyBase.OnMouseDown(ma)
_MouseButtonState = Down
Me.Focus()
MyBase.Invalidate()
End Sub




Control.Invalidate調用用於告知基類該控制項需要被重畫。基類依次調用覆蓋的OnPaint方法,它通過PaintEventArgs來提供一個GDI+ 圖象對象。你可以用該對象共用的DrawImage方法用一行代碼繪製一個位元影像(bitmap),給DrawImage提供圖象、位置和大小,選擇將哪個圖象繪製到滑鼠位置。一個很方便的設計態專用的DisplayImageIndex屬性會讓使用者自己選擇將哪種圖象顯示出來。你可以將兩種屬性用在該方法的聲明中:<Category ("Design")>用於告訴Visual Studio屬性視窗該在哪裡列出該屬性,<DesignOnly(True)>用於在運行時將它隱藏起來。給DisplayImageIndex值添加一個枚舉,使使用者可以通過簡單地點擊這個值來查看到Down、Up和Hover。DisplayImageIndex使使用者無需開啟ImageList控制項來確保他們選擇了正確的用於Down、Up和Hover的ImageIndex值。

你可以用滑鼠位置來選取需要繪製的邊框顏色。當焦點集中在控制項上時,代碼將邊框厚度設定為兩個象素點,只用於UP狀態。建立一個新的Pen對象(不要用預設的系統的畫筆)畫出大於一個象素點的一行。不要忘記在完成時調用Dispose方法。你應該根據邊框的寬度調整邊框矩形的大小,因為控制項不能隨意在表單以外進行繪製。

我從來不喜歡用按鈕圖象的演算法操作來顯示up、over和down狀態,每個ImageButton均用了三個單獨的位元影像。在一個form中使用許多ImageButtons會導致產生大量的圖象,因此我給ImageButton提供了一個ImageList屬性,而不是三個圖象屬性。將該屬性作為Forms.ImageList來聲明,則NET和VS.NET IDE會為你處理大量的工作。你不需要通過編寫代碼來檢測ImageList,屬性視窗會將它顯示出來。使用ImageList的另一個好處是它排除了用代碼處理使用者提供圖象大小的可能性。當使用者以不同的大小載入它時,ImageList代表的是一個單一大小和比例的圖象。

圖象的大小決定了ImageButton的大小;該控制項沒有AutoSize屬性。假如使用者試圖通過拖動控制項的邊框或通過屬性視窗來改變它的大小,則ImageButton會立即重新設定為圖象的大小。你可以通過覆蓋OnSizeChanged過程來得到該行為,你還可以用一個唯讀版本將Control類的非覆蓋Size屬性隱藏起來。這給IDE帶來了一個問題,因為他要序列化Size屬性,試著將它設定到使用者表單的"Designer generated code"地區。添加<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>屬性以避免使用者在設計時讀取它的屬性序列化時,它提供一個更友好的工具給使用者。

相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。