这段时间做了个小项目,需要用到一个背景透明,只显示图片和文字的Button,没有找到现成的,所以自己写了一个,主要就是重写OnPaint事件
下面是这个Button的代码,
其中,是否有选中状态是指按钮按下之后是否有类似于菜单的那中选中状态,同级别之间是否互斥是指当同一空间内有多个Button时,点击某一个是否取消其他按钮的选中状态
1 /***********************Created By Liushufeng 2011-08-18********************/ 2 using System; 3 using System.Collections.Generic; 4 using System.Text; 5 using System.Windows.Forms; 6 using System.Drawing; 7 using System.ComponentModel; 8 using System.Drawing.Drawing2D; 9 10 namespace OurControls 11 { 12 public class OurButton : Label 13 { 14 private bool isMouseIn; 15 16 private bool isMouseDown; 17 18 private bool withBorder = true; 19 20 private bool roundCorner = true; 21 22 private bool withArrow = true; 23 24 private int intervalBetweenTextAndBorder = 2; 25 26 private int intervalBetweenTextAndImage = 2; 27 28 private Color colorMouseIn = Color.White; 29 30 private Color colorMouseDown = Color.White; 31 32 private bool haveCheckState = true; 33 34 private bool exclusion = true; 35 36 private eTextPosition textPosition = eTextPosition.Bottom; 37 38 [CategoryAttribute("文字位置"), Browsable(true), DisplayName("文字位置"), DescriptionAttribute("文字位置")] 39 public eTextPosition TextPosition 40 { 41 get { return textPosition; } 42 set 43 { 44 textPosition = value; 45 this.Invalidate(); 46 } 47 } 48 49 [CategoryAttribute("绘制边框"), Browsable(true), DisplayName("绘制边框"), DescriptionAttribute("绘制边框")] 50 public bool WithBorder 51 { 52 get { return withBorder; } 53 set 54 { 55 withBorder = value; 56 this.Invalidate(); 57 } 58 } 59 60 [CategoryAttribute("圆角"), Browsable(true), DisplayName("圆角"), DescriptionAttribute("圆角")] 61 public bool RoundCorner 62 { 63 get { return roundCorner; } 64 set 65 { 66 roundCorner = value; 67 this.Invalidate(); 68 } 69 } 70 71 [CategoryAttribute("带向下的剪头"), Browsable(true), DisplayName("带向下的剪头"), DescriptionAttribute("带向下的剪头")] 72 public bool WithArrow 73 { 74 get { return withArrow; } 75 set 76 { 77 withArrow = value; 78 this.Invalidate(); 79 } 80 } 81 82 [CategoryAttribute("文字与图像之间的间隔"), Browsable(true), DisplayName("文字与图像之间的间隔"), DescriptionAttribute("文字与图像之间的间隔")] 83 public int IntervalBetweenTextAndImage 84 { 85 get { return intervalBetweenTextAndImage; } 86 set 87 { 88 intervalBetweenTextAndImage = value; 89 this.Invalidate(); 90 } 91 } 92 93 [CategoryAttribute("文字与边框之间的间隔"), Browsable(true), DisplayName("文字与边框之间的间隔"), DescriptionAttribute("文字与边框之间的间隔")] 94 public int IntervalBetweenTextAndBorder 95 { 96 get { return intervalBetweenTextAndBorder; } 97 set 98 { 99 intervalBetweenTextAndBorder = value; 100 this.Invalidate(); 101 } 102 } 103 104 [CategoryAttribute("鼠标悬停时的背景色"), Browsable(true), DisplayName("鼠标悬停时的背景色"), DescriptionAttribute("鼠标悬停时的背景色")] 105 public Color ColorMouseIn 106 { 107 get { return colorMouseIn; } 108 set { colorMouseIn = value; } 109 } 110 111 [CategoryAttribute("选中状态的背景色"), Browsable(true), DisplayName("选中状态的背景色"), DescriptionAttribute("选中状态的背景色")] 112 public Color ColorMouseDown 113 { 114 get { return colorMouseDown; } 115 set { colorMouseDown = value; } 116 } 117 118 [CategoryAttribute("是否有选中状态"), Browsable(true), DisplayName("是否有选中状态"), DescriptionAttribute("是否有选中状态")] 119 public bool CheckState 120 { 121 get { return haveCheckState; } 122 set { haveCheckState = value; } 123 } 124 125 [CategoryAttribute("同级别之间是否互斥"), Browsable(true), DisplayName("同级别之间是否互斥"), DescriptionAttribute("同级别之间是否互斥")] 126 public bool Exclusion 127 { 128 get { return exclusion; } 129 set { exclusion= value; } 130 } 131 132 protected override void OnClick(EventArgs e) 133 { 134 base.OnClick(e); 135 if (CheckState) 136 { 137 isMouseDown = true; 138 if (exclusion) 139 { 140 if (this.Parent != null) 141 { 142 143 int ctlCount = this.Parent.Controls.Count; 144 for (int i = 0; i < ctlCount; i++) 145 { 146 object o = this.Parent.Controls[i]; 147 if (o.GetType() == this.GetType()) 148 { 149 OurButton button = this.Parent.Controls[i] as OurButton; 150 if (button != null) 151 { 152 if (button != this) 153 { 154 button.PopUp(); 155 } 156 } 157 } 158 } 159 } 160 } 161 } 162 } 163 164 private void PopUp() 165 { 166 this.isMouseDown = false; 167 this.Invalidate(); 168 } 169 170 public override bool AutoSize 171 { 172 get 173 { 174 return false; 175 } 176 set 177 { 178 base.AutoSize = value; 179 } 180 } 181 182 protected override void OnPaint(PaintEventArgs e) 183 { 184 Graphics g = e.Graphics; 185 g.SmoothingMode = SmoothingMode.HighQuality; 186 float imagex = 0; 187 float imagey = 0; 188 float tx = 0; float ty = 0; 189 float txtHeight = 0; 190 float txtWidth = 0; 191 192 #region 绘制背景 193 194 if (isMouseIn || isMouseDown ) 195 { 196 Color c = colorMouseIn; 197 if (isMouseDown) 198 { 199 c = colorMouseDown; 200 } 201 int arrowHeight = 7; 202 if (!withArrow) 203 arrowHeight = 0; 204 Rectangle rect = new Rectangle(0, 0, this.Width, this.Height - arrowHeight ); 205 Rectangle rect2 = new Rectangle(0, 0, this.Width - 1, this.Height - arrowHeight); 206 207 GraphicsPath path1 = null; 208 GraphicsPath path2 = null; 209 if (roundCorner) 210 { 211 if (withArrow) 212 { 213 path1 = GetRoundRectangleWithArrow(rect, 10); 214 path2 = GetRoundRectangleWithArrow(rect2, 10); 215 } 216 else 217 { 218 path1 = GetRoundRectangle(rect, 10); 219 path2 = GetRoundRectangle(rect2, 10); 220 } 221 g.FillPath(new SolidBrush(c), path1); 222 if (withBorder) 223 g.DrawPath(new Pen(Color.Silver, 2), path2); 224 } 225 else 226 { 227 g.FillRectangle(new SolidBrush(c), rect); 228 g.DrawRectangle(new Pen(c, 2), rect2); 229 } 230 } 231 232 #endregion 233 234 #region 绘制文本 235 236 if (this.Text != string.Empty) 237 { 238 SizeF sizeoftext = g.MeasureString(this.Text, Font); 239 txtHeight = (float)(sizeoftext.Height); 240 txtWidth = (float)(sizeoftext.Width); 241 switch (TextPosition) 242 { 243 case eTextPosition.Top: 244 tx = (float)((this.Width - sizeoftext.Width) / 2.0); 245 ty = intervalBetweenTextAndBorder; 246 break; 247 case eTextPosition.Left: 248 ty = (float)((this.Height - sizeoftext.Height) / 2.0); 249 tx = intervalBetweenTextAndBorder; 250 break; 251 case eTextPosition.Right: 252 if (Image == null) 253 tx = this.Width - sizeoftext.Width - intervalBetweenTextAndBorder; 254 else 255 tx = intervalBetweenTextAndBorder + Image.Width + intervalBetweenTextAndImage; 256 ty = (float)((this.Height - sizeoftext.Height) / 2.0); 257 break; 258 case eTextPosition.Bottom: 259 if (Image != null) 260 ty = intervalBetweenTextAndBorder + intervalBetweenTextAndImage + Image.Height; 261 else 262 ty = IntervalBetweenTextAndBorder; 263 tx = (float)((this.Width - txtWidth) / 2.0); 264 break; 265 } 266 g.DrawString(this.Text, Font, new SolidBrush(ForeColor), tx, ty); 267 268 } 269 270 #endregion 271 272 #region 绘制图片 273 274 if (Image != null) 275 { 276 switch (TextPosition) 277 { 278 case eTextPosition.Top: 279 imagex = (float)((this.Width - Image.Width) / 2.0); 280 imagey = ty + txtHeight + intervalBetweenTextAndImage; 281 break; 282 case eTextPosition.Left: 283 imagex = tx + txtWidth + intervalBetweenTextAndImage; 284 imagey = (float)((this.Height - Image.Height) / 2.0); 285 break; 286 case eTextPosition.Right: 287 imagex = IntervalBetweenTextAndBorder; 288 imagey = (float)((this.Height - Image.Height) / 2.0); 289 break; 290 case eTextPosition.Bottom: 291 imagey = intervalBetweenTextAndBorder; 292 imagex = (float)((this.Width - Image.Width) / 2.0); 293 break; 294 } 295 g.DrawImage(Image, imagex, imagey); 296 } 297 298 #endregion 299 300 } 301 302 protected override void OnMouseEnter(EventArgs e) 303 { 304 base.OnMouseEnter(e); 305 isMouseIn = true; 306 this.Invalidate(); 307 } 308 309 protected override void OnMouseLeave(EventArgs e) 310 { 311 base.OnMouseLeave(e); 312 isMouseIn = false; 313 this.Invalidate(); 314 } 315 316 private GraphicsPath GetRoundRectangle(Rectangle rectangle, int r) 317 { 318 int l = 2 * r; 319 // 把圆角矩形分成八段直线、弧的组合,依次加到路径中 320 GraphicsPath gp = new GraphicsPath(); 321 gp.AddLine(new Point(rectangle.X + r, rectangle.Y), new Point(rectangle.Right - r, rectangle.Y)); 322 gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Y, l, l), 270F, 90F); 323 324 gp.AddLine(new Point(rectangle.Right, rectangle.Y + r), new Point(rectangle.Right, rectangle.Bottom - r)); 325 gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Bottom - l, l, l), 0F, 90F); 326 327 gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), new Point(rectangle.X + r, rectangle.Bottom)); 328 gp.AddArc(new Rectangle(rectangle.X, rectangle.Bottom - l, l, l), 90F, 90F); 329 330 gp.AddLine(new Point(rectangle.X, rectangle.Bottom - r), new Point(rectangle.X, rectangle.Y + r)); 331 gp.AddArc(new Rectangle(rectangle.X, rectangle.Y, l, l), 180F, 90F); 332 return gp; 333 } 334 335 private GraphicsPath GetRoundRectangleWithArrow(Rectangle rectangle, int r) 336 { 337 int l = 2 * r; 338 // 把圆角矩形分成八段直线、弧的组合,依次加到路径中 339 GraphicsPath gp = new GraphicsPath(); 340 gp.AddLine(new Point(rectangle.X + r, rectangle.Y), new Point(rectangle.Right - r, rectangle.Y)); 341 gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Y, l, l), 270F, 90F); 342 343 gp.AddLine(new Point(rectangle.Right, rectangle.Y + r), new Point(rectangle.Right, rectangle.Bottom - r)); 344 gp.AddArc(new Rectangle(rectangle.Right - l, rectangle.Bottom - l, l, l), 0F, 90F); 345 346 347 int miniwidth = 5; 348 int miniheight = 6; 349 //这是下面的一条线,把它分成四份 350 // gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), ); 351 //1 352 gp.AddLine(new Point(rectangle.Right - r, rectangle.Bottom), new Point(rectangle.Width / 2 + miniwidth, rectangle.Bottom)); 353 //2 354 gp.AddLine(new Point(rectangle.Width / 2 + miniwidth, rectangle.Bottom), new Point(rectangle.Width / 2, rectangle.Bottom + miniheight)); 355 //3 356 gp.AddLine(new Point(rectangle.Width / 2, rectangle.Bottom + miniheight), new Point(rectangle.Width / 2 - miniwidth, rectangle.Bottom)); 357 358 //4 359 gp.AddLine(new Point(rectangle.Width / 2 - miniwidth, rectangle.Bottom), new Point(rectangle.X + r, rectangle.Bottom)); 360 361 gp.AddArc(new Rectangle(rectangle.X, rectangle.Bottom - l, l, l), 90F, 90F); 362 363 gp.AddLine(new Point(rectangle.X, rectangle.Bottom - r), new Point(rectangle.X, rectangle.Y + r)); 364 gp.AddArc(new Rectangle(rectangle.X, rectangle.Y, l, l), 180F, 90F); 365 return gp; 366 } 367 368 } 369 370 public enum eTextPosition 371 { 372 Top, 373 Left, 374 Right, 375 Bottom, 376 } 377 378 }
下面是按钮的效果: