winform自定义控件:imagebutton(转)

author author     2022-08-29     444

关键词:

原文地址:https://www.codeproject.com/Articles/29010/WinForm-ImageButton

 

自定义winfrom图片按钮:支持鼠标正常、悬停、按下更改图片,支持文本。

首先,创建没有按钮文本的图片,这样的:

正常:技术分享      悬停:技术分享       按下:技术分享

添加ImageButton控件并设置图像属性,然后设置文本Text,设置字体Font。

 

1.创建ImageButton类,重写PictureBox控件,实现IButtonControl接口。

实现IButtonControl接口,将允许ImageButton按钮与窗体上的任何其他按钮一起使用,作为默认按钮或取消按钮。

 public class ImageButton : PictureBox, IButtonControl

2.鼠标方法

思路很简单。就是创建一个图片显示在屏幕上,如果用户将鼠标停留在图片上,就会切换图片到HoverImage,

鼠标按下就会切换图片到DownImage。

  2.1 设置属性

        private bool hover = false;
        private bool down = false;

        #region HoverImage
        private Image m_HoverImage;
        [Category("Appearance")]
        [Description("Image to show when the button is hovered over.")]
        public Image HoverImage
        {
            get { return m_HoverImage; }
            set { m_HoverImage = value; if (hover) Image = value; }
        }
        #endregion

        #region DownImage
        private Image m_DownImage;
        [Category("Appearance")]
        [Description("Image to show when the button is depressed.")]
        public Image DownImage
        {
            get { return m_DownImage; }
            set { m_DownImage = value; if (down) Image = value; }
        }
        #endregion

        #region NormalImage
        private Image m_NormalImage;
        [Category("Appearance")]
        [Description("Image to show when the button is not in any other state.")]
        public Image NormalImage
        {
            get { return m_NormalImage; }
            set { m_NormalImage = value; if (!(hover || down)) Image = value; }
        }
        #endregion

  2.2 重写OnMouseMove事件

当鼠标移动到ImageButton上时调用OnMouseMove。避免使用OnMouseHover,因为这个方法会延迟调用。

设置hover=true,表示鼠标悬停在ImageButton上,

然后判断down的值,down=true时,设置按钮图片为DownImage;down=false时,设置按钮图片为HorverImage。

        protected override void OnMouseMove(MouseEventArgs e)
        {
            hover = true;
            if (down)
            {
                if ((m_DownImage != null) && (Image != m_DownImage))
                    Image = m_DownImage;
            }
            else
                if (m_HoverImage != null)
                    Image = m_HoverImage;
                else
                    Image = m_NormalImage;
            base.OnMouseMove(e);
        }

   2.3 重写OnMouseLeave事件

 如果鼠标已经离开ImageButton的边界,设置hover=false。然后切换图片为NormalImage。

        protected override void OnMouseLeave(EventArgs e)
        {
            hover = false;
            Image = m_NormalImage;
            base.OnMouseLeave(e);
        }

   2.4 重写OnMouseDown事件

如果鼠标按下控件,我们将焦点转移到ImageButton上(这不是默认行为,需要实现),

然后设置down为true,并切换图片为DownImage。

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.Focus();
            down = true;
            if (m_DownImage != null)
                Image = m_DownImage;
            base.OnMouseDown(e);
        }

  2.5 重写OnMouseUp事件

当鼠标不再被按下,设置down为false。

如果鼠标悬停在ImageButton上,切换图片为HoverImage。

如果鼠标离开ImageButton,切换图片为NormalImage。

        protected override void OnMouseUp(MouseEventArgs e)
        {
            down = false;
            if (hover)
            {
                if (m_HoverImage != null)
                    Image = m_HoverImage;
            }
            else
                Image = m_NormalImage;
            base.OnMouseUp(e);
        }

3.空值

你应该注意到,我们在切换图片之前会检查HoverImage和DowmImage是否为空,而NormalImage不用检查,这是为什么呢?

这是为了防止当NormalImage没有指定图片,而HoverImage和DowmImage有图片时,显示图片出来。

4.文本

PictureBox控件继承了Control类,而Control类具有Text和Font属性,

所以Text和Font属性没有实现,而是隐藏在属性里。

我们可以改变这一点,使文本呈现:

  4.1 重写Text属性和Font属性

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        [Description("The text associated with the control.")]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
            }
        }

        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Category("Appearance")]
        [Description("The font used to display text in the control.")]
        public override Font Font
        {
            get
            {
                return base.Font;
            }
            set
            {
                base.Font = value;
            }
        }

 

  4.2 重写方法:绘制文本

    OnPaint

由于ImageButton继承的PictureBox控件不会呈现文本,我们必须添加代码来绘制按钮上的文本。

OnPain可以处理图像的绘制和其他。然后根据Text的大小,与ImageButton大小比较,找到开始绘制文本的位置。

    OnTextChanged

当控件文本改变时,我们必须重新绘制控件。

因此重写OnTextChanged方法,并调用Refresh方法,该方法重新绘制了该按钮(Refresh方法继承自PictureBox)。

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            if ((!string.IsNullOrEmpty(Text)) && (pe != null) && (base.Font != null))
            {
                SolidBrush drawBrush = new SolidBrush(base.ForeColor);
                SizeF drawStringSize = pe.Graphics.MeasureString(base.Text, base.Font);
                PointF drawPoint;
                if (base.Image != null)
                    drawPoint = new PointF(base.Image.Width / 2 - drawStringSize.Width / 2, base.Image.Height / 2 - drawStringSize.Height / 2);
                else
                    drawPoint = new PointF(base.Width / 2 - drawStringSize.Width / 2, base.Height / 2 - drawStringSize.Height / 2);
                pe.Graphics.DrawString(base.Text, base.Font, drawBrush, drawPoint);
            }
        }

        protected override void OnTextChanged(EventArgs e)
        {
            Refresh();
            base.OnTextChanged(e);
        }

 5.隐藏属性

对于一些继承了PictureBox,而对ImageButton不是很有用的属性,我们希望它们从Property窗口隐藏起来。

为了做到这一点,我们使用了与Text和Font属性相反的处理。

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image Image { get { return base.Image; } set { base.Image = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new ImageLayout BackgroundImageLayout { get { return base.BackgroundImageLayout; } set { base.BackgroundImageLayout = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image BackgroundImage { get { return base.BackgroundImage; } set { base.BackgroundImage = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new String ImageLocation { get { return base.ImageLocation; } set { base.ImageLocation = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image ErrorImage { get { return base.ErrorImage; } set { base.ErrorImage = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Image InitialImage { get { return base.InitialImage; } set { base.InitialImage = value; } }

        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool WaitOnLoad { get { return base.WaitOnLoad; } set { base.WaitOnLoad = value; } }

 6.说明变更

SizeMode和BorderStyle属性描述提到的是pictureBox,而不是ImageButton。下面的代码会改变属性的Description。

        [Description("Controls how the ImageButton will handle image placement and control sizing.")]
        public new PictureBoxSizeMode SizeMode { get { return base.SizeMode; } set { base.SizeMode = value; } }

        [Description("Controls what type of border the ImageButton should have.")]
        public new BorderStyle BorderStyle { get { return base.BorderStyle; } set { base.BorderStyle = value; } }

 7.实现IButtonControl

我们也要实现IButtonControl,很简单,我们所要做的就是实现这些方法:

        private bool isDefault = false;

        private DialogResult m_DialogResult;
        public DialogResult DialogResult
        {
            get
            {
                return m_DialogResult;
            }
            set
            {
                m_DialogResult = value;
            }
        }

        public void NotifyDefault(bool value)
        {
            isDefault = value;
        }

        public void PerformClick()
        {
            base.OnClick(EventArgs.Empty);
        }

 8.键盘方法

我们必须实现键盘事件,以便用户可以使用空格键和输入键“点击”按钮。

如果它是一个key up或key down事件,我们会将消息发送到控件。如果是,我们检查它是什么键。如果是输入键,我们只需调用点击事件。

如果是空格键,则按住按钮直到:

  1. 用户放开空格键,在这种情况下,我们执行点击或 
  2. 用户按Escape,Tab或控件丢失焦点,在这种情况下,我们不调用点击事件

如果不是空格键,而不是输入键,我们让PictureBox基类方法处理消息。

private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private bool holdingSpace = false;
public override bool PreProcessMessage(ref Message msg)
{
    if (msg.Msg == WM_KEYUP)
    {
        if (holdingSpace)
        {
            if ((int)msg.WParam == (int)Keys.Space)
            {
                OnMouseUp(null);
                PerformClick();
            }
            else if ((int)msg.WParam == (int)Keys.Escape
                || (int)msg.WParam == (int)Keys.Tab)
            {
                holdingSpace = false;
                OnMouseUp(null);
            }
        }
        return true;
    }
    else if (msg.Msg == WM_KEYDOWN)
    {
        if ((int)msg.WParam == (int)Keys.Space)
        {
            holdingSpace = true;
            OnMouseDown(null);
        }
        else if ((int)msg.WParam == (int)Keys.Enter)
        {
            PerformClick();
        }
        return true;
    }
    else
        return base.PreProcessMessage(ref msg);
}
protected override void OnLostFocus(EventArgs e)
{
    holdingSpace = false;
    OnMouseUp(null);
    base.OnLostFocus(e);
}

9.演示程序

技术分享

 

wpf自定义按钮

...义控件(CustomControl)的方式对Button控件进行封装。其中ImageButton.xaml为默认控件模板,ImageButton.cs为控件的逻辑控制文件,其中包含了ImageButton控件所需要的新的依赖属性,包括图片源属性等。        ... 查看详情

自定义 Winforms 设计器控件同时缩放和平移控件

】自定义Winforms设计器控件同时缩放和平移控件【英文标题】:ZoomandPancontrolssimultaneouslyforacustomWinformsdesignercontrol【发布时间】:2021-10-1514:59:00【问题描述】:我正在尝试在winforms中创建一个“设计师”。这将向用户呈现一个所见... 查看详情

winform自定义控件中其他遮挡控件点击事件(代码片段)

自定义控件在其他窗口调用时,里面的lable阻挡了控件的点击事件解决方法自定义控件中lable的 点击事件privatevoidLable1_Click(objectsender,EventArgse)base.OnClick(e);//触发控件点击事件  查看详情

c#winform制作自定义控件

在winform中,我想制作一个自定义的控件,自定义的控件里就一个label控件和一个panel控件,想实现的其实就是一个有标题的panel容器。请问怎么为自定义的控件添加属性和事件,如添加一个Txt属性用来设定label的值。还有一个问题... 查看详情

使用自定义 WinForms 控件,我可以更改嵌套控件停靠在里面的矩形吗?

】使用自定义WinForms控件,我可以更改嵌套控件停靠在里面的矩形吗?【英文标题】:WithacustomWinFormscontrol,canIchangetherectanglethatnestedcontrolsdockinside?【发布时间】:2016-02-1719:01:57【问题描述】:我正在尝试创建一个行为类似于GroupBo... 查看详情

winform自定义控件基础

1.设置图像和文字以抗锯齿的方式呈现1g.SmoothingMode=SmoothingMode.AntiAlias;2g.TextRenderingHint=TextRenderingHint.AntiAlias; 2.指定区域绘图(常见于OnPaint函数中:g.DrawImage(...))1//参数:2//image:3//要绘制的System.Drawing.Image。4// 查看详情

winform自定义自动完成控件(代码片段)

...,很多优秀的前端框架都会带有自动完成控件,同样的,winform也有,在我们的TextBox和ComboBox中,只需要设置AutoCompleteSource属性为CustomSource,然后将值加入到AutoCompleteCustomSource中就可以了  比如:  string[]dataSource=newstring[]"appl... 查看详情

需要 C# Winforms 自定义 WebBrowser 控件

】需要C#Winforms自定义WebBrowser控件【英文标题】:C#WinformsCustomWebBrowserControlNeeded【发布时间】:2011-04-2816:10:09【问题描述】:我最近一直在网上搜索一个现有的控件,该控件的作用类似于网络浏览器控件,具有一些我需要的特定... 查看详情

winform日历控件

 分享一个漂亮的winform自定义控件,做考勤、日程管理、计划最好的自定义控件了,能够添加备注等等。 查看详情

wpf使用winform自定义控件(代码片段)

...引用WindowsFormsIntegration.dllSystem.Windows.Forms.dll2、在要使用WinForm控件的WPF窗体的XAML文件中添加如下内容:xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration... 查看详情

自定义 WinForms ErrorProvider 以在控件条目中显示其图标

】自定义WinFormsErrorProvider以在控件条目中显示其图标【英文标题】:CustomizingWinFormsErrorProvidertodisplayitsiconinsidecontrol\'sentry【发布时间】:2010-11-1103:52:07【问题描述】:我有一些自定义/用户控件,在大多数情况下都有标签和条目... 查看详情

winform自定义控件的使用

  c#的自定义控件还是很方便的,至少相对于c++而言。  1,当然是建立一个windows窗体空间库,我这里就是用vs2015,工程名MyControl  第二步。在自定义空间窗体内,拖放这样一组空间。我们发送编辑框的内容给父窗体,然后... 查看详情

如何让 WinForm 设计器完全忽略自定义控件上的属性?

】如何让WinForm设计器完全忽略自定义控件上的属性?【英文标题】:HowdoIgettheWinFormDesignertototallyignoreapropertyonacustomcontrol?【发布时间】:2011-02-0514:59:06【问题描述】:这一定是常见问题解答,但我找不到重复的问题!有很多不同... 查看详情

c#做的winform窗体程序把一个form给为自定义控件?

比如把Form2给成UserControl2要怎么做??修改你的类,从继承自Form改为继承自UserControl他就变成UserControl了参考技术Aform窗体是继承了windows.form,将此处改为CONTROL即可。或者重新创建一个控件,将窗体的控件及代码内容复制到自定义... 查看详情

自定义组合控件

...011/10/12/2209467.html 代码为自己编写目标:实现textview和ImageButton组合,可以通过Xml设置自定义控件的属性。    通过代码或者通过xml设置自定义控件的属性1.控件布局:以Linearlayout为根布局,一个TextVi 查看详情

将自定义控件 dll 添加到我的 Form(WinForm) 时出现问题

】将自定义控件dll添加到我的Form(WinForm)时出现问题【英文标题】:ProblemswhenaddingcustomcontroldllintomyForm(WinForm)【发布时间】:2011-06-3008:54:48【问题描述】:将自定义控件从我的工具箱添加到表单中可以正常工作,但是当我尝试构建... 查看详情

winform自定义分页控件及datagridview数据绑定

  分页效果如上图所示,用到的控件均为基本控件,其方法如下右击项目-添加-新建项选择用户控件然后在用户控件中拖入所需要的Label,Button,Text用户控件全部代码: usingSystem;usingSystem.Collections.Generic;usingSystem.Componen... 查看详情

首次放置在表单上时如何获取要遵守的 WinForms 自定义控件的默认值

】首次放置在表单上时如何获取要遵守的WinForms自定义控件的默认值【英文标题】:HowtogetWinFormscustomcontrol\'sdefaultvaluetoberespectedwhenfirstdroppedonaform【发布时间】:2018-06-2900:33:04【问题描述】:我有一个包含自定义控件的类库:using... 查看详情