C# winform中不规则窗体制作的解决方案

作者:杨丹
C winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题) - 乂乂 - 一个人,一支烟  ·~~相信每个编程爱好者都希望自己的程序不仅性能优越而且有一个美观的界面,一个区别于别人的程序的个性化的界面。然而以前烦琐的API调用和大量的代码使大家望而却步。现在好了,在C#中通过少量的代码就可以实现不规则窗体的制作。如果您有兴趣就接着往下看吧。C winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题) - 乂乂 - 一个人,一支烟  ·~~

一、在说我用的方法前,我不得不说一下另一种方法,这种方法在实现不规则窗体自身显示效果(即除开窗体的移动、最大最小话、关闭等)时是不用编代码 的。非常简便,但它的致命缺点就是要要求程序运行环境在24位色以下,否则不规则窗体的透明部分就会显示出来,窗体会非常难看。

C winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题) - 乂乂 - 一个人,一支烟  ·~~方法1:
      步骤1:先用图象处理软件制作您的不规则窗体的位图BMP(最好是位图,其它的我没有试过:))。制作时请注意将背景色(即需要设置成透明的颜色部分)设置成与非背景图片颜色反差较大的颜色,并且使用一种容易记忆的颜色。如下图:

C winform中不规则窗体制作的解决方案 - 乂乂 - 一个人,一支烟  ·~~
图中黄颜色背景将要设置成透明部分

步骤2:新建windows应用程序。创建windows窗体并设置窗体基本属性。
(1)将 FormBorderStyle 属性设置为 None。
(2)将窗体的 BackgroundImage 属性设置为先前创建的位图文件。不必将文件添加到项目系统中;这将在指定该文件作为背景图像时自动完成。
(3)将 TransparencyKey 属性设置为位图文件的背景色,本例中为黄色。(此属性告诉应用程序窗体中的哪些部分需要设置为透明。 )
  上面两个步骤已经完成了不规则窗体自身显示效果的制作,此刻您要做的就是为窗体添加移动、关闭、最大最小化的事件。这个将在方法2中详细介绍。
  方法1在24位色以下的环境中可以显示正常,但在24位色以上时黄色背景不能消失,所以方法1不能胜任24位色以上环境。
    为了解决这个问题,我们可以用到方法2

C winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题) - 乂乂 - 一个人,一支烟  ·~~方法2
步骤1:同方法1,先用图象处理软件制作您的不规则窗体的位图BMP
步骤2:创建windows应用程序。创建windows窗体。
      由于方法2是调用类来实现制作不规则窗体,所以您只需要在窗体的LOAD事件中加入以下代码:
 private void login_Load(object sender, System.EventArgs e)
  {
   //初始化调用不规则窗体生成代码
    BitmapRegion BitmapRegion =new BitmapRegion();//此为生成不规则窗体和控件的类
   BitmapRegion.CreateControlRegion(this,new Bitmap("HMlogin.bmp"));
  }
其中"HMlogin.bmp"为您制作的位图。

下面就是文件BitmapRegion.cs

/***************************************************************************************/
//  功能描述:不规则窗体和控件的生成类
/***************************************************************************************/

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.
Windows.Forms;
namespace FallingGold
{
  ///
  /// 说明:图片轮廓类,通过这个类提供的方法得到图片的外围轮廓
  /// 作者:周公
  /// 原创地址:http://blog.csdn.net/zhoufoxcn/archive/2008/06/06/2515753.aspx
  ///
  public class BitmapRegion
  {
    public BitmapRegion()
    { }
    public static void CreateControlRegion(Control control, Bitmap bitmap)
    {
      //如果控件或者图象为空
      if (control == null || bitmap == null)
      {
        return;
      }
      //将控件设置成图象一样的尺寸
      control.Width = bitmap.Width;
      control.Height = bitmap.Height;
      //如果处理的是一个窗体对象
      if (control is System.Windows.Forms.Form)
      {
        Form form = control as Form; //强制转换为Form实例
        //将窗体的尺寸设置成比图片稍微大一点,这样就不用显示窗体边框
        form.Width += 15;
        form.Height += 35;
        //设置窗体无边框
        form.FormBorderStyle = FormBorderStyle.None;
        //设置窗体背景
        form.BackgroundImage = bitmap;
        //根据图片计算路径
        GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);
        //应用区域
        form.Region = new Region(graphicsPath);
      }
      //如果处理的是一个按钮对象
      else if (control is System.Windows.Forms.Button)
      {
        Button button = control as Button; //强制转换为Button实例
        //不显示文字
        button.Text = "";
        //当鼠标处在上方时更改光标状态
        button.Cursor = Cursors.Hand;
        //设置背景图片
        button.BackgroundImage = bitmap;
        //根据图片计算路径
        GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);
        //应用区域
        button.Region = new Region(graphicsPath);
      }
     
    }
    ///
    /// 通过逼近的方式扫描图片的轮廓
    ///
    /// 要扫描的图片
    ///

    private static GraphicsPath CalculateControlGraphicsPath(Bitmap bitmap)
    {
      GraphicsPath graphicsPath = new GraphicsPath();
      //将图片的(0,0)处的颜色定义为透明色
      Color transparentColor = bitmap.GetPixel(0, 0);
      //存储发现的第一个不透明的象素的列值(即x坐标),这个值将定义我们扫描不透明区域的边缘
      int opaquePixelX = 0;
      //从纵向开始
      for (int y = 0; y < bitmap.Height; y++)
      {
        opaquePixelX = 0;
        for (int x = 0; x < bitmap.Width; x++)
        {
          if (bitmap.GetPixel(x, y) != transparentColor)
          {
            //标记不透明象素的位置
            opaquePixelX = x;
            //记录当前位置
            int nextX = x;
            for (nextX = opaquePixelX; nextX < bitmap.Width; nextX++)
            {
              if (bitmap.GetPixel(nextX, y) == transparentColor)
              {
                break;
              }
            }
            graphicsPath.AddRectangle(new Rectangle(opaquePixelX, y, nextX - opaquePixelX, 1));
            x = nextX;
          }
        }
      }
      return graphicsPath;
    }
  }
}


 完成窗口自身效果后此刻您要做的就是为窗体添加移动、关闭、最大最小化的事件代码了。

 1、首先,关闭很简单,只需要在您的事件中加入
   this.Close();//关闭此窗体
   或
  Application.Exit();//退出应用程序 
 2、最大最小化事件也很简单
   this.WindowState=FormWindowState.Minimized;//窗口最小化   
   this.WindowState=FormWindowState.Maximized;//窗口最大化
 3、移动相对比较麻烦
   你先需要建立两个全局变量:
   private Point mouseOffset;        //记录鼠标指针的坐标
    private bool isMouseDown = false; //记录鼠标按键是否按下

然后为您的事件加入相应的代码:
private void form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
  {
   int xOffset;
   int yOffset;

   if (e.Button == MouseButtons.Left)
   {
    xOffset = -e.X - SystemInformation.FrameBorderSize.Width;
    yOffset = -e.Y - SystemInformation.CaptionHeight -
     SystemInformation.FrameBorderSize.Height;
    mouseOffset = new Point(xOffset, yOffset);
    isMouseDown = true;
   }
  }

  private void form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
  {
   if (isMouseDown)
   {
    Point mousePos = Control.MousePosition;
    mousePos.Offset(mouseOffset.X, mouseOffset.Y);
    Location = mousePos;
   }
  }

  private void form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
  {
   // 修改鼠标状态isMouseDown的值
   // 确保只有鼠标左键按下并移动时,才移动窗体
   if (e.Button == MouseButtons.Left)
   {
    isMouseDown = false;
   }
  }

程序的执行情况如下图:
C winform中不规则窗体制作的解决方案 - 乂乂 - 一个人,一支烟  ·~~

    C winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题) - 乂乂 - 一个人,一支烟  ·~~ 总结:我在了解到方法2前也是一直用的方法1,在24位色下不能正常显示的问题我也头疼了很久,当时在MSDN上找的文章居然都说是 ------------“请确保您的用户是在24位色以下环境中使用本程序”!!!晕死了,这个怎么行?!现在有了方法2就好了,自己解决了问题不敢独 享,那出来给大家看看。
          另外,方法2中的类也支持制作不规则的button控件,有兴趣的朋友可以试试。
我将此文发到首页合乎博客园规范吗?如果不,请斑竹提醒,我想这篇文章对大家还是有用的。

【from http://zamuj.blog.hexun.com/15267044_d.html
原文地址:https://www.cnblogs.com/chlyzone/p/1980038.html