C#防闪烁、自定义扩展控件和DGI+部分知识

一、防闪烁的两种方法

1.直接设置窗体的 DoubleBuffered 属性

public partial class MyForm : Form

{

    public MyForm()

    {

        InitializeComponent();

        this.DoubleBuffered = true; // 启用双缓冲

    }

}

2.通过 SetStyle 方法启用双缓冲

public partial class MyForm : Form

{

    public MyForm()

    {

        InitializeComponent();

        SetStyle(ControlStyles.OptimizedDoubleBuffer |

                 ControlStyles.AllPaintingInWmPaint |

                 ControlStyles.UserPaint, true);

    }

}

3.修改窗体的扩展样式(WS_EX_COMPOSITED)

通过设置 CreateParams 的 ExStyle 属性,启用系统级别的双缓冲。

  protected override CreateParams CreateParams
  {
      get
      {
          CreateParams cp = base.CreateParams;
          cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
          return cp;
      }
  }

4.禁用清除背景消息(WM_ERASEBKGND)

窗体在重绘时会频繁清除背景(WM_ERASEBKGND),禁用此消息可减少闪烁

  protected override void WndProc(ref Message m)
  {
      if (m.Msg == 0x0014) // WM_ERASEBKGND 消息
      {
          return; // 直接返回,不处理清除背景
      }
      base.WndProc(ref m);
  }

二、自定义控件,扩展控件如何建立

1.扩展控件建立

1.1添加用户控件或者窗体控件

1.2将继承的UserCotrol改为继承Button

  public partial class ButtonExtension : Button
  {
      public ButtonExtension()
      {
          InitializeComponent();
      }

      // 给Button扩展事件,属性,方法。

     。。。。。。。
  }

1.3生成解决方案

1.4双击错误列表中的错误内容,跳转到ButtonExtension.Designer,删除或注释错误代码  this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

2.自定义控件建立

1.1添加用户控件或者窗体控件

1.2将继承的UserCotrol改为继承Button

  public partial class MyButton : Control
  {
      public MyButton()
      {
          InitializeComponent();
      }     
  }

1.3生成解决方案

1.4双击错误列表中的错误内容,跳转到MyButton.Designer,删除或注释错误代码 

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

三、SetStyle()给自定义控件设置风格

    UserPaint: 指定控件必须调用 OnPaint 方法来绘制自己,而不是使用默认的绘制逻辑。这通常用于自定义控件的绘制。

    AllPaintingInWmPaint: 指定所有的绘制操作都应该在 WM_PAINT 消息处理中完成。这有助于减少闪烁,因为它确保了所有的绘制都通过一个单一的绘制消息进行。

    DoubleBuffer: 启用双缓冲,减少闪烁和图形失真。在.NET Framework 2.0之前,这是实现双缓冲的常用方法。

    OptimizedDoubleBuffer: 启用优化的双缓冲。这是在.NET Framework 2.0及更高版本中推荐的方法,因为它提供了更好的性能。

    ResizeRedraw: 当控件调整大小时,控件将重绘自身。默认情况下,控件在调整大小时不会重绘,除非设置了这个样式。

    SupportsTransparentBackColor: 允许控件的背景色是透明的。

    StandardClick: 指定控件响应标准的鼠标点击。如果未设置此样式,控件可能不会响应点击事件。

    Selectable: 指定控件可以被选中,通常用于键盘导航。

    UserMouse: 指定控件将处理鼠标事件,即使鼠标不在控件的区域内。

    UseAntiAlias: 指定控件使用抗锯齿技术来绘制文本和图形。

    UseSmoothScrolling: 指定控件使用平滑滚动。
    this.SetStyle(ControlStyles.UserPaint, true);  //***
    this.SetStyle(ControlStyles.ResizeRedraw, true); //***

    this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
    this.SetStyle(ControlStyles.StandardClick, true);
    this.SetStyle(ControlStyles.Selectable, true); //*** 能交互时,尽量让能选中,不能交互时,就不要设置这个样式。

    // 简写成如下代码:
    /*this.SetStyle(ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.StandardClick | ControlStyles.Selectable | ControlStyles.UserMouse , true);

}

四、使用GDI+对控件进行完全重绘步骤

  protected override void OnPaint(PaintEventArgs e)
  {
      // base表示基类
      base.OnPaint(e);

      // 1.拿到要绘制的“画板,画布”,目的:将来在此处绘制图形
      Graphics g = e.Graphics;

      // 2.画板的一些配置参数(省略)    Smooth平滑,“锯齿,毛边”
      g.SmoothingMode = SmoothingMode.AntiAlias;  // 平滑模式 AntiAlias抗锯齿,HighSpeed高速度,HighQuality高质量
      g.InterpolationMode = InterpolationMode.HighQualityBicubic; // 插补模式
      g.TextRenderingHint = TextRenderingHint.AntiAlias;  // 文本渲染

      g.PixelOffsetMode = PixelOffsetMode.HighQuality; // 像素偏移模式
      g.CompositingQuality = CompositingQuality.HighQuality; // 合成质量
      g.CompositingMode = CompositingMode.SourceOver; // 合成模式

      //3.绘制图形   DrawXXX()绘制  FillXXX()填充
      // 参数:绘制的文字,字体,画笔,绘制的位置
      // Graphics,Font,Brush|Color,Point|F,Rectangle|F
      //g.DrawString("文字", new Font("宋体", 12, FontStyle.Underline), Brushes.Red, new Point(10, 10));
      //g.DrawImage(Properties.Resources.a, new Point(10, 10));

      g.FillRectangle(Brushes.Red, new Rectangle(10, 10, 100, 100));
  }

五、圆角按钮案例

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

namespace MYN_DGI_622.UserControls
{
    public partial class RoundButton : Button
    {
        public RoundButton()
        {
            InitializeComponent();
            //防闪烁
            SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

        }
        private float radius = 10;
        [Description("圆角半径"), DefaultValue(10)]
        public float Radius
        {
            get { return radius; }
            set { radius = value; Refresh(); }
        }

        private Color borderColor = Color.Red;

        [Description("边框颜色"), DefaultValue(typeof(Color), "Red")]

        public Color BorderColor
        {
            get { return borderColor; }
            set { borderColor = value; Refresh(); }
        }
        private float borderWidth = 1;
        [Description("边框宽度"), DefaultValue(1)]
        public float BorderWidth
        {
            get { return borderWidth; }
            set { borderWidth = value; Refresh(); }
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            Graphics g=e.Graphics;
            RectangleF rect=new RectangleF (BorderWidth, BorderWidth, this.Width-2*BorderWidth, this.Height-2*BorderWidth);
            GraphicsPath path = GetRoundedRect(rect, Radius); // 获取圆角矩形路径
            SolidBrush brush = new SolidBrush(this.BackColor);  // 实体画刷

            if (BorderWidth>0)
            {
                var pen = new Pen(BorderColor, BorderWidth);  // 创建画笔
                g.DrawPath(pen, path); // 绘制圆角矩形边框
                this.Region = new Region(rect);
            }
            else
            {
                g.FillPath(brush, path); // 填充圆角矩形区域
                SizeF textSize = g.MeasureString(this.Text, this.Font);
                float x = (rect.Width - textSize.Width) / 2F;
                float y = (rect.Height - textSize.Height) / 2F;
                // 3。绘制文字
                g.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), x, y);
                this.Region = new Region(path);
            }

        }

        private GraphicsPath GetRoundedRect(RectangleF rect, float radius)
        {
           GraphicsPath path=new GraphicsPath();
            if (radius == 0)
            {
                path.AddRectangle(rect);
            }
            else 
            {
                float diameter = radius * 2; // 直径等于半径的两倍。
                int arcAngle = 90; // 圆弧的角度为90度。可以根据需要调整这个值以改变圆角的弧度。
                path.AddArc(rect.X + BorderWidth, rect.Y + BorderWidth, diameter, diameter, 180, arcAngle); // 左上角圆弧。
                path.AddArc(rect.Right - diameter - BorderWidth, rect.Y + BorderWidth, diameter, diameter, 270, arcAngle); // 右上角圆弧(电脑Y坐标上面为负,是270°,下面为正,是90°)
                path.AddArc(rect.Right - diameter - BorderWidth, rect.Bottom - diameter - BorderWidth, diameter, diameter, 0, arcAngle); // 右下角圆弧
                path.AddArc(rect.X + BorderWidth, rect.Bottom - diameter - BorderWidth, diameter, diameter, 90, arcAngle); // 左下角圆弧
                path.CloseFigure();
            }
            return path;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值