成人午夜激情影院,小视频免费在线观看,国产精品夜夜嗨,欧美日韩精品一区二区在线播放

用VS.NET制作功能強大的位圖按鈕控件

2010-08-28 10:50:01來源:西部e網作者:

原文(英文)http://www.codeproject.com/cs/miscctrl/XCtrls.asp

 

系統:WindowsXP   P42.2G   內存:512MB

環境:Visual Studio.NET 2003 語言:C#                                                                         源碼下載

 

在開始我們的講解之前先看一下我們位圖Button控件的效果(很漂亮吧!)如果你對這個控件感興趣的話,就跟著我們的腳步學習如何做出這樣的一個控件吧!

XCtrls1.jpg 

簡介:

       創建自定義位圖控件的目的是允許在每一種按鈕狀態下呈現不同的位圖,這些狀態包括:disabled, normal, mouse over,還有button pressed;除了按鈕的圖像,讓我們的按鈕飽含文本,并且根據按鈕圖片控制文本的對齊方式也很重要。按鈕采用XP樣式,還包含了我們定制的一些特性。

 

代碼使用:

       程序的源碼可以分為3大部分:data(數據), rendering(表現), and events(事件)

       Data:存儲狀態和設置屬性的私有變量,下表中有每一個屬性的描述。

Rendering:按鈕的呈現是靠幾個方法來實現的,OnPaint方法是調用其它繪制方法的一個驅動性質的方法(意思就是靠我們的OnPaint方法,調用自定義的繪制方法),用來呈現我們的Button控件

Events:事件處理操作按鈕的狀態這些事件有:OnMouseDown, OnMouseUp, OnMouseLeave, OnMouseMove, OnEnabledChanged, OnLostFocus.

 

Data

       首先讓我們研究一下這些屬性

      

BITMAP BUTTON PROPERTIES

BackColor

background color of the button

按鈕的背景

BorderColor

the color of the thin one pixel width border surrounding the button

圍繞著按鈕的一個像素寬的邊框的顏色

Font

font used to render the text

按鈕文本呈現的字體

ForeColor

color of button text

按鈕文本的顏色

ImageAlign

specifies the alignment of the image

指定圖像的對齊方式

ImageBorderColor

If ImageBorderEnabled is true, then this property contains the color of the rendered image border. In addition, the StretchImage property must be false

如果該屬性被設置為true,這個屬性就使得圖像邊框為設置多顏色,但是使用此屬性時,StretchImage必須設為false

ImageBorderEnabled

true if to render an image border, otherwise false

是否呈現圖像的邊框

ImageDropShadow

true, if to render a shadow around the image border

是否呈現圖像的陰影

ImageFocused

image used to render when button has focus and is in a normal state

按鈕獲得焦點并處于普通狀態時呈現的圖像

ImageInactive

image used when button is disabled. Note, if a image is not defined, a gray scale version of the normal image is used in substitution

按鈕不可用時呈現的圖像,如果沒有被設置,將呈現灰化的普通狀態的圖像

ImageMouseOver

image used when the mouse is over the button, but the button is not pressed

鼠標移到按鈕時顯示的圖片

ImageNormal

image used when the button is it its normal state. Note, this image must be set for an image button

普通狀態的按鈕呈現圖片,必須被設置

ImagePressed

image used when button is pressed

按鈕按下呈現的圖片

InnerBorderColor

color of the inner border while button is in its normal state

普通狀態按鈕內邊框的顏色

InnerBorderColor_Focus

color of the inner border when the button has focus

按鈕獲取焦點時內邊框的顏色

InnerBorderColor_MouseOver

color of the inner border when the mouse is over a button

鼠標移到按鈕上時內邊框的顏色

OffsetPressedContent

If this is set to true and the button is pressed, the contents of the button is shifted.

如果屬性設置為true,按鈕按下時替換的內容

Padding

It holds the pixel padding amount between each of the button contents. This is the space between the image, text, and border.

圖像、文本和邊框之間的距離(像素)

StretchImage

If true, it indicates to stretch the current image across the button

如果設置為true,拉伸圖像.

Text

the text to be displayed in the button

按鈕文本

TextAlignment

defines the alignment of the text

按鈕文本對齊方式

TextDropShadow

If true, the text casts a shadow

如果設置為true,文本有陰影屬性

 

所有的這些屬性都被加到屬性標簽頁了,下面是個截圖

XCtrls2.jpg
Rendering

       按鈕控件的呈現工作是OnPaint方法實現的,它輪流調用幾個方法呈現Button我們設置的狀態。

  • CreateRegion創建按鈕的圓角邊框
  • paint_Background: 繪制呈現按鈕背景
  • paint_Text: 繪制呈現按鈕文本和文本陰影
  • paint_Border繪制 1像素的按鈕邊框
  • paint_InnerBorder: 繪制 2像素的按鈕內邊框
  • paint_FocusBorder繪制 1像素的按鈕虛線焦點邊框

/// <summary>
/// This method paints the button in its entirety.
/// </summary>
/// <param name="e">paint arguments use to paint the button</param>

protected override void OnPaint(PaintEventArgs e)
{                
    CreateRegion(
0);            
    paint_Background(e);
    paint_Text(e);
    paint_Image(e);            
    paint_Border(e);
    paint_InnerBorder(e);
    paint_FocusBorder(e);
}


繪制背景應該是很有趣的:

Painting the background can be of some interest. The approach that was taken allows for a gradient background interpolation between multiple colors (meaning more then 2 colors). First, a blend object needs to be initialized with an array of colors, and the position of interpolation.  Next, the gradient brush can be created as usual. The Final step involves linking the blend object to the brush. This is accomplished by setting the InterpolationColors property of a brush.

 

下面是復合顏色的代碼示例:


   

Color[] ColorArray = new Color[]{
   System.Drawing.Color.White,
   System.Drawing.Color.Yellow,
   System.Drawing.Color.Blue,
   System.Drawing.Color.Green,               
   System.Drawing.Color.Red,
   System.Drawing.Color.Black}
;                
float[] PositionArray  = new float[]{0.0f,.15f,.40f,.65f,.80f,1.0f};
//
// create blend variable for the interpolate the colors
//
System.Drawing.Drawing2D.ColorBlend blend
                                
= new System.Drawing.Drawing2D.ColorBlend();
blend.Colors    
= ColorArray;
blend.Positions 
= PositionArray;
//
// create vertical gradient brush
//
System.Drawing.Drawing2D.LinearGradientBrush brush
                
= new System.Drawing.Drawing2D.LinearGradientBrush(rect, 
                      
this.BackColor,Blend(this.BackColor,this.BackColor,10),
                      System.Drawing.Drawing2D.LinearGradientMode.Vertical);
brush.InterpolationColors 
= blend;
//
// fill the rectangle
//
g.FillRectangle(brush, rect);
//
// release resources
//
brush.Dispose();    


   我使用了System.Drawing.DrawString()方法繪制按鈕文本,在何處使用這個方法呢,為了區別paint_Text()方法,我們將代碼放置在Helper函數部分(看源代碼大家就一目了然是什么意思了)還有一處大家一定會感興趣,就是文本的陰影效果是如何實現的呢?我們看看接下來的代碼:

//
// paint text shadow
//
if(TextDropShadow)
{
    System.Drawing.Brush TransparentBrush0
          
= new System.Drawing.SolidBrush( System.Drawing.Color.FromArgb(50
                System.Drawing.Color.Black  ) ) ;
    System.Drawing.Brush TransparentBrush1
           
= new System.Drawing.SolidBrush( System.Drawing.Color.FromArgb(20
                System.Drawing.Color.Black  ) ) ;

    e.Graphics.DrawString(
this.Text,this.Font,
                                               TransparentBrush0,pt.X,pt.Y
+1);
    e.Graphics.DrawString(
this.Text,this.Font, 
                                               TransparentBrush0,pt.X
+1,pt.Y);
            
    e.Graphics.DrawString(
this.Text,this.Font, 
                                            TransparentBrush1,pt.X
+1,pt.Y+1);    
    e.Graphics.DrawString(
this.Text,this.Font, 
                                            TransparentBrush1,pt.X,pt.Y
+2);    
    e.Graphics.DrawString(
this.Text,this.Font, 
                                            TransparentBrush1,pt.X
+2,pt.Y);    
    TransparentBrush0.Dispose();
    TransparentBrush1.Dispose();    
}


   相信不用我多解釋,大家就知道實現的原理是什么了吧,好了我們繼續。

       繪制圖像更是一個直接的過程,但是在使用下面的方法的時候,我遇到了一些問題,當他繪制一個有我們資源編輯器產生的為圖的時候確實沒有什么問題,但是當我們繪制一個由第三方程序產生的24位位圖的時候,失敗了。它必須使用另一種DrawImage方法,現在我們知道接下來需要怎么修改我們的方法了。

      

// FAILED
g.DrawImage(image,rect.Left,rect.Top)
// WORKAROUND
g.DrawImage(image,rect, 00 ,image.Width,image.Height, GraphicsUnit.Pixel);

       繪制邊框的代碼當然也不難,像前面一樣創建一個梯度畫刷對象,然后繪制的時候把這個對象當作參數傳遞進去,看下面的代碼,其實很簡單。

   

//.
//
// create brush and pens
//
System.Drawing.Drawing2D.LinearGradientBrush brush
            
= new System.Drawing.Drawing2D.LinearGradientBrush(rect,  
                  
this.BackColor,Blend(this.BackColor,this.BackColor,10), 
                  System.Drawing.Drawing2D.LinearGradientMode.Vertical);
brush.InterpolationColors 
= blend;
System.Drawing.Pen pen0 
= new System.Drawing.Pen(brush,1);
//
// draw line 0
//
g.DrawLine(pen0 , point_0,point_1);
//.


Events:

      數據成員、一些方法都簡單的陳述了,接下來看看我們的事件處理機制。按鈕的一個大的方面就是事件和捕獲與處理。我們走了個大的捷徑,那就是重載按鈕事件的方法,這些方法通過按鈕屬性直接修改按鈕的狀態。一旦狀態改變,他們就會讓控件無效,然后刷新機制重新繪制我們的Button。下面是事件方法列表和簡單說明。

 

Event Methods

Button state

OnMouseDown

Set BtnState to Pushed and Capturing mouse to true

設置Button狀態為按下,并且將捕獲鼠標屬性設為true

OnMouseUp

Set BtnState to Normal and set CapturingMouse to false

設置Button狀態為普通,并且將捕獲鼠標屬性設為false

OnMouseLeave

Set BtnState to normal if we CapturingMouse = true

設置Button狀態為普通,如果捕獲鼠標狀態屬性為true

OnMouseMove

If CapturingMouse = true and mouse coordinates are within button region, set BtnState to Pushed, otherwise set BtnState to Normal. If CapturingMouse = false, then set BtnState to MouseOver

簡單的說就是根據十分捕獲鼠標設置Button狀態

OnEnabledChanged

The button either became enabled or disabled. If button became enabled, set BtnState to Normal else set BtnState to Inactive

Button是否可用改變時的方法

OnLostFocus

Set btnState to Normal

失去焦點,把Button狀態屬性變為普通的方法

下面的代碼是一個簡單的事件處理。這里值得注意的是Capture屬性。

/// <summary>
/// Mouse Down Event:
/// set BtnState to Pushed and Capturing mouse to true
/// </summary>
/// <param name="e"></param>

protected override void OnMouseDown(MouseEventArgs e)
{
  
base.OnMouseDown (e);
  
this.Capture = true;
  
this.CapturingMouse = true;
  btnState 
= BtnState.Pushed;            
  
this.Invalidate();
}


   按鈕是否獲取焦點問題,大家知道如果這個焦點一直被設置在Button上,那其它當實際焦點改變時,我們的事件處理機制就不能按照我們的要求正常工作了。給出原文供大家參考:

The below code block shows an example of the event code. Events generally are composed of little code. One tidbit of information I should cover is the Capture property of the control. By setting this to true, the button does not lose input focus when the pointer is outside the button region. This is important because if the mouse button is held down and the user moves the mouse pointer in and out of the button region, the state of the button needs to change accordingly.  If the Capture property is not set, the control will stop capturing input events when the pointer leaves the button region.

由此展開的課題:

       這只是程序最原始的一個版本,所有代碼都在一個源文件中,以后我們可以擴展這個程序,比如預先定義好好看的樣式,從一個XML文檔加載我們主題信息,希望大家能好好利用這個程序,也希望這個程序真的能給大家帶來幫助。

 

這里有一些額外的說明:

       CodeProject這篇文章的源碼是很不錯的,值得大家研究研究,代碼其實很簡單,有這樣的思路才是重點,這樣的控件我們也完全能開發出來。

大家可以好好研究 HelperMethods,其實這些才是該控件比較精華的代碼。

但是我也發現了一個問題,該控件對設計期的支持不夠完善,具體說來就是你改變了某一個屬性,它并沒有立即在設計期反映出來,我研究了一下,發現它的屬性設置完成了都沒有這句話,前面我翻譯的一篇文章已經強調了,要想讓你的控件及時反映出屬性的變化,做出相應的反映this.Invalidate()這句話是重點,希望大家不能忽視,我已將修改好的源代碼打包,還有一個Demo程序,這樣就比較完美了。

       怎么把這個不錯的控件添加到你的ToolBox中,相信不用我再教一次了,定位到這個dll就行了;還有如何定制自己的空間圖標等等小的方面,參看我的這篇文章吧:http://www.cnblogs.com/jht/archive/2005/08/10/211650.html

關鍵詞:VS.NET
主站蜘蛛池模板: 清新县| 大竹县| 贵溪市| 辉南县| 仲巴县| 蓝田县| 睢宁县| 耿马| 台中市| 姚安县| 繁峙县| 山西省| 苗栗县| 合肥市| 文成县| 孟州市| 壶关县| 大新县| 冀州市| 治多县| 鄂温| 峨边| 大连市| 苏尼特左旗| 哈尔滨市| 新密市| 元谋县| 松潘县| 雷波县| 岳西县| 东城区| 青河县| 福贡县| 安吉县| 紫阳县| 鸡泽县| 老河口市| 如皋市| 赤峰市| 沛县| 嫩江县|