zoukankan      html  css  js  c++  java
  • FlexLabel——控制伸缩面板的标签

    前    注:

    这是自己平时根据自己需要写的一些小代码,未必对各看官有用。另外,这是根据个人想法而写,未必严谨和符合设计原则,若有任何不妥之处,还请不吝赐教。

    说    明:

    在豆瓣和其它一些网站陆续看到这样的UI效果:单击一篇文章的标题,在下边展开一个面板,显示文章的内容;再次单击则将文章内容面板收缩。

    此控件是仿此效果的一个WinForm的实现。

    此控件显示为了一个水平的标签条,左边可显示文本,右边显示一个向上或向下的箭头(描述当然相关面板处于展开还是收缩状态)。将鼠标置于控件上时,控件背景将高亮。

    使用时,将要展开和收缩的面板关联到此控件并设置好其它相关属性即可。在此控件上单击鼠标时,此控件将通过设置目标控件的高度来达到展开或收缩的效果,展开或收缩的过程应用了阻尼效果。

    设计要点&使用说明:

    1、Target属性描述此控件关联的面板,IsSpread描述目标面板当前处于展开还是收缩状态。

    2、SizeSpread和SizeShrink分别描述目标控件展开或收缩时的尺寸(高度)。

    3、阻尼效果指目标控件的尺寸呈正弦曲线形变化。TickCount和TickPause用于控制阻尼效果,TickCount用于控制变化过程分几步完成,TickPause用于控制每两次变化之间的时间间隔。TickCount越大,变化过程越精细;TickCount越小、TickPause越小,收缩或展开的过程越快。

    4、Flexing事件发生于IsSpread即将发生变化时,Flexed事件发生于IsSpread变化完成之后。

    5、此控件的展示效果比较丑(因为是自己绘制的,在这方面,我没有天赋),如果哪位能够实现更好的效果,还请不吝赐教。

    源代码  :

    代码
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;

    namespace CommonLibrary.ExtendedControl
    {
        
    /// <summary>
        
    /// 带有伸缩功能的一个标签
        
    /// </summary>
        public partial class FlexLabel : Control
        {
            
    #region 数据

            
    #region 控件绘制相关

            
    /// <summary>
            
    /// 是否高亮
            
    /// </summary>
            private bool _IsHighLight = false;

            
    /// <summary>
            
    /// 是否处于伸展状态
            
    /// </summary>
            private bool _IsSpread = false;

            
    /// <summary>
            
    /// 状态变化:此变量用于防止使用者在Flexing事件响应中修改IsSpread属性
            
    /// </summary>
            private bool StateChanging = false;

            
    /// <summary>
            
    /// 高亮区域的边界路径
            
    /// </summary>
            System.Drawing.Drawing2D.GraphicsPath HighLightRegionPath;

            
    /// <summary>
            
    /// 高亮颜色
            
    /// </summary>
            Color _HighLightColor;

            
    /// <summary>
            
    /// 隐藏时的颜色
            
    /// </summary>
            Color _HideColor;

            
    /// <summary>
            
    /// 用于填充高亮区域的刷子
            
    /// </summary>
            Brush HighLightBrush;

            
    /// <summary>
            
    /// 用于清空高亮区域的刷子
            
    /// </summary>
            Brush HideBrush;

            
    /// <summary>
            
    /// 文本画刷
            
    /// </summary> 
            Brush TextBrush;

            
    /// <summary>
            
    /// 描述信息
            
    /// </summary>
            string _Description;

            
    private int _LabelStyle = 0;

            
    #endregion

            
    #region 关联控件数据与伸缩效果

            
    /// <summary>
            
    /// 目标
            
    /// </summary>
            Control _Target;

            
    /// <summary>
            
    /// 收缩时的尺寸
            
    /// </summary>
            int _SizeShrink = 10;

            
    /// <summary>
            
    /// 伸展时的尺寸
            
    /// </summary>
            int _SizeSpread = 10;

            
    /// <summary>
            
    /// 阻尼效果的间隔角度
            
    /// </summary>
            double RadianTick = 5 * (Math.PI / 180);

            
    /// <summary>
            
    /// 指示伸缩过程分为多个部分完成
            
    /// </summary>
            int _TickCount = 10;

            
    /// <summary>
            
    /// 指定两个部分伸缩动作间的时间间隔,以毫秒为单位
            
    /// </summary>
            int _TickPause = 50;

            
    #endregion

            CancelEventArgs FlexingArgs;

            
    #endregion

            
    #region 属性

            
    /// <summary>
            
    /// 是否处于伸展状态
            
    /// </summary>
            public bool IsSpread
            {
                
    get { return _IsSpread; }
                
    set
                {
                    
    if (_IsSpread == value || StateChanging) return;

                    StateChanging 
    = true;

                    FlexingArgs.Cancel 
    = false;
                    
    if (_Flexing != null) _Flexing(this, FlexingArgs);

                    
    if (FlexingArgs.Cancel)
                    {
                        StateChanging 
    = false;
                        
    return;
                    }

                    _IsSpread 
    = value;

                    FlexTarget();

                    
    this.Refresh();

                    StateChanging 
    = false;

                    
    if (_Flexed != null) _Flexed(this, System.EventArgs.Empty);
                }
            }

            
    #region 控件绘制相关

            
    /// <summary>
            
    /// 是否高亮
            
    /// </summary>
            private bool IsHighLight
            {
                
    get { return _IsHighLight; }
                
    set
                {
                    
    if (_IsHighLight == value) return;
                    _IsHighLight 
    = value;
                    
    this.Refresh();
                }
            }

            
    /// <summary>
            
    /// 高亮颜色
            
    /// </summary>
            public Color HighLightColor
            {
                
    get { return _HighLightColor; }
                
    set
                {
                    
    if (_HighLightColor == value) return;

                    _HighLightColor 
    = value;
                    HighLightBrush 
    = new SolidBrush(_HighLightColor);
                }
            }

            
    /// <summary>
            
    /// 隐藏颜色
            
    /// </summary>
            public Color HideColor
            {
                
    get { return _HideColor; }
                
    set
                {
                    
    if (_HideColor == value) return;

                    _HideColor 
    = value;
                    HideBrush 
    = new SolidBrush(_HideColor);
                }
            }

            
    /// <summary>
            
    /// 显示的提示信息
            
    /// </summary>
            [Browsable(true)]
            
    public override string Text
            {
                
    get
                {
                    
    return base.Text;
                }
                
    set
                {
                    
    base.Text = value;
                }
            }

            
    /// <summary>
            
    /// 标签样式
            
    /// </summary>
            public int LabelStyle
            {
                
    get { return _LabelStyle; }
                
    set { _LabelStyle = value; }
            }

            
    #endregion

            
    #region 关联控件与伸缩效果

            
    /// <summary>
            
    /// 关联的控件
            
    /// </summary>
            public Control Target
            {
                
    get { return _Target; }
                
    set { _Target = value; }
            }

            
    /// <summary>
            
    /// 朝向
            
    /// </summary>
            public Orientation Orientation
            {
                
    get { return Orientation.Vertical; }
                
    set { }
            }

            
    /// <summary>
            
    /// 收缩时的尺寸
            
    /// </summary>
            public int SizeShrink
            {
                
    get { return _SizeShrink; }
                
    set
                {
                    
    if (value < 0return;
                    _SizeShrink 
    = value;
                }
            }

            
    /// <summary>
            
    /// 伸展时的尺寸
            
    /// </summary>
            public int SizeSpread
            {
                
    get { return _SizeSpread; }
                
    set
                {
                    
    if (value < _SizeShrink) return;
                    _SizeSpread 
    = value;
                }
            }

            
    /// <summary>
            
    /// 此值用于指定将伸缩过程分为多少次完成。此值越大,则伸缩过程的平滑效果越好,但代价也越大。推荐在8至20之间。
            
    /// </summary>
            public int TickCount
            {
                
    get { return _TickCount; }
                
    set
                {
                    
    if (_TickCount < 1)
                    {
                        _TickCount 
    = 1;
                    }
                    
    else if (_TickCount > 30)
                    {
                        TickCount 
    = 30;
                    }
                    
    else
                    {
                        _TickCount 
    = value;
                    }

                    RadianTick 
    = Math.PI / (_TickCount * 2);
                }
            }

            
    /// <summary>
            
    /// 指定两个部分伸缩动作间的时间间隔,以毫秒为单位
            
    /// </summary>
            public int TickPause
            {
                
    get { return _TickPause; }
                
    set
                {
                    
    if (_TickPause < 0)
                    {
                        _TickPause 
    = 0;
                    }
                    
    else
                    {
                        _TickPause 
    = value;
                    }
                }
            }

            
    #endregion

            
    #endregion

            
    #region 事件

            
    /// <summary>
            
    /// 伸缩事件
            
    /// </summary>
            private event CancelEventHandler _Flexing;

            
    /// <summary>
            
    /// 伸缩事件
            
    /// </summary>
            public event CancelEventHandler Flexing
            {
                add
                {
                    _Flexing 
    += value;
                }
                remove
                {
                    _Flexing 
    -= value;
                }
            }

            
    /// <summary>
            
    /// 伸缩发生后事件
            
    /// </summary>
            private event EventHandler _Flexed;

            
    /// <summary>
            
    /// 伸缩发生后事件
            
    /// </summary>
            public event EventHandler Flexed
            {
                add
                {
                    _Flexed 
    += value;
                }
                remove
                {
                    _Flexed 
    -= value;
                }
            }

            
    #endregion

            
    #region 方法

            
    public FlexLabel()
            {
                InitializeComponent();

                
    #region 画笔

                
    //Graphics = this.CreateGraphics();

                HighLightRegionPath 
    = GetLRRoundRegionPath(this.ClientRectangle);

                HighLightColor 
    = Color.FromKnownColor(KnownColor.Control);

                HideColor 
    = Color.FromKnownColor(KnownColor.Window);

                TextBrush 
    = new SolidBrush(Color.FromKnownColor(KnownColor.Black));

                
    #endregion

                
    this.Padding = new Padding(33203);
                FlexingArgs 
    = new CancelEventArgs(false);
            }

            
    /// <summary>
            
    /// 重置伸缩状态
            
    /// </summary>
            
    /// <param name="IsSpread"></param>
            public void ResetFlex(bool IsSpread)
            {
                _IsSpread 
    = IsSpread;
                
    this.Refresh();
            }

            
    protected override void OnPaint(PaintEventArgs pe)
            {
                
    // TODO: Add custom paint code here

                
    // Calling the base class OnPaint
                base.OnPaint(pe);

                
    float YPos = Math.Max(0, (this.Height - 10)) / 2;

                
    if (HighLightRegionPath == nullreturn;

                pe.Graphics.FillRectangle(HideBrush, 
    this.ClientRectangle);
                
    if (IsHighLight) pe.Graphics.FillPath(HighLightBrush, HighLightRegionPath);

                pe.Graphics.DrawString(
    this.Text, this.Font, this.TextBrush, this.Padding.Left, YPos);

                
    string FlexTag = (IsSpread) ? "" : "";

                pe.Graphics.DrawString(FlexTag, 
    this.Font, this.TextBrush, (float)(this.Width - this.Padding.Right), YPos);
            }

            
    protected override void OnSizeChanged(EventArgs e)
            {
                
    base.OnSizeChanged(e);

                Console.WriteLine(
    "SizeChanged");

                HighLightRegionPath 
    = GetLRRoundRegionPath(this.ClientRectangle);
                
    //Graphics = this.CreateGraphics();
            }

            
    protected override void OnMouseEnter(EventArgs e)
            {
                
    base.OnMouseEnter(e);

                IsHighLight 
    = true;

                
    //Graphics.FillPath(HighLightBrush, HighLightRegionPath);
                
    //Graphics.DrawString(Description, this.Font, this.TextBrush, 8f, 3f);
            }

            
    protected override void OnMouseLeave(EventArgs e)
            {
                
    base.OnMouseLeave(e);

                IsHighLight 
    = false;

                
    //Graphics.FillPath(HideBrush, HighLightRegionPath);
                
    //Graphics.DrawString(Description, this.Font, this.TextBrush, 8f, 3f);
            }

            
    protected override void OnClick(EventArgs e)
            {
                
    base.OnClick(e);
                IsSpread 
    = !IsSpread;
            }

            
    /// <summary>
            
    /// 获取一个左右两端为弧形的区域
            
    /// </summary>
            
    /// <param name="Rect">包含区域的矩形</param>
            
    /// <returns></returns>
            public System.Drawing.Drawing2D.GraphicsPath GetLRRoundRegionPath(Rectangle Rect)
            {
                System.Drawing.Drawing2D.GraphicsPath Path 
    = null;
                Rectangle ArcRect;

                
    try
                {
                    Path 
    = new System.Drawing.Drawing2D.GraphicsPath();

                    
    switch (LabelStyle)
                    {
                        
    case 0:
                            
    #region 两端圆滑

                            ArcRect 
    = new Rectangle(Rect.Location, new Size(Rect.Height, Rect.Height));

                            
    //左边
                            Path.AddArc(ArcRect, 90180);

                            
    //右边
                            ArcRect.X = Rect.X + Rect.Width - Rect.Height;
                            Path.AddArc(ArcRect, 
    270180);

                            
    break;
                            
    #endregion

                        
    case 1:
                            
    #region 四角圆滑

                            ArcRect 
    = new Rectangle(Rect.Location, new Size(88));

                            
    //左上角
                            Path.AddArc(ArcRect, 18090);


                            ArcRect.X 
    = Rect.Width - 9;
                            
    //右上角
                            Path.AddArc(ArcRect, 27090);

                            ArcRect.Y 
    = Rect.Height - 9;
                            
    //右下角
                            Path.AddArc(ArcRect, 090);

                            ArcRect.X 
    = 0;
                            
    //左下角
                            Path.AddArc(ArcRect, 9090);

                            
    break;

                            
    #endregion

                        
    case 2:
                            
    #region 四角平滑

                            Path.AddLine(
    0220);
                            Path.AddLine(Rect.Width 
    - 20, Rect.Width, 2);
                            Path.AddLine(Rect.Width, Rect.Height 
    - 2, Rect.Width - 2, Rect.Height);
                            Path.AddLine(
    2, Rect.Height, 0, Rect.Height - 2);

                            
    break;
                            
    #endregion

                        
    default:
                            
    break;
                    }

                    
    //闭合
                    Path.CloseFigure();
                }
                
    catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }

                
    return Path;
            }

            
    /// <summary>
            
    /// 伸缩目标控件
            
    /// </summary>
            public void FlexTarget()
            {
                
    if (Target == null || SizeShrink == SizeSpread) return;

                
    int Distance = SizeSpread - SizeShrink;
                
    double Radian = 0;
                
    double RadianTick = this.IsSpread ? this.RadianTick : -this.RadianTick;
                
    int SizeInit = this.IsSpread ? this.SizeShrink : this.SizeSpread;

                
    for (int i = 0; i < _TickCount; i++)
                {
                    Radian 
    += RadianTick;

                    Target.Height 
    = SizeInit + (int)(Distance * Math.Sin(Radian));

                    Target.Update();

                    System.Threading.Thread.Sleep(_TickPause);
                }
            }

            
    #endregion
        }
    }


  • 相关阅读:
    git常用命令
    springcloud 心得记录
    Spring Boot整合RabbitMQ
    docker安装rabbitmq
    Linux按顺序启动多个jar的shell脚本
    idea连接docker实现一键部署
    docker安装mysql
    阿里云CentOS服务器挂载数据盘
    【selenium学习中级篇 -26】HTMLTestRunner生成测试报告
    【selenium学习中级篇 -25】Unittest框架
  • 原文地址:https://www.cnblogs.com/yedaoq/p/1712336.html
Copyright © 2011-2022 走看看