winform滚动条美化

首次做winfrom应用,在滚动条美化上费了很大劲,网上资料新手表示要么看不懂要么不会用。这里把我的实现过程记下来,尽量写详细点,希望帮助下其他跟我一样纠结这个问题的朋友。

首先重绘控件直接复制Sunday丶若雪写的:
https://blog.csdn.net/qq_33212020/article/details/53447135
项目内新建个用户控件,全部复制进去就直接能用了,再次对Sunday丶若雪表示感谢。这里把自己摸索出来的该控件用法写给需要的朋友。
原效果:
控件原效果
个人实现效果:
个人实现效果
原理:设计界面放两个panel(pn_info,pn_scroll。AutoScroll属性都设为false,最好命名和我一样,方便代码使用),pn_info放在pn_scroll内部,pn_info放信息,pn_scroll放滚动条。pn_info添加滚轮事件,带动滚动条运动。滚动条的拖动事件内带动pn_info的滚动(pn_info通过改变top值来模拟滚动)。pn_info的location设为(0,0)。我这里pn_info为动态添加数据。

源码

 
        SundayRXScrollBar sb = new SundayRXScrollBar();//滚动条实例
        //窗口初始化
        public void init()
        {
            history his = new history();
            List<history> hisList = his.read();//获取历史记录列表
            for(var i=0;i<hisList.Count;i++)
            {
                int timestamp = hisList[i].timestamp;
                historyItem item = new historyItem();
                item.setDate(toDate(timestamp));
                item.chName(timestamp.ToString());//给勾选框赋值(判断勾选用)
                item.Location = new System.Drawing.Point(0, i * 115); //记录位置
                item.setAvgForce(hisList[i].avg_force.ToString("0.#"));
                item.setMaxForce(hisList[i].max_force.ToString());
                item.setMaxFrequence(hisList[i].max_frequence.ToString());
                item.setPunchCount(hisList[i].punch_count.ToString());
                item.setTrainTime(hisList[i].train_time.ToString());
                item.setRemark(hisList[i].remark.ToString());
                pn_info.Controls.Add(item);
            }
            //以上部分为我的pn_info添加item,不能照抄,请改为自己的添加方法
            //以下内容可全部照抄
            //内部容器高度要设为实际高度,这里我每个item的高度是115
            pn_info.Height = hisList.Count * 115;
            pn_info.Focus(); //获取焦点
            sb_init(); //滚动条初始化
        }
        private void sb_init()
        {
            if (pn_info.Height <= pn_scroll.Height)
            {
                //内部容器高度小于滚动条容器时不生产滚动条
                pn_info.Width = pn_scroll.Width;
                return;
            }
            sb.Width = 10;  //滚动条宽度(px)
            pn_info.Width = pn_scroll.Width-10;
            sb.Height = pn_scroll.Height;
            //滑块高度=可视高度/实际高度*滚动条高度(pn_scroll.Height)
            float length = (float)pn_scroll.Height / (float)pn_info.Height * (float)pn_scroll.Height;
            sb.SliderHeight = (int)length; 
            //sb.SliderColor = Color.FromArgb(2,153,255);//滑块颜色
            //sb.MouseDownSliderColor  鼠标点击后滑块颜色
            //sb.MouseOverSliderColor   鼠标接触时滑块颜色
            //sb.BottomColor      滚动条颜色
            sb.SliderWidthPercent = 1; //滑块宽度和滚动条宽度比,1表示占满
            sb.Dock = DockStyle.Right; //滚动条位置
            sb.ValueChanged += sb_ValueChanged;  //滚动条拖动事件
            sb.GotFocus += sb_GotFocus;  //滚动条获得焦点事件
            pn_scroll.Controls.Add(sb); //pn_scroll添加滚动条
            pn_info.MouseWheel += pn_info_MouseWheel; //pn_info添加滚轮事件
        }
        bool isMouseWheel = false; //防止滚轮带动的滚动条再次触发sb_ValueChanged
        //pn_info滚轮事件
        private void pn_info_MouseWheel(object sender, MouseEventArgs e)
        {
       	    isMouseWheel = true;
            int scrollRang = 40; //每次滚动高度(px)
            int sbRang = calSbRang(scrollRang); //滚动条实际滚动幅度
            if (e.Delta > 0) //滚轮向上
            {
                if (sb.Value - sbRang<= 0)
                {
                    //滚动到顶,直接设为默认值,防止滚动产生的误差
                    sb.Value = 0;
                    pn_info.Top = 0;
                }
                else
                {
                    sb.Value -= sbRang;
                    pn_info.Top += scrollRang;
                }
            }
            else//滚轮向下
            {
                if (sb.Value + sbRang>= 100)
                {
                    //滚动到底,直接设为默认值,防止滚动产生的误差
                    sb.Value = 100;
                    pn_info.Top = -(pn_info.Height-pn_scroll.Height);
                }
                else
                {
                    sb.Value += sbRang;
                    pn_info.Top -= scrollRang;
                }
            }
        }
        //因为滚动条滚动幅度可能是小数,转int后会损失精度,导致滚动到底或到底时产生一定误差
        float residue = 0; //float转int后舍去的小数部分累积凑1
        private int calSbRang(int scrollRang)
        {
            float temp = ((float)scrollRang) / (float)(pn_info.Height - pn_scroll.Height) * 100;//滚动条滚动比例
            int sbRang = Convert.ToInt32(temp);//保留整数部分
            residue += temp - (float)sbRang; //累积舍去的小数部分
            if (residue >= 1)
            {
                residue -= 1;
                sbRang += 1;
            }
            return sbRang;
        }
        //滚动条拖动
        private void sb_ValueChanged(object sender, EventArgs e)
        {
            if (isMouseWheel) return;
            pn_info.Top =-Convert.ToInt32((float)sb.Value / 100 * (float)(pn_info.Height-pn_scroll.Height));
        }
        //滚动条获取焦点时把焦点给pn_info,防止触发滚动条的滚轮事件(滚动条的滚轮滑动和容器内的滑动速度不一致)
        private void sb_GotFocus(object sender, EventArgs e)
        {
            isMouseWheel = false;
            pn_info.Focus();
        }

经过几次测试,发现内容比较少的时候,滚动条滑块会伸到容器外面去。
解决办法:重绘控件代码SliderHeight方法中注释这句(原意应该是当滚动条高度-滑块高度<100的话就把滚动条高度+100,不知道作者为啥要这么处理)
在这里插入图片描述

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值