欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Winform控件優(yōu)化之圓角按鈕2

 更新時間:2022年08月29日 09:57:38   作者:代碼迷途  
這篇文章主要介紹了Winform控件優(yōu)化之圓角按鈕2,文章通過圍繞主題展開詳細的內容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下

前言

接上一篇Winform控件優(yōu)化之圓角按鈕1繼續(xù)介紹圓角按鈕的實現和優(yōu)化,以及這個過程中遇到的問題...

圓角按鈕實現的進一步優(yōu)化

【最終實現,兼容默認按鈕】

主要功能【圓角方面】

結合前面兩部分介紹和代碼,最終優(yōu)化實現ButtonPro按鈕(繼承自Button),既提供Button原生功能,又提供擴展功能,除了圓角以外,還實現了圓形、圓角矩形的腳尖效果、邊框大小和顏色、背景漸變顏色、圓角的繪制模式和創(chuàng)建Region模式、常用按鈕圖標快速使用(此項暫未實現)等其他功能。

圓角按鈕控件相關屬性和實現:

  • RoundRadius:圓角半徑,>=0時啟用圓角按鈕,等于0為直角(但可使用背景色等所有Round圓角相關屬性),<0時使用默認Button樣式。
  • RegionNewModel:創(chuàng)建新Region的模式,使用'繪制范圍'創(chuàng)建新的Region,實現控件區(qū)域貼合繪制范圍,實現圖形外的部分"正確的透明",但相對會有些鋸齒。
  • ShowCusp:是否顯示尖角,默認不顯示,當啟用Radius圓角(RoundRadius>=0)時才有效。
  • CuspAlign:(三角)尖角的顯示位置,當啟用圓角按鈕(RoundRadius>=0),且顯示尖角時有效。
  • RoundBorderWidth:啟用Radius圓角(RoundRadius>=0)時邊框寬度,默認0。
  • RoundBorderColor:啟用Radius圓角(RoundRadius>=0)時邊框顏色,默認黑色。
  • EnableBGGradient:啟用漸變背景色(需要RoundRadius>=0),啟用后RoundNormalColor、RoundHoverColor、RoundPressedColor顏色無效。
  • GradientModel:線性漸變的模式,默認垂直漸變。
  • BGColorBegin:漸變開始色。
  • BGColorEnd:漸變結束色。
  • RoundNormalColor:啟用Radius圓角(RoundRadius>=0)時按鈕標準顏色。
  • RoundHoverColor:啟用Radius圓角(RoundRadius>=0)鼠標位于按鈕上時的按鈕顏色。
  • RoundPressedColor:啟用Radius圓角(RoundRadius>=0)鼠標按下時的按鈕顏色。
  • 圓形按鈕,長寬一樣,圓角半徑為長寬的一半,可實現圓形按鈕。
  • 擴展控件屬性分類修改為“高級”,使用CategoryAttribute特性。

注意:

borderPen繪制線條的對齊方式:borderPen.Alignment = PenAlignment.Inset;。但是指定Inset繪制邊框也有小問題,如果是重新創(chuàng)建Region,則繪制邊框后內部變?yōu)橹苯蔷匦危ㄏ忍畛湓倮L制邊框線條);如果使用就有Region(不新建),也會變成內部直角,并且如果不指定Inset則會外部繪制的Border線條變成直接(由原本直角的Region承載圓角之外的部分)??傊加行﹩栴},可自行測試。

在繪制邊框時,不推薦使用PenAlignment.Inset,通過計算減少Rectangle的范圍為半個Border的路徑范圍(寬高-RoundBorderWidth),繪制時在路徑內外正好有一個Border的大小來實現。而且這樣不會發(fā)生上面介紹的內或外直角而非圓角的情況 

OnPaint方法中不要使用e.ClipRectangle

應該使用控件的寬高(Width、Height)計算Rectangle矩形,或者使用ClientRectangle屬性。

相互影響的問題,復制的或拖拽的ButtonPro控件,會被其他控件影響,即調整某個控件,會導致ButtonPro的一個或多個也會牽連變化(很雜亂的關聯變化),如何解決?應該是獨立的才對!且在設計器中沒法通過撤銷操作還原效果

與SetStyle設置無關,后面測試和重新指定Region有關,在后續(xù)測試發(fā)現最終導致此類問題的原因,在于使用了OnPaint參數e.ClipRectangle作為控件繪制范圍繪制產生的。【比如rect = e.Graphics.DrawRoundRectAndCusp(e.ClipRectangle, roundRadius, baseColor, showCusp, cuspAlign)

直接使用控件的WidthHeight定義繪制繪制范圍,替換到e.ClipRectangle。

OnPaint方法中不要使用e.ClipRectangle作為控件繪制范圍

以下問題均是由于OnPaint方法中使用e.ClipRectangle來繪制繪制范圍導致的(它是個自動被影響的值,應該使用Width、Height創(chuàng)建)

不重新賦值Region,拖動或調整按鈕,會重寫顯示相互影響:

如果賦值新的Region,當調整或移動控件時,就有可能影響顯示的布局或大小,且無法通過撤銷還原

重新創(chuàng)建Region的鋸齒問題和優(yōu)勢

【寫錯代碼實現圓形導致的錯誤探索,但也很有意義】

重新賦值Region一個最大的確實是會產生一些鋸齒,即使使用抗鋸齒和最好質量繪制,要想繪制圓形效果,必須重新賦值Region,否則控件只會是圓角。因此,提供了RoundCircleModel屬性,用于是否啟用可繪制圓形按鈕的模式,會有些鋸齒,默認不啟用,如果需要時啟用即可。

需要記住的幾點:

  • Region定義的是控件的區(qū)域,通過GDI+繪制可以實現一個自定義的區(qū)域,從而解除默認的寬高矩形區(qū)域控件的限制。
  • 重新定義和賦值Region的缺點是會產生一定鋸齒,這個鋸齒是Region產生的,而不是GDI+繪制填充產生的。
  • 無法消除創(chuàng)建的Region鋸齒,至少沒提供相關API,因此實際重繪控件時,通常不要創(chuàng)建新的Region
  • 由于設置中使用了Winform透明父控件的樣式,因此要注意其正確的父控件設置。

直接使用繪制后的正確的繪制范圍創(chuàng)建新的Region區(qū)域,則沒有透明父控件的問題,可以實現“正確的透明”,具體可參加下圖所示【新建Region繪制圖形后圓角邊緣部分出現的1像素的控件顏色可以通過調整創(chuàng)建Region時和繪制時的范圍消除(多余的1像素白邊問題無法簡單的通過調整Region和繪制范圍解決,具體可自行測試)】。 

【若是消除新建Region的鋸齒問題,將會非常完美】

若是能實現直接繪制無鋸齒的圓角Region區(qū)域,則,直接在Paint事件中實現控件的圓角Region即可,無需在額外重新繪制背景和文字。【更簡單、更完美的方案】

目前所知,無法對Region進行抗鋸齒,即使使用使用GDI+的APICreateRoundRectRgn方法。相關介紹參見 c# How to make smooth arc region using graphics path、Winforms: Smooth the rounded edges for panel

控件上重繪可以使用Graphics對象在背景透明的Region區(qū)域控件上實現,其背后至少一個父控件(或頂層的Form窗體)。

但是,對于一個Form,要想實現圓角或多邊形窗體,則必須重新生成Region,但創(chuàng)建Region在不規(guī)則形狀時邊緣鋸齒無法解決(如果有大牛,應該可以應用消除鋸齒的算法),后面會介紹一種取巧或者Win32窗體推薦的一種方式,即,使用Layered Windows。

代碼具體實現

將繪制方法精簡為擴展方法后,擴展控件的全部源代碼如下:

擴展方法參見Winform控件優(yōu)化Paint事件實現圓角組件及提取繪制圓角的方法

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace CMControls
{
    public class ButtonPro : Button
    {
        private int roundRadius;//半徑 

        private bool showCusp = false;//顯示尖角
        private RectangleAlign cuspAlign = RectangleAlign.RightTop;//三角尖角位置

        private Color roundBorderColor = Color.Black;//邊框顏色
        private int roundBorderWidth = 0;//邊框寬度

        private Color roundHoverColor = Color.FromArgb(220, 80, 80);//鼠標位于控件時顏色
        private Color roundNormalColor = Color.FromArgb(51, 161, 224);//基顏色
        private Color roundPressedColor = Color.FromArgb(251, 161, 0);//鼠標按下控件時基顏色

        // 鼠標相對控件的狀態(tài)位置,對應上面不同顏色
        private MouseControlState mouseControlState = MouseControlState.Normal;

        private bool regionNewModel = false; // 創(chuàng)建新Region的模式,使用"繪制范圍"創(chuàng)建新的Region,實現控件區(qū)域貼合繪制范圍,實現圖形外的部分"正確的透明",但相對會有些鋸齒

        private Color beginBGColor; //= Color.FromArgb(251, 161, 0);//漸變開始色
        private Color endBGColor; //= Color.FromArgb(251, 161, 0);//漸變結束色
        private bool enableBGGradient = false; //使用漸變色
        private LinearGradientMode gradientModel = LinearGradientMode.Vertical; //線性漸變的模式

        private Region originRegion;

        /// <summary>
        /// 圓形按鈕的半徑屬性
        /// </summary>
        [CategoryAttribute("高級"), DefaultValue(20), Description("圓角半徑,>=0時啟用圓角按鈕,等于0為直角(但可使用背景色等所有Round圓角相關屬性),<0時使用默認Button樣式")]
        public int RoundRadius
        {
            set
            {
                roundRadius = value;
                // 使控件的整個畫面無效并重繪控件
                this.Invalidate();
            }
            get
            {
                return roundRadius;
            }
        }
        /// <summary>
        /// 圓角下創(chuàng)建新Region模式
        /// </summary>
        [CategoryAttribute("高級"), DefaultValue(false), Description("創(chuàng)建新Region的模式,使用'繪制范圍'創(chuàng)建新的Region,實現控件區(qū)域貼合繪制范圍,實現'正確的透明',但相對會有些的鋸齒")]
        public bool RegionNewModel
        {
            set
            {
                regionNewModel = value;
                this.Invalidate();
            }
            get
            {
                return regionNewModel;
            }
        }

        /// <summary>
        /// 三角尖角位置,當啟用圓角
        /// </summary>
        [CategoryAttribute("高級"), Description("(三角)尖角的顯示位置,當啟用圓角按鈕(RoundRadius>=0),且顯示尖角時有效"), DefaultValue(RectangleAlign.RightTop)]
        public RectangleAlign CuspAlign
        {
            set
            {
                cuspAlign = value;
                this.Invalidate();
            }
            get
            {
                return cuspAlign;
            }
        }
        [CategoryAttribute("高級"), Description("是否顯示尖角,默認不顯示,當啟用Radius圓角(RoundRadius>=0)時才有效"), DefaultValue(false)]
        public bool ShowCusp
        {
            set
            {
                showCusp = value;
                this.Invalidate();
            }
            get
            {
                return showCusp;
            }
        }

        [CategoryAttribute("高級"), DefaultValue(0), Description("啟用Radius圓角(RoundRadius>=0)時邊框寬度,默認0")]
        public int RoundBorderWidth
        {
            set
            {
                roundBorderWidth = value;
                this.Invalidate();
            }
            get
            {
                return roundBorderWidth;
            }
        }

        [CategoryAttribute("高級"), DefaultValue(typeof(Color), "0, 0, 0"), Description("啟用Radius圓角(RoundRadius>=0)時邊框顏色,默認黑色")]
        public Color RoundBorderColor
        {
            get
            {
                return this.roundBorderColor;
            }
            set
            {
                this.roundBorderColor = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// 是否啟用背景漸變色,啟用后RoundNormalColor、RoundHoverColor、RoundPressedColor顏色無效
        /// </summary>
        [CategoryAttribute("高級"), DefaultValue(false), Description("啟用漸變背景色(需要RoundRadius>=0),啟用后RoundNormalColor、RoundHoverColor、RoundPressedColor顏色無效")]
        public bool EnableBGGradient
        {
            get
            {
                return this.enableBGGradient;
            }
            set
            {
                this.enableBGGradient = value;
                this.Invalidate();
            }
        }
        /// <summary>
        /// 線性漸變的模式,默認垂直漸變
        /// </summary>
        [CategoryAttribute("高級"), DefaultValue(LinearGradientMode.Vertical), Description("線性漸變的模式,默認垂直漸變")]
        public LinearGradientMode GradientModel
        {
            get
            {
                return this.gradientModel;
            }
            set
            {
                this.gradientModel = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// 背景漸變色
        /// </summary>
        [CategoryAttribute("高級"), DefaultValue(typeof(Color), "0, 122, 204"), Description("漸變開始色")]
        public Color BGColorBegin
        {
            get
            {
                return this.beginBGColor;
            }
            set
            {
                this.beginBGColor = value;
                this.Invalidate();
            }
        }
        /// <summary>
        /// 背景漸變色
        /// </summary>
        [CategoryAttribute("高級"), DefaultValue(typeof(Color), "8, 39, 57"), Description("漸變結束色")]
        public Color BGColorEnd
        {
            get
            {
                return this.endBGColor;
            }
            set
            {
                this.endBGColor = value;
                this.Invalidate();
            }
        }

        [CategoryAttribute("高級"), DefaultValue(typeof(Color), "51, 161, 224"), Description("啟用Radius圓角(RoundRadius>=0)時按鈕標準顏色")]
        public Color RoundNormalColor
        {
            get
            {
                return this.roundNormalColor;
            }
            set
            {
                this.roundNormalColor = value;
                this.Invalidate();
            }
        }
        [CategoryAttribute("高級"), DefaultValue(typeof(Color), "220, 80, 80"), Description("啟用Radius圓角(RoundRadius>=0)鼠標位于按鈕上時的按鈕顏色")]
        public Color RoundHoverColor
        {
            get
            {
                return this.roundHoverColor;
            }
            set
            {
                this.roundHoverColor = value;
                this.Invalidate();
            }
        }

        [CategoryAttribute("高級"), DefaultValue(typeof(Color), "251, 161, 0"), Description("啟用Radius圓角(RoundRadius>=0)鼠標按下時的按鈕顏色")]
        public Color RoundPressedColor
        {
            get
            {
                return this.roundPressedColor;
            }
            set
            {
                this.roundPressedColor = value;
                this.Invalidate();
            }
        }
        protected override void OnMouseEnter(EventArgs e)//鼠標進入時
        {
            mouseControlState = MouseControlState.Hover;//Hover
            base.OnMouseEnter(e);
        }
        protected override void OnMouseLeave(EventArgs e)//鼠標離開
        {
            mouseControlState = MouseControlState.Normal;//正常
            base.OnMouseLeave(e);
        }
        protected override void OnMouseDown(MouseEventArgs e)//鼠標按下
        {
            if (e.Button == MouseButtons.Left && e.Clicks == 1)//鼠標左鍵且點擊次數為1
            {
                mouseControlState = MouseControlState.Pressed;//按下的狀態(tài)
            }
            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)//鼠標彈起
        {
            if (e.Button == MouseButtons.Left && e.Clicks == 1)
            {
                if (ClientRectangle.Contains(e.Location))//控件區(qū)域包含鼠標的位置
                {
                    mouseControlState = MouseControlState.Hover;
                }
                else
                {
                    mouseControlState = MouseControlState.Normal;
                }
            }
            base.OnMouseUp(e);
        }
        public ButtonPro()
        {
            ForeColor = Color.White;

            this.FlatStyle = FlatStyle.Flat;
            this.FlatAppearance.BorderSize = 0;

            FlatAppearance.MouseDownBackColor = Color.Transparent;
            FlatAppearance.MouseOverBackColor = Color.Transparent;
            FlatAppearance.CheckedBackColor = Color.Transparent;

            RoundRadius = 20; // 似乎當值為默認20時重新生成設計器或者重新打開項目后,此屬性就會變?yōu)?,必須在構造函數中指定20來解決

            this.mouseControlState = MouseControlState.Normal;

            // 原始Region
            originRegion = Region;
        }

        public override void NotifyDefault(bool value)
        {
            base.NotifyDefault(false); // 去除窗體失去焦點時最新激活的按鈕邊框外觀樣式
        }

        //重寫OnPaint
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            //base.OnPaintBackground(e);


            // 不能使用 e.ClipRectangle.GetRoundedRectPath(_radius) 計算控件全部的Region區(qū)域,e.ClipRectangle 似乎是變化的,必須使用固定的Width和Height,包括下面的繪制也不能使用e.ClipRectangle
            // 在Paint事件中也不推薦使用e.ClipRectangle時沒問題的
            Rectangle controlRect = new Rectangle(0, 0, this.Width, this.Height);

            // roundRadius 修改回來是要還原
            if (roundRadius >= 0 && regionNewModel) // 圓角下創(chuàng)建新Region模式,使用自定義Region
            {
                var controlPath = controlRect.GetRoundedRectPath(roundRadius);

                // 要在繪制之前指定Region,否則無效
                this.Region = new Region(controlPath);
            }
            else // 修改對應調整
            {
                //this.Region = new Region(controlRect);//也屬于重新修改
                this.Region = originRegion;
            }

            if (roundRadius >= 0)
            {
                Rectangle rect;

                if (enableBGGradient)
                {
                    rect = e.Graphics.DrawRoundRectAndCusp(controlRect, roundRadius, beginBGColor, endBGColor, true, CuspAlign, gradientModel, roundBorderWidth > 0 ? new Pen(roundBorderColor, roundBorderWidth) : null);
                }
                else
                {
                    Color baseColor;

                    switch (mouseControlState)
                    {
                        case MouseControlState.Hover:
                            baseColor = this.roundHoverColor;
                            break;
                        case MouseControlState.Pressed:
                            baseColor = this.roundPressedColor;
                            break;
                        case MouseControlState.Normal:
                            baseColor = this.roundNormalColor;
                            break;
                        default:
                            baseColor = this.roundNormalColor;
                            break;
                    }
                    rect = e.Graphics.DrawRoundRectAndCusp(controlRect, roundRadius, baseColor, showCusp, cuspAlign, roundBorderWidth > 0 ? new Pen(roundBorderColor, roundBorderWidth) : null);

                }

                // 使用合適的區(qū)域
                e.Graphics.DrawText(rect, Text, ForeColor, Font, TextAlign);
            }
        }
    }
}

測試擴展按鈕控件ButtonPro

通過拖拽ButtonPro按鈕控件,調整各個參數,查看不同樣式的按鈕效果。

TextRenderer.DrawText繪制文本

文本垂直居中偏上的問題及文字大小不正確【推薦使用TextRenderer.DrawText繪制文本】

所有的一切都非常好,但是,目前還有一個小問題,就是繪制垂直居中的文本時,可以明顯看到偏上方。是的由此產生“瑕疵”。

目前沒有找到很好的解決辦法,更換字體、字體大小為偶數會有一定效果,但并不能完全解決。

使用StringFormat.GenericTypographic

后面經過花木蘭控件庫的大佬提醒,使用StringFormat.GenericTypographic作為文本繪制的格式對象,可以看到偏上的問題有了明顯改善。

        using (StringFormat strF = StringFormat.GenericTypographic)
        {
            // 文字布局
            switch (_textAlign)
            {
                //...
            }
            g.DrawString(text, font, brush, rect, strF);
        }

雖然如此,但是還是有一點點不完全垂直。而且對比同樣字體情況下,DrawString繪制出來的文本明顯和原生Button時顯示的文字有很大差別(大小、清晰度)

僅僅重寫OnPaintBackground

【無效果】

后面由于文字繪制的問題,想著直接重寫OnPaintBackground,文字交由Winform自己繪制,應該可以達到很好的效果。

但是,但是重寫OnPaintBackground后背景沒有任何效果,僅僅是設置的透明背景,無法實現圓角等各種繪制。

目前暫時不知道該如何正確的處理OnPaintBackground方法。

使用TextRenderer.DrawText繪制文本

【不推薦Graphics.DrawString】

后來幾乎要放棄了,因為最終繪制的文字確實很不理想,和原生Button對比起來差好多。。。

然后想著測試下TextRenderer.DrawText()繪制文本的效果如何,最終發(fā)現文字繪制效果非常好(大小正確、清晰),重點是文字位置的水平和垂直居中沒有任何問題,基本和原生Button的文字效果一致。

// ...
TextRenderer.DrawText(g, text, font, rect, color, formatFlags);

擴展方法的源碼參見Winform控件優(yōu)化Paint事件實現圓角組件及提取繪制圓角的方法

到此這篇關于Winform控件優(yōu)化之圓角按鈕2的文章就介紹到這了,更多相關Winform 圓角按鈕內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C#使用GDI+創(chuàng)建縮略圖實例

    C#使用GDI+創(chuàng)建縮略圖實例

    這篇文章主要介紹了C#使用GDI+創(chuàng)建縮略圖實例,是C#程序設計中非常實用的技巧,需要的朋友可以參考下
    2014-10-10
  • C#操作SQLite數據庫幫助類詳解

    C#操作SQLite數據庫幫助類詳解

    這篇文章主要介紹了C#操作SQLite數據庫幫助類,詳細分析了C#針對sqlite數據庫的連接、查詢、分頁等各種常見操作的實現與封裝技巧,需要的朋友可以參考下
    2017-07-07
  • C#生成不重復隨機數列表實例

    C#生成不重復隨機數列表實例

    C#生成不重復隨機數列表實例的代碼,需要的朋友可以參考一下
    2013-02-02
  • c# 異步編程基礎講解

    c# 異步編程基礎講解

    這篇文章主要介紹了c# 異步編程的相關資料,幫助大家更好的理解和學習使用c#,感興趣的朋友可以了解下
    2021-04-04
  • C# 實現在當前目錄基礎上找到上一層目錄

    C# 實現在當前目錄基礎上找到上一層目錄

    這篇文章主要介紹了C# 實現在當前目錄基礎上找到上一層目錄,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 關于C#?調用Dll?傳遞字符串指針參數的問題

    關于C#?調用Dll?傳遞字符串指針參數的問題

    這篇文章主要介紹了C#?調用Dll傳遞字符串指針參數,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • 如何隨機選取一個機器的ip

    如何隨機選取一個機器的ip

    此方法可用于當需要負載均衡時,即想選擇多臺機器來處理程序執(zhí)行。 隨機的選擇一臺機器來處理。
    2013-03-03
  • Unity相機移動之屏幕邊緣檢測

    Unity相機移動之屏幕邊緣檢測

    這篇文章主要為大家詳細介紹了Unity相機移動之屏幕邊緣檢測,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • 利用Distinct()內置方法對List集合的去重問題詳解

    利用Distinct()內置方法對List集合的去重問題詳解

    這篇文章主要給大家介紹了關于利用Distinct()內置方法對List集合的去重問題的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-06-06
  • C#實現插入排序

    C#實現插入排序

    這篇文章介紹了C#實現插入排序的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08

最新評論