WinForm Custom(二) 滑塊控制項

来源:https://www.cnblogs.com/zhuanghamiao/archive/2022/06/13/winform-custom-slider.html
-Advertisement-
Play Games

public class ZhmSlider : Control { private Rectangle foreRect; private Rectangle backRect; private Rectangle setRect; private Color backgroundColor = ...


public class ZhmSlider : Control
    {
        private Rectangle foreRect;
        private Rectangle backRect;
        private Rectangle setRect;

        private Color backgroundColor = Color.White;
        private Color foregroundColor = Color.Gray;
        private Color setRectColor = Color.Black;//滑塊顏色
        private Color fontColor = Color.Black;
        private Color borderColor = Color.Black;

        private int maximum = 100; //進度條最大值
        private int minimum = 0;  //進度條最小值
        private double _value = 0;//進度條當前值

        private bool showPercent; //當前進度百分比
        private float fontSize = 9;// 
        private FontFamily _fontFamily = new FontFamily("Segoe UI");

        private Point originPoint;
        private Point originsetRectPoint;
        private bool setRectDown = false;

        public ZhmSlider()
        {
            // 避免重繪時視窗閃爍
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);

            this.MouseDown += ZhmSlider_MouseDown;
            this.MouseMove += ZhmSlider_MouseMove;
            this.MouseUp += ZhmSlider_MouseUp;
        }

        private void ZhmSlider_MouseUp(object sender, MouseEventArgs e)
        {
            setRectDown = false;
        }

        private void ZhmSlider_MouseMove(object sender, MouseEventArgs e)
        {
            if (setRectDown)
            {
                int dd = e.Location.X - originPoint.X;

                double percent = (double)(originsetRectPoint.X + dd - this.backRect.X) / (this.backRect.Width - this.backRect.Height);
                if (percent < 0)
                {
                    this.Value = minimum;
                    this.foreRect.Width = 0;
                    this.setRect.X = backRect.X;
                }
                else if (percent > 1)
                {
                    this.Value = maximum;
                    this.foreRect.Width = this.backRect.Width;
                    this.setRect.X = backRect.X + backRect.Width - backRect.Height;
                }
                else
                {
                    this.Value = percent * maximum;
                    this.foreRect.Width = (int)(percent * this.backRect.Width);
                    this.setRect.X = originsetRectPoint.X + dd;
                }
                Invalidate();
            }
        }

        private void ZhmSlider_MouseDown(object sender, MouseEventArgs e)
        {
            if (setRect.Contains(e.Location))
            {
                this.originPoint = e.Location;
                originsetRectPoint = this.setRect.Location;
                this.setRectDown = true;
            }
        }

        [Category("擴展屬性"), Browsable(true)]
        public bool ShowPercentTag
        {
            get { return showPercent; }
            set
            {
                showPercent = value;
                Invalidate();
            }
        }
        [Category("擴展屬性"),  Browsable(true)]
        public int Maximum
        {
            get { return maximum; }
            set
            {
                maximum = value;
                Invalidate();
            }
        }
        [Category("擴展屬性"),  Browsable(true)]
        public int Minimum
        {
            get { return minimum; }
            set
            {
                minimum = value;
                Invalidate();
            }
        }

        [Category("擴展屬性"), Browsable(true)]
        public float FontSize
        {
            get { return fontSize; }
            set
            {
                this.fontSize = value;
                Invalidate();
            }
        }
        [Category("擴展屬性"), Browsable(true)]
        public FontFamily FontFamily
        {
            get { return _fontFamily; }
            set
            {
                this._fontFamily = value;
                Invalidate();
            }
        }

        [Category("擴展屬性"), Browsable(true)]
        public Color BackgroundColor
        {
            get { return backgroundColor; }
            set
            {
                this.backgroundColor = value;
                Invalidate();
            }
        }
        [Category("擴展屬性"), Browsable(true)]
        public Color ForegroundColor
        {
            get { return foregroundColor; }
            set
            {
                this.foregroundColor = value;
                Invalidate();
            }
        }
        [Category("擴展屬性"), Browsable(true)]
        public Color SetRectColor
        {
            get { return setRectColor; }
            set
            {
                this.setRectColor = value;
                Invalidate();
            }
        }
        [Category("擴展屬性"), Browsable(true)]
        public Color FontColor
        {
            get { return fontColor; }
            set
            {
                this.fontColor = value;
                Invalidate();
            }
        }

        [Category("擴展屬性"), Browsable(true)]
        public Color BorderColor
        {
            get { return borderColor; }
            set
            {
                this.borderColor = value;
                Invalidate();
            }
        }


        //確定控制項的位置。 我們根據寬度和高度屬性確定矩形的位置。 因為Control類也有這兩個屬性,所以我們在前面添加new來覆蓋原來的屬性 
        [Category("擴展屬性"), Browsable(true)]
        public new int Width
        {
            get { return base.Width; }
            set
            {
                base.Width = value;
                foreRect.X = backRect.X = base.Width / 20;
                backRect.Width = base.Width * 9 / 10;
                foreRect.Width = (int)(_value / maximum * backRect.Width);
                setRect.X = (int)(_value / maximum * (backRect.Width - backRect.Height) + foreRect.X);

                Invalidate();
            }
        }
        [Category("擴展屬性"), Browsable(true)]
        public new int Height
        {
            get { return base.Height; }
            set
            {
                base.Height = value;
                foreRect.Height = backRect.Height = setRect.Height = setRect.Width = base.Height / 3;
                foreRect.Y = backRect.Y = setRect.Y = base.Height / 3;
                Invalidate();
            }
        }

        //值發生變化的屬性。 當向事件添加外部響應函數時,事件將生效,否則OnValueChanged方法的值為空 
        protected EventHandler OnValueChanged;
        public event EventHandler ValueChanged
        {
            add
            {
                if (OnValueChanged != null)
                    foreach (Delegate d in OnValueChanged.GetInvocationList())
                        if (object.ReferenceEquals(d, value)) return;
                OnValueChanged = (EventHandler)Delegate.Combine(OnValueChanged, value);
            }
            remove
            {
                OnValueChanged = (EventHandler)Delegate.Remove(OnValueChanged, value);
            }
        }

        //定義value的值。 當Value值發生變化時,重置矩形的進度,控制塊的位置,並重新繪製控制項(如果在value屬性中修改進度條的值,請使用_value變數,在其他地方,請使Value屬性 )
        [Category("擴展屬性"), Browsable(true)]
        public double Value
        {
            get { return _value; }
            set
            {
                if (_value < Minimum)
                    throw new ArgumentException("Less than minimum");
                if (_value > Maximum)
                    throw new ArgumentException("Exceeds the maximum");

                _value = value;
                foreRect.Width = (int)(_value / maximum * backRect.Width);
                setRect.X = (int)(_value / maximum * (backRect.Width - backRect.Height) + backRect.X);

                if ((_value - maximum) > 0)
                {
                    foreRect.Width = backRect.Width;
                    setRect.X = backRect.Width - backRect.Height + backRect.X;
                }

                if (OnValueChanged != null)
                    OnValueChanged(this, EventArgs.Empty);

                Invalidate();
            }
        }
        //繪製控制項,重載OnPaint方法來繪製控制項 
        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);

            DrawRect(pe.Graphics);
            DrawText(pe.Graphics);
        }

        //滑塊區域
        private void DrawRect(Graphics e)
        {
            Pen pen = new Pen(this.foregroundColor);

            e.FillRectangle(new SolidBrush(this.backgroundColor), backRect);
            e.DrawRectangle(new Pen(this.borderColor), backRect);

            e.FillRectangle(new SolidBrush(this.foregroundColor), foreRect);
            e.DrawRectangle(new Pen(this.borderColor), foreRect);

            e.FillRectangle(new SolidBrush(this.setRectColor), setRect);
            e.DrawRectangle(new Pen(this.borderColor), setRect);
        }

         // 繪製文本
        private void DrawText(Graphics e)
        {
            Point point = new Point();
            point.X = this.backRect.X + this.backRect.Width * 3 / 7;
            point.Y = this.backRect.Y + this.backRect.Height / 3;

            SolidBrush brush = new SolidBrush(fontColor);
            Font font = new Font(_fontFamily, this.fontSize);
            string percent = ((int)this._value).ToString() + "%";

            //設置文本居中
            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Center;

            e.DrawString(percent, font, brush, backRect, format);
        }

        //在設計期間更改控制項的大小時調用OnResize方法。 當您拖動邊緣上的箭頭來更改控制項的大小時,當需要對控制項進行相應更改時,可以重寫此方法。如果沒有重新載入,則只有在修改完成後才會更新控制項。
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            this.Width = Width;
            this.Height = Height;
            Invalidate();
        }
    }

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 周末到了,不想給大家太多的壓力,今天就給大家分享一個比較簡單的彈球小游戲吧。這無聊的周末又有事可以做了,nice… 先看一下我們的最終效果圖 我們分9步來講解如何寫這個小游戲 1.創建游戲的主界面 我們用Python的內置模塊Tkinter來完成了,它是Python的標準GUI工具包,可以非常 ...
  • 前面我們剖析了Redisson的源碼,主要分析了Redisson實現Redis分散式鎖的15問,理清了Redisson是如何實現的分散式鎖和一些其它的特性。這篇文章就來接著剖析Zookeeper分散式鎖的實現框架Curator的源碼,看看Curator是如何實現Zookeeper分散式鎖的,以及它提 ...
  • 認識JavaWeb,衛星定位:zhanjiquan666,衛星定位:zhanjiquan666 ...
  • 一、說明 Fate 是一個工業級聯邦學習框架,所謂聯邦學習指的就是可以聯合多方的數據,共同構建一個模型; 與傳統數據使用方式相比,它不需要聚合各方數據搭建 數據倉庫,聯邦學習在聯合計算建模的過程中,多方機構之間的數據是不會進行共用的,實現數據的 可用不可見;本文主要分享隱私計算平臺 Fate 的相關 ...
  • 文章首發在公眾號(龍台的技術筆記),之後同步到個人網站:xiaomage.info Hippo-4J 距離上一個版本 1.2.1 已經過去一個月的時間。在此期間,由 8 位貢獻者 提交了 170+ commits,正式發佈 1.3.0 版本。 註:這是一個 相容歷史版本 的重大升級。 Github: ...
  • Blazor WebAssembly是什麼 首先來說說WebAssembly是什麼,WebAssembly是一個可以使C#,Java,Golang等靜態強類型編程語言,運行在瀏覽器中的標準,瀏覽器廠商基於此標準實現執行引擎。 在實現了WebAssembly標準引擎之後,瀏覽器中可以執行由其他語言編譯 ...
  • Openxml的顏色變化屬性 目前Openxml存在顏色變化屬性如下: 參數 說明 Hue 色調(色相) HueModulate 色調調製,百分比 HueOffset 色調偏移量,角度值 Saturation 飽和度 SaturationModulation 飽和度調製,百分比 Saturation ...
  • 在基於SqlSugar的開發框架的服務層中處理文件上傳的時候,我們一般有兩種處理方式,一種是常規的把文件存儲在本地文件系統中,一種是通過FTP方式存儲到指定的FTP伺服器上。這種處理應該由程式進行配置,決定使用那種方式,那麼這裡面我們為了彈性化處理, 在文件上傳模塊中採用選項模式【Options】處... ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...