使用c#自定义位图按钮
介绍 自定义位图控件背后的动机是允许为每个按钮状态显示不同的位图图像。这包括禁用、正常、鼠标移动和按下按钮。除了按钮图形之外,包含按钮文本并控制文本对按钮图像的对齐也是很重要的。它遵循XP风格的外观和感觉,并有一些独特的装饰。 使用的代码 代码可以分为3个主要部分:数据、呈现和事件。 数据:私有变量保存状态和属性设置。在大多数情况下,这段代码遵循属性引用或更改成员变量值的实践。每个属性在下面的属性表中进行了描述。渲染:按钮的渲染通过几种方法进行;然而,OnPaint方法是为按钮渲染调用其他绘制方法的驱动程序。事件:覆盖了许多方法来处理事件处理和管理按钮的状态。方法是OnMouseDown, OnMouseUp, OnMouseLeave, OnMouseMove, OnEnabledChanged, OnLostFocus。 当查看源代码时,可以很容易地找到这些节,因为#region关键字用于代码分离。 数据 首先,让我们探讨一下属性。 Bitmap 按钮属性 按钮的背景色背景颜色bordercolor薄一个像素宽度的颜色边界周围的按钮字体字体用来渲染按钮文本的文本字体颜色颜色imagealign指定图像的对齐imagebordercolor如果ImageBorderEnabled是真的,那么这个属性包含的颜色渲染后的图像边界。此外,StretchImage属性必须为假。imageborderenabled true如果渲染一个图像边界,否则false imagedropshadow true,如果渲染一个阴影周围的图像边界,imagefocused图像用于渲染时,按钮有焦点和在正常状态,imageinactive图像时,按钮禁用。注意,如果图像未定义,则使用正常图像的灰度版本来替代当鼠标在按钮上时使用的imagemouseover图像,但当按钮处于其正常状态时未按下imagenormal图像。注意,这个形象必须设置为图像按钮imagepressed图像按钮被按下时使用innerbordercolor内部边界的颜色按钮是在其正常状态innerbordercolor_focus内部边界的颜色当按钮焦点innerbordercolor_mouseover内部边界的颜色当鼠标在按钮offsetpressedcontent如果这是设置为true,按钮被按下,按钮的内容发生了变化。它保存每个按钮内容之间的像素填充量。这是图像、文本和边框之间的空间。如果为真,则指示将当前图像拉伸到按钮上。文本将在按钮textalignment定义了文本的对齐方式如果为真,文本会投射阴影 所有属性都已添加到属性页中的appearance类别中。下面的图片是他们的快照。 呈现 按钮的呈现由OnPaint方法执行。这依次调用几个例程来处理按钮的呈现细节。 CreateRegion:创建一个透明的圆形按钮控制paint_background边缘:显示按钮的背景paint_text:呈现的文本和文本阴影paint_border:呈现1像素与边框按钮paint_innerborder:呈现2像素宽度内边界paint_focusborder:呈现1像素宽度冲焦点边界内的按钮 详情请参阅下面的代码片段: 隐藏,复制Code
/// <summary> /// This method paints the button in its entirety. /// </summary> /// <paramname="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); }
画背景可能会很有趣。所采取的方法允许在多个颜色(意味着超过两种颜色)之间进行梯度背景插值。首先,混合对象需要初始化一个颜色数组,以及插值的位置。接下来,可以像往常一样创建渐变笔刷。最后一步是将混合对象连接到画笔。这是通过设置画笔的内插颜色属性来完成的。 下面是一个例子,插值多种颜色: 隐藏,收缩,复制Code
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。拉带的方法。棘手的部分是决定在哪里绘制文本。由于代码太多,所以将该功能放在helper函数中,以防止它干扰paint_Text方法。这个方法的一个有趣之处在于它实现了投影功能。这仅仅涉及到创造ing笔刷与阿尔法组件,并绘制文本照常。 隐藏,复制Code
// // 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方法。它可能会慢一些,但在我理解问题是什么之前,它必须暂时起作用。 隐藏,复制Code
// FAILED g.DrawImage(image,rect.Left,rect.Top) // WORKAROUND g.DrawImage(image,rect, 0, 0 ,image.Width,image.Height, GraphicsUnit.Pixel);
用插值的颜色画边界也不困难。你可以像以前一样创建一个渐变笔刷。当创建pen对象时,渐变笔刷作为参数传递。下面的代码片段就是这个过程的一个示例。 隐藏,复制Code
.... // // 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); ....
事件 对该图像的数据和绘制作了简要描述。按钮的下一个重要方面是输入捕获和处理。所采用的方法涉及覆盖基按钮类中的方法。这些方法然后通过属性直接更改按钮的状态。一旦状态被改变,它们就会使控件失效,从而让OnPaint()机制刷新图像。下面是事件方法的列表,以及它们的目的: 事件方法按钮状态onmousedown设置BtnState推和CapturingMouse真正onmouseup BtnState正常和CapturingMouse为false onmouseleave集合BtnState正常如果我们CapturingMouse = true onmousemove CapturingMouse = true和鼠标坐标内按钮区域,设置BtnState推,否则设置BtnState正常。 如果CapturingMouse = false,则将BtnState设置为鼠标悬停 onenabledchanged按钮变为启用或禁用。如果按钮启用,则设置BtnState为Normal,否则设置BtnState为inactive 下面的代码块显示了事件代码的示例。事件通常由小代码组成。我应该介绍的一个小信息是控件的捕获属性。通过将此设置为true,当指针在按钮区域之外时,按钮不会丢失输入焦点。这一点很重要,因为如果按住鼠标按钮并且用户将鼠标指针移进或移出按钮区域,则按钮的状态需要相应地更改。如果没有设置Capture属性,则当指针离开按钮区域时,控件将停止捕获输入事件。 隐藏,复制Code
/// <summary> /// Mouse Down Event: /// set BtnState to Pushed and Capturing mouse to true /// </summary> /// <paramname="e"></param> protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown (e); this.Capture = true; this.CapturingMouse = true; btnState = BtnState.Pushed; this.Invalidate(); }
包装的事情了… 这是该控件的第一次具体化,整个源代码都在一个名为BitmapButton.cs的文件中。稍后,如果时间允许并且控件令人感兴趣,源代码可以使用接口来将功能的不同方面组件化,并增强可扩展性和可维护性。如果能包含主题并从XML源访问它们就好了。图像的缓存(双缓冲)也是一个选项。我期待建议,并希望位图控件满足您的需要或提供一些想法,您的控件。 历史 版本日期更改为1.0 02-27-2005控件的初始发布 许可证 本文没有附带明确的许可,但可能包含文章文本或下载文件本身的使用条款。如果有疑问,请通过下面的讨论区联系作者。可以在这里找到作者可能使用的许可证列表。 本文转载于:http://www.diyabc.com/frontweb/news499.html