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

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

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

前言

Windows 11下所有控件已經(jīng)默認(rèn)采用圓角,其效果更好、相對(duì)有著更好的優(yōu)化,只是這是默認(rèn)的行為,無(wú)法進(jìn)一步自定義。

圓角按鈕實(shí)現(xiàn)【重寫OnPaint實(shí)現(xiàn)圓角繪制】

控件自定義繪制的關(guān)鍵在于:重寫OnPaint方法,其參數(shù)提供了用于GDI+繪圖的Graphics對(duì)象,由此實(shí)現(xiàn)繪制需要的圖形效果。

為了更好的顯示繪制的圖形,通常必須設(shè)置控件背景透明(圖形外的控件區(qū)域透明,便于正確顯示繪制的圖形),雖然Winform的背景透明有著一定缺陷,但總體來(lái)說(shuō)這是必須的。

此外,Paint事件方法中,也可以進(jìn)行控件的繪制(重繪),與繼承重寫OnPaint沒(méi)有本質(zhì)區(qū)別。

代碼主要關(guān)鍵點(diǎn)或思路、優(yōu)化

  • 半徑Radius、Color、TextAlign屬性的賦值,都調(diào)用 Invalidate() 方法使控件畫面無(wú)效并重繪控件。
  • 添加文本位置的屬性TextAlign,并在屬性賦值時(shí)調(diào)用Invalidate()重繪控件,實(shí)現(xiàn)修改文本位置的布局。
  • 有一個(gè)bug問(wèn)題,就是在點(diǎn)擊按鈕鼠標(biāo)抬起方法OnMouseUp中,實(shí)現(xiàn)了修改鼠標(biāo)狀態(tài),對(duì)應(yīng)的背景顏色值也修改了,控件重繪時(shí)也修改了顏色(debug),但絕大多數(shù)情況下,鼠標(biāo)抬起背景顏色未變化。原因在重寫的OnMouseUp(MouseEventArgs e)中先調(diào)用的控件基類base.OnMouseUp(e);,后修改的狀態(tài)顏色,將base.OnMouseUp(e);改為最后調(diào)用即可。
  • 修改和優(yōu)化圓角部分圓弧的繪制,原實(shí)現(xiàn)圓弧半徑處理不合理。
  • 【盡可能高質(zhì)量繪制】圖形部分的幾個(gè)模式必須指定,怎么明顯看出顯示的文本、邊框等不清晰、鋸齒驗(yàn)證等問(wèn)題。
  • 其他一些小修改和調(diào)整,比如抗鋸齒、高質(zhì)量繪圖、使用控件字體、文本顏色默認(rèn)白色、設(shè)置字體方向等
  • Radius 屬性修改邊角半徑大?。磮A角的大小、圓弧的大小)
  • NormalColor、HoverColor、PressedColor 屬性設(shè)置按鈕正常狀態(tài)、鼠標(biāo)懸停、鼠標(biāo)按下時(shí)的背景顏色,通常設(shè)置為一致即可。
  • 指定Size的Width、Height的大小相同,Radius為正方向邊長(zhǎng)的一半,可以實(shí)現(xiàn)圓形按鈕。

StringFormat 對(duì)象,可以提供對(duì)字符串文本的顏色、布局、方向等各種格式的設(shè)置,用于渲染文本效果。

Control.DesignMode屬性可以判斷當(dāng)前代碼的執(zhí)行環(huán)境是否是設(shè)計(jì)器模式,在某些條件下可以通過(guò)此判斷,決定是否在設(shè)計(jì)器下執(zhí)行某段代碼(如果不涉及樣式效果,就可以不需要在設(shè)計(jì)器下執(zhí)行)

使用圓角按鈕

編譯后,直接從工具箱中拖動(dòng)RoundButtons圓角按鈕控件到窗體即可。

代碼如下,關(guān)鍵部分都有相關(guān)注釋,可以直接過(guò)一遍代碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CMControls.RoundButtons
{
    public enum ControlState { Hover, Normal, Pressed }
    public class RoundButton : Button
    {

        private int radius;//半徑 
        //private Color _borderColor = Color.FromArgb(51, 161, 224);//邊框顏色
        private Color _hoverColor = Color.FromArgb(220, 80, 80);//基顏色
        private Color _normalColor = Color.FromArgb(51, 161, 224);//基顏色
        private Color _pressedColor = Color.FromArgb(251, 161, 0);//基顏色

        private ContentAlignment _textAlign = ContentAlignment.MiddleCenter;

        public override ContentAlignment TextAlign
        {
            set
            {
                _textAlign = value;
                this.Invalidate();
            }
            get
            {
                return _textAlign;
            }
        }

        /// <summary>
        /// 圓角按鈕的半徑屬性
        /// </summary>
        [CategoryAttribute("Layout"), BrowsableAttribute(true), ReadOnlyAttribute(false)]
        public int Radius
        {
            set
            {
                radius = value;
                // 使控件的整個(gè)畫面無(wú)效并重繪控件
                this.Invalidate();
            }
            get
            {
                return radius;
            }
        }
        [CategoryAttribute("Appearance"), DefaultValue(typeof(Color), "51, 161, 224")]
        public Color NormalColor
        {
            get
            {
                return this._normalColor;
            }
            set
            {
                this._normalColor = value;
                this.Invalidate();
            }
        }
        [CategoryAttribute("Appearance"), DefaultValue(typeof(Color), "220, 80, 80")]
        public Color HoverColor
        {
            get
            {
                return this._hoverColor;
            }
            set
            {
                this._hoverColor = value;
                this.Invalidate();
            }
        }

        [CategoryAttribute("Appearance"), DefaultValue(typeof(Color), "251, 161, 0")]
        public Color PressedColor
        {
            get
            {
                return this._pressedColor;
            }
            set
            {
                this._pressedColor = value;
                this.Invalidate();
            }
        }

        public ControlState ControlState { get; set; }

        protected override void OnMouseEnter(EventArgs e)//鼠標(biāo)進(jìn)入時(shí)
        {
            ControlState = ControlState.Hover;//Hover
            base.OnMouseEnter(e);
        }
        protected override void OnMouseLeave(EventArgs e)//鼠標(biāo)離開
        {
            ControlState = ControlState.Normal;//正常
            base.OnMouseLeave(e);
        }
        protected override void OnMouseDown(MouseEventArgs e)//鼠標(biāo)按下
        {
            if (e.Button == MouseButtons.Left && e.Clicks == 1)//鼠標(biāo)左鍵且點(diǎn)擊次數(shù)為1
            {
                ControlState = ControlState.Pressed;//按下的狀態(tài)
            }
            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)//鼠標(biāo)彈起
        {
            if (e.Button == MouseButtons.Left && e.Clicks == 1)
            {
                if (ClientRectangle.Contains(e.Location))//控件區(qū)域包含鼠標(biāo)的位置
                {
                    ControlState = ControlState.Hover;
                }
                else
                {
                    ControlState = ControlState.Normal;
                }
            }
            base.OnMouseUp(e);
        }
        public RoundButton()
        {
            ForeColor = Color.White;
            Radius = 20;
            this.FlatStyle = FlatStyle.Flat;
            this.FlatAppearance.BorderSize = 0;
            this.ControlState = ControlState.Normal;
            this.SetStyle(
             ControlStyles.UserPaint |  //控件自行繪制,而不使用操作系統(tǒng)的繪制
             ControlStyles.AllPaintingInWmPaint | //忽略背景擦除的Windows消息,減少閃爍,只有UserPaint設(shè)為true時(shí)才能使用。
             ControlStyles.OptimizedDoubleBuffer |//在緩沖區(qū)上繪制,不直接繪制到屏幕上,減少閃爍。
             ControlStyles.ResizeRedraw | //控件大小發(fā)生變化時(shí),重繪。
             ControlStyles.SupportsTransparentBackColor, //支持透明背景顏色
             true);
        }

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

            // 盡可能高質(zhì)量繪制
            e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
            e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;

            Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
            var path = GetRoundedRectPath(rect, radius);

            this.Region = new Region(path);

            Color baseColor;
            //Color borderColor;
            //Color innerBorderColor = this._baseColor;//Color.FromArgb(200, 255, 255, 255); ;

            switch (ControlState)
            {
                case ControlState.Hover:
                    baseColor = this._hoverColor;
                    break;
                case ControlState.Pressed:
                    baseColor = this._pressedColor;
                    break;
                case ControlState.Normal:
                    baseColor = this._normalColor;
                    break;
                default:
                    baseColor = this._normalColor;
                    break;
            }

            using (SolidBrush b = new SolidBrush(baseColor))
            {
                e.Graphics.FillPath(b, path); // 填充路徑,而不是DrawPath
                using (Brush brush = new SolidBrush(this.ForeColor))
                {
                    // 文本布局對(duì)象
                    using (StringFormat gs = new StringFormat())
                    {
                        // 文字布局
                        switch (_textAlign)
                        {
                            case ContentAlignment.TopLeft:
                                gs.Alignment = StringAlignment.Near; 
                                gs.LineAlignment = StringAlignment.Near;
                                break;
                            case ContentAlignment.TopCenter:
                                gs.Alignment = StringAlignment.Center;
                                gs.LineAlignment = StringAlignment.Near;
                                break;
                            case ContentAlignment.TopRight:
                                gs.Alignment = StringAlignment.Far;
                                gs.LineAlignment = StringAlignment.Near;
                                break;
                            case ContentAlignment.MiddleLeft:
                                gs.Alignment = StringAlignment.Near;
                                gs.LineAlignment = StringAlignment.Center;
                                break;
                            case ContentAlignment.MiddleCenter:
                                gs.Alignment = StringAlignment.Center; //居中
                                gs.LineAlignment = StringAlignment.Center;//垂直居中
                                break;
                            case ContentAlignment.MiddleRight:
                                gs.Alignment = StringAlignment.Far;
                                gs.LineAlignment = StringAlignment.Center;
                                break;
                            case ContentAlignment.BottomLeft:
                                gs.Alignment = StringAlignment.Near;
                                gs.LineAlignment = StringAlignment.Far;
                                break;
                            case ContentAlignment.BottomCenter:
                                gs.Alignment = StringAlignment.Center;
                                gs.LineAlignment = StringAlignment.Far;
                                break;
                            case ContentAlignment.BottomRight:
                                gs.Alignment = StringAlignment.Far;
                                gs.LineAlignment = StringAlignment.Far;
                                break;
                            default:
                                gs.Alignment = StringAlignment.Center; //居中
                                gs.LineAlignment = StringAlignment.Center;//垂直居中
                                break;
                        }
                        // if (this.RightToLeft== RightToLeft.Yes)
                        // {
                        //     gs.FormatFlags = StringFormatFlags.DirectionRightToLeft;
                        // }
                        e.Graphics.DrawString(this.Text, this.Font, brush, rect, gs);
                    }
                }
            }
        }
        /// <summary>
        /// 根據(jù)矩形區(qū)域rect,計(jì)算呈現(xiàn)radius圓角的Graphics路徑
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="radius"></param>
        /// <returns></returns>
        private GraphicsPath GetRoundedRectPath(Rectangle rect, int radius)
        {
            #region 正確繪制圓角矩形區(qū)域
            int R = radius*2;
            Rectangle arcRect = new Rectangle(rect.Location, new Size(R, R));
            GraphicsPath path = new GraphicsPath();
            // 左上圓弧 左手坐標(biāo)系,順時(shí)針為正 從180開始,轉(zhuǎn)90度
            path.AddArc(arcRect, 180, 90);
            // 右上圓弧
            arcRect.X = rect.Right - R;
            path.AddArc(arcRect, 270, 90);
            // 右下圓弧
            arcRect.Y = rect.Bottom - R;
            path.AddArc(arcRect, 0, 90);
            // 左下圓弧
            arcRect.X = rect.Left;
            path.AddArc(arcRect, 90, 90);
            path.CloseFigure();
            return path;
            #endregion
        }

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

參考 C# Winform實(shí)現(xiàn)圓角無(wú)鋸齒按鈕

可以改進(jìn)和實(shí)現(xiàn)的

  • 添加Border,實(shí)現(xiàn)Border顏色和寬度的指定(目前的一個(gè)思路時(shí)利用路徑在外層填充一個(gè)圓角矩形,在內(nèi)層再填充一個(gè)圓角矩形,形成有Border的效果;另一個(gè)思路時(shí),畫路徑時(shí),繪制內(nèi)層路徑和圓環(huán)路徑,Border部分是一個(gè)圓角的圓環(huán)路徑,而后分別填充顏色;還有就是繪制路徑線條,線條作為Border。)
  • 通過(guò)百分比實(shí)現(xiàn)圓角
  • 完全擴(kuò)展Button,通過(guò)標(biāo)志位啟動(dòng)圓角和修改圓角,做到圓角和普通Button共存。
  • 修改使用RectangleF對(duì)象,使用浮點(diǎn)數(shù)繪制矩形和路徑
  • 圓角半徑radius指定為0的處理

Rectangle.Round(RectangleF) 將RectangleF對(duì)象轉(zhuǎn)換為Rectangle,通過(guò)舍入最近的數(shù)。

利用填充內(nèi)外兩層圓角矩形路徑形成Border

【有著致命缺陷(隨后介紹了正確處理的方案)】

控件的Region區(qū)域一定指定,并且要包含全部的Graphics繪制的內(nèi)容,否則顯示不全,包含在Region內(nèi)才能全部顯示出來(lái)。

Region區(qū)域指定的是控件的區(qū)域,表示的是控件的范圍

如下,通過(guò)Border大小 _borderWidth 計(jì)算不同的路徑,指定Region。

矩形區(qū)域長(zhǎng)寬不同,無(wú)法按照等比的方式計(jì)算長(zhǎng)寬方向上固定邊框?qū)挾鹊谋壤灰虼?,?nèi)部的內(nèi)層圓角半徑也無(wú)法準(zhǔn)確計(jì)算,理論采用比例較小的比較合適

// 外層圓角矩形
Rectangle outRect = new Rectangle(0, 0, this.Width, this.Height);
var outPath = outRect.GetRoundedRectPath(_radius);

// 計(jì)算內(nèi)存圓角矩形,不嚴(yán)謹(jǐn)
Rectangle rect = new Rectangle(_borderWidth, _borderWidth, this.Width - _borderWidth*2, this.Height - _borderWidth*2);
var path = rect.GetRoundedRectPath(_radius);

//this.Region = new Region(path);
// 必須正確指定外層路徑outPath的全部區(qū)域,否則無(wú)法顯示完全填充的全部
this.Region = new Region(outPath);

然后分別填充兩個(gè)路徑:

using (SolidBrush borderB = new SolidBrush(_borderColor))
{
    e.Graphics.FillPath(borderB, outPath);
}

using (SolidBrush b = new SolidBrush(baseColor))
{
    e.Graphics.FillPath(b, path); // 填充路徑,而不是DrawPath 
}

通過(guò)縮放實(shí)現(xiàn)正確的內(nèi)外兩層圓角矩形路徑

通過(guò)縮放實(shí)現(xiàn)正確Border的原理主要如下圖所示,長(zhǎng)寬縮小BorderSize大小,圓角半徑同樣縮小BorderSize,兩個(gè)內(nèi)外層圓角矩形的圓角在共同半徑下繪制圓角弧線。

Rectangle.Inflate()方法用于返回Rectangle結(jié)構(gòu)的放大副本,第二三個(gè)參數(shù)表示x、y方向放大或縮小的量。

var innerRect = Rectangle.Inflate(outRect, -borderSize, -borderSize);

則對(duì)應(yīng)得到內(nèi)層圓角路徑為:

GraphicsPath innerPath = innerRect.GetRoundedRectPath(borderRadius - borderSize)

從這里可以看出,需要保證borderSize小于borderRadius

CDI+路徑的填充模式

GraphicsPath的填充模式FillMode默認(rèn)是FillMode.Alternate,所以替代填充可以實(shí)現(xiàn)內(nèi)外兩層的填充實(shí)現(xiàn)Border效果。

填充模式另一個(gè)選項(xiàng)為FillMode.Winding,可實(shí)現(xiàn)環(huán)繞效果,它們都是應(yīng)用在路徑發(fā)生重疊(overlap)時(shí),不同的填充效果??删唧w測(cè)試不同效果

GraphicsPath gp = new GraphicsPath(FillMode.Winding);

直接繪制路徑作為邊框【推薦】**

通過(guò)DrawPath直接繪制邊框,注意寬度的處理。

// 繪制邊框
using (Pen pen = new Pen(_borderColor,_borderWidth*2))
{
    e.Graphics.DrawPath(pen, path);
    // 繪制路徑上,會(huì)有一半位于路徑外層,即Region外面,無(wú)法顯示出來(lái)。因此設(shè)置為雙borderWidth
}

記得同時(shí)修改下文字繪制的區(qū)域范圍問(wèn)題,邊框?qū)挾日紦?jù)了區(qū)域的一部分。否則,在空間很小時(shí),文字會(huì)位于邊框上。

查看效果如下:

最好的處理不要使用_borderWidth*2,而是使用原本大小,繪制的Path縮小在半個(gè)_borderWith范圍內(nèi)。比如:new Rectangle(rect.X + _borderWidth / 2, rect.Y + _borderWidth / 2, rect.Width - _borderWidth, rect.Height - _borderWidth)

在Paint事件中重繪控件為圓角

除了繼承控件(如上面Button)通過(guò)重寫OnPaint方法,實(shí)現(xiàn)圓角的繪制,還可以直接在原生控件的Paint事件方法中,實(shí)現(xiàn)重繪控件為圓角。

后面文章中也介紹了,可以發(fā)現(xiàn)在Paint事件方法中重繪比完全用戶繪制控件,圓角和各個(gè)部分有著更少的鋸齒,幾乎沒(méi)有,看起來(lái)相對(duì)更好一些,也因此較為推薦在Paint事件中實(shí)現(xiàn)圓角。

【可以直接對(duì)比兩者效果】

比如,對(duì)于Button設(shè)置如下樣式,并添加Paint事件方法

button1.Paint += Button1_Paint;
button1.FlatStyle = FlatStyle.Flat;
button1.FlatAppearance.BorderSize = 0;
button1.FlatAppearance.MouseDownBackColor = Color.Transparent;
button1.FlatAppearance.MouseOverBackColor = Color.Transparent;
button1.FlatAppearance.CheckedBackColor = Color.Transparent;

可實(shí)現(xiàn)效果如下:

具體實(shí)現(xiàn)和代碼參見 Winform控件優(yōu)化Paint事件實(shí)現(xiàn)圓角組件及提取繪制圓角的方法

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

相關(guān)文章

最新評(píng)論