65.9K
CodeProject 正在变化。 阅读更多。
Home

一个简单的位图按钮实现

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.63/5 (15投票s)

2003年7月3日

4分钟阅读

viewsIcon

174321

downloadIcon

2487

一个小的类,为WinForms提供纯位图按钮功能。

Sample Image - screenshot.jpg

引言

经过一番小小的搜索,似乎没有人为Code Project(或其他任何地方)写过BitmapButton。WiB出色的XP风格按钮控件解决了带图标的XP风格按钮的问题。但是,如果你想完全控制按钮的外观,无论操作系统、清单、主题等,都使用位图呢?这个控件提供了这个能力。请注意,这个类非常基础——我并没有努力使其在窗体设计器中可用。如果有人想更新代码并具备此能力,我非常乐意让他们成为合著者。

使用BitmapButton

指定按钮状态图像

 BitmapButton类使用一个单一的位图,该位图包含一个或多个图像,每个图像代表按钮的五种状态之一。图像必须从左到右连续放置。例如:

代表一个有五种状态的按钮的位图

  1. up
  2. down
  3. 获得焦点
  4. 鼠标悬停
  5. disabled

初始化BitmapButton

按钮以通常的方式初始化,并添加一行代码来指定位图文件:

bitmapButton=new BitmapButton();
bitmapButton.Location=new Point(232, 32);
bitmapButton.Size=new Size(32, 32);
bitmapButton.TabIndex=0;
bitmapButton.Text="&Down";
bitmapButton.Image=new Bitmap("downArrow.bmp");

三个重要提示

  1. Text字段仅用于指定按钮的键盘快捷方式;
  2. 按钮的宽度应与位图中单个图像的宽度相同(所有图像的宽度和高度应相同);
  3. 按钮的高度应与位图的高度相同。

就这样。(如果你忘记了图像,程序将抛出异常)。

幕后

按钮状态

考虑到键盘和鼠标的双用户界面,按钮状态是一件复杂的事情。例如,用户可能将鼠标悬停在按钮上,但正在使用Tab键在控件之间导航。完整的状态图如下所示:

此图代表了在使用鼠标和键盘时必须考虑的状态转换。这相当复杂!

使用键盘的按钮状态

如果使用键盘,状态图会更简单(为了清晰起见,已移除“禁用”状态):

使用鼠标的按钮状态

如果使用鼠标,状态图中有一些缺失的状态转换(同样,为了清晰起见,已移除“禁用”状态):

事件处理程序

为了管理可能发生的所有事件并正确地在不同状态之间转换,必须定义几个事件处理程序:

Paint+=new PaintEventHandler(BitmapButton_Paint);
MouseDown+=new MouseEventHandler(BitmapButton_MouseDown);
MouseUp+=new MouseEventHandler(BitmapButton_MouseUp);
GotFocus+=new EventHandler(BitmapButton_GotFocus);
LostFocus+=new EventHandler(BitmapButton_LostFocus);
MouseEnter+=new EventHandler(BitmapButton_MouseEnter);
MouseLeave+=new EventHandler(BitmapButton_MouseLeave);
KeyDown+=new KeyEventHandler(BitmapButton_KeyDown);
KeyUp+=new KeyEventHandler(BitmapButton_KeyUp);
EnabledChanged+=new EventHandler(BitmapButton_EnabledChanged);
Paint 负责以其各种状态绘制按钮。
MouseDown 转换到“已单击”状态。
MouseUp 转换到“获得焦点”状态。
GotFocus 转换到“获得焦点”状态(例如,通过键盘获得焦点)。
LostFocus 转换到“按钮释放”或“鼠标悬停”状态。
MouseEnter 如果处于“按钮释放”状态,则转换为“鼠标悬停”状态。
MouseLeave 如果处于“鼠标悬停”状态,则转换为“按钮释放”状态。
KeyDown 当用户在按钮获得焦点时按下空格键时,转换到“已单击”状态。
KeyUp 当用户在按钮获得焦点时释放空格键时,转换到“获得焦点”状态。
EnabledChanged  当按钮的Enabled状态改变时,转换为“禁用”状态或返回“按钮释放”状态。

绘制图像

虽然不需要双缓冲,因为整个状态图像都绘制在按钮表面上,但还是实现了它,以防控件被增强以包含额外的绘图效果。双缓冲通过SetStyle方法指定,该方法是一个受保护的成员,因为有人决定,由于控件将拥有自己的Paint处理程序,因此不应在不继承控件的情况下进行设置。不过,Paint事件处理程序可以在一个完全独立的类中实现!

SetStyle(ControlStyles.UserPaint |
              ControlStyles.AllPaintingInWmPaint |
              ControlStyles.DoubleBuffer, true);
按钮图像显示在Paint事件处理程序中。根据状态,它确定所需图像的索引。位图不需要包含所有图像状态,只要提供的图像状态是连续的(也就是说,你不能拥有按钮按下、按钮释放和禁用图像状态,而焦点和鼠标悬停状态为空——如果你想要禁用状态的图像,那么你也必须提供所有其他状态的图像)。
private void BitmapButton_Paint(object sender, PaintEventArgs e)
{
    Graphics gr=e.Graphics;
    int indexWidth=Size.Width*(int)imgState;

    if (Image.Width > indexWidth)
    {
        gr.DrawImage(Image, 0, 0,
                     new Rectangle(new Point(indexWidth, 0), Size),
                     GraphicsUnit.Pixel);
    }
    else
    {
        gr.DrawImage(Image, 0, 0,
                     new Rectangle(new Point(0, 0),
                     new Size(Size.Width, Size.Height)),
                     GraphicsUnit.Pixel);
    }
}

结论

哇,这可能是我近年来写过的最短的文章之一!位图按钮可以比我在这里实现的复杂得多。例如,如果你的图像没有边框,而你希望控件自己生成3D风格的边框怎么办?还有对不同按钮状态大小和透明度的考虑,例如。希望本文能为读者提供定制位图控件以满足其需求的依据。

 

© . All rights reserved.