现在,C#创建不规则窗体不是一件难事,下面总结一下:
一、自定义窗体
一般为规则的图形,如圆、椭圆等。
做法:重写Form1_Paint事件(Form1是窗体的名字),最简单的一种情况如下:
- System.Drawing.Drawing2D.GraphicsPath shape = new System.Drawing.Drawing2D.GraphicsPath();
- shape.AddEllipse(0,0,this.Height, this.Width);
- this.Region = new Region(shape);
即重绘窗体的规则。
二、利用背景图片实现
1. 设置窗体的背景图片,其中背景图片是24位(不包括24)以下的位图(BMP图片),并且要设置TansparencyKey的值,一般为你背景图片的背景色,即创建不规则图片时的底色,一般设为你图片中没有的颜色。
这种做法的不好的地方就是背景图片一定要16位或者更低的,而且还要确保客户端的显示。如果监视器的颜色深度设置大于 24 位,则不管 TransparencyKey 属性是如何设置的,窗体的非透明部分都会产生显示问题。若要避免出现这种问题,请确保“显示”控制面板中的监视器颜色深度的设置小于 24 位。当开发具有这种透明功能的应用程序时,请牢记应使您的用户意识到此问题。
实现步骤如下:
1. 新建windows application
2. 选择窗体,找到BackgroundImage属性,点击打开新的窗口,选择下面的导入资源文件,选择你的不规则的BMP图片
3. 找到窗体的TansparencyKey,将它设置为你背景图片的背景色(如黄色)
4. 找到窗体的FormBorderStyle,将其设置为none,即不显示标题栏
5. 运行
<!--[endif]-->
2. 跟背景图片一样的图形,不过是动态加载,遍历位图以实现不规则窗体。它的原理是这样的,在Form的load事件中写方法使得窗体的描绘区域发生改变。
实现步骤如下:
1. 建立winform应用程序
2. 找到窗体的Load事件,双击进行编辑
3. 编写方法,主要的代码如下:
- class BitmapRegion
- {
- public BitmapRegion()
- { }
- /// <summary>
- /// Create and apply the region on the supplied control
- /// 创建支持位图区域的控件(目前有button和form)
- /// </summary>
- /// <param name="control">The Control object to apply the region to控件</param>
- /// <param name="bitmap">The Bitmap object to create the region from位图</param>
- public static void CreateControlRegion(Control control, Bitmap bitmap)
- {
- // Return if control and bitmap are null
- //判断是否存在控件和位图
- if (control == null || bitmap == null)
- return;
- // Set our control''s size to be the same as the bitmap
- //设置控件大小为位图大小
- control.Width = bitmap.Width;
- control.Height = bitmap.Height;
- // Check if we are dealing with Form here
- //当控件是form时
- if (control is System.Windows.Forms.Form)
- {
- // Cast to a Form object
- //强制转换为FORM
- Form form = (Form)control;
- // Set our form''s size to be a little larger that the bitmap just
- // in case the form''s border style is not set to none in the first place
- //当FORM的边界FormBorderStyle不为NONE时,应将FORM的大小设置成比位图大小稍大一点
- form.Width = control.Width;
- form.Height = control.Height;
- // No border
- //没有边界
- form.FormBorderStyle = FormBorderStyle.None;
- // Set bitmap as the background image
- //将位图设置成窗体背景图片
- form.BackgroundImage = bitmap;
- // Calculate the graphics path based on the bitmap supplied
- //计算位图中不透明部分的边界
- GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);
- // Apply new region
- //应用新的区域
- form.Region = new Region(graphicsPath);
- }
- // Check if we are dealing with Button here
- //当控件是button时
- else if (control is System.Windows.Forms.Button)
- {
- // Cast to a button object
- //强制转换为 button
- Button button = (Button)control;
- // Do not show button text
- //不显示button text
- button.Text = "";
- // Change cursor to hand when over button
- //改变 cursor的style
- button.Cursor = Cursors.Hand;
- // Set background image of button
- //设置button的背景图片
- button.BackgroundImage = bitmap;
- // Calculate the graphics path based on the bitmap supplied
- //计算位图中不透明部分的边界
- GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);
- // Apply new region
- //应用新的区域
- button.Region = new Region(graphicsPath);
- }
- }
- /// <summary>
- /// Calculate the graphics path that representing the figure in the bitmap
- /// excluding the transparent color which is the top left pixel.
- /// //计算位图中不透明部分的边界
- /// </summary>
- /// <param name="bitmap">The Bitmap object to calculate our graphics path from</param>
- /// <returns>Calculated graphics path</returns>
- private static GraphicsPath CalculateControlGraphicsPath(Bitmap bitmap)
- {
- // Create GraphicsPath for our bitmap calculation
- //创建 GraphicsPath
- GraphicsPath graphicsPath = new GraphicsPath();
- // Use the top left pixel as our transparent color
- //使用左上角的一点的颜色作为我们透明色
- Color colorTransparent = bitmap.GetPixel(0, 0);
- // This is to store the column value where an opaque pixel is first found.
- // This value will determine where we start scanning for trailing opaque pixels.
- //第一个找到点的X
- int colOpaquePixel = 0;
- // Go through all rows (Y axis)
- // 偏历所有行(Y方向)
- for (int row = 0; row < bitmap.Height; row++)
- {
- // Reset value
- //重设
- colOpaquePixel = 0;
- // Go through all columns (X axis)
- //偏历所有列(X方向)
- for (int col = 0; col < bitmap.Width; col++)
- {
- // If this is an opaque pixel, mark it and search for anymore trailing behind
- //如果是不需要透明处理的点则标记,然后继续偏历
- if (bitmap.GetPixel(col, row) != colorTransparent)
- {
- // Opaque pixel found, mark current position
- //记录当前
- colOpaquePixel = col;
- // Create another variable to set the current pixel position
- //建立新变量来记录当前点
- int colNext = col;
- // Starting from current found opaque pixel, search for anymore opaque pixels
- // trailing behind, until a transparent pixel is found or minimum width is reached
- ///从找到的不透明点开始,继续寻找不透明点,一直到找到或则达到图片宽度
- for (colNext = colOpaquePixel; colNext < bitmap.Width; colNext++)
- if (bitmap.GetPixel(colNext, row) == colorTransparent)
- break;
- // Form a rectangle for line of opaque pixels found and add it to our graphics path
- //将不透明点加到graphics path
- graphicsPath.AddRectangle(new Rectangle(colOpaquePixel, row, colNext - colOpaquePixel, 1));
- // No need to scan the line of opaque pixels just found
- col = colNext;
- }
- }
- }
- // Return calculated graphics path
- return graphicsPath;
- }
- }
4. 运行
<!--[endif]-->
三、调用类库实现
主要就是根据一些坐标,然后根据这些坐标绘制窗体
代码如下:
- public Form3()
- {
- InitializeComponent();
- //创建不规则窗体
- POINTAPI[] poin;
- poin = new POINTAPI[5];
- poin[0].x = 90;
- poin[0].y = 90;
- poin[1].x = this.Width;
- poin[1].y = 0;
- poin[2].x = Width;
- poin[2].y = this.Height / 2;
- poin[3].x = Width / 2;
- poin[3].y = Height / 2;
- poin[4].x = 0;
- poin[4].y = Width;
- Boolean flag = true;
- IntPtr hRgn = CreatePolygonRgn(ref poin[0], 8, 1);
- SetWindowRgn(this.Handle, hRgn, ref flag);
- this.BackColor = Color.BurlyWood;
- }
- [StructLayout(LayoutKind.Sequential)]
- private struct POINTAPI
- {
- internal int x;
- internal int y;
- }
- [DllImport("gdi32.dll")]
- private static extern IntPtr CreatePolygonRgn(ref POINTAPI lpPoint,int nCount,int nPolyFillMode);
- [DllImport("user32.dll")]
- private static extern IntPtr SetWindowRgn(IntPtr hWnd,IntPtr hRgn, ref Boolean bRedraw);
- //设置窗体显示状态
- [DllImport("user32.dll")]
- private static extern int SetWindowPos(IntPtr hwnd,int hWndInsertAfter,int x,int y,int cx,int cy,int wFlags);
- private void Start_Btn_Click(object sender, EventArgs e)
- {//始终显示在前面
- SetWindowPos(this.Handle, -1, 0, 0, 0, 0, 1);
- }
- private void button1_Click(object sender, EventArgs e)
- {
- //最小化始终显示在前面
- SetWindowPos(this.Handle, -1, 0, 0, 0, 0, 0);
- }
当然,我们也可以自定义窗体的动作,如按着某个轨迹一定,下面的代码中的BackgroundForm程序中就小试了一下,效果还不错,下面是这些程序的效果图(有点乱)和代码:
代码下载:http://files.cnblogs.com/alexis/IrregularForm.rar
代码是.Net 2.0的,也可以转换为其他版本的,只要运行主程序即可。
以上的四种方法有利也有弊,希望大家提意见或者更好的解决方案。
发表评论
-
(转)ASP.NET文件上传控件——WebbUpload我下载了这个组件后做了一些修改并应用了ajax技术
2010-12-06 16:28 980我下载了这个组件后做了一些修改并应用了ajax技术,你们可以去 ... -
ASP.NET 下载管理的基础篇
2010-10-13 11:20 838很多时候一个网站是需要对文件下载进行管理的,不是任何人都允许下 ... -
C#实现获取CPU使用率的方法
2010-10-13 11:09 2129无需多说,直接上代码 using System; ... -
用C#取得远程IP地址,MAC地址的方法
2010-10-13 11:05 1291经常需要获得远程的地址,需要用sendarp这个函数来实现。具 ... -
C#在应用程序中实现自动升级(转)
2010-10-11 12:06 5895这是本人第一次写比较复杂的文章,表达不清之处,请各位见谅。好, ... -
.Net垃圾收集机制 了解算法与代龄
2010-10-08 17:40 634垃圾收集器在本质上就是负责跟踪所有对象被引用到的地方,关注 ... -
深入了解Array,弄个明明白白
2010-10-08 17:28 6931. 数组大局观 数组是一个引用类型,也就是意味着数 ... -
Asp.Net如何实现断点续传
2010-10-08 17:07 1069断点续传的原理 ... -
编码实现动态调用WebService的方法
2010-10-08 11:00 1688调用方法,同时也支持带ref参数的 /// ... -
ASP.NET得到当前代码位置的类名和方法名
2010-10-08 10:31 966protected void writeerror(obje ... -
文本字符的html格式转换
2010-10-08 10:23 762前一段仿泡泡网做了个论坛,遇到了个文本符号转化成相应htm ... -
C#串口serialPort操作
2010-10-08 10:20 1611现在大多数硬件设备均采用串口技术与计算机相连,因此串口的应 ... -
浅解XML与DataSet对象的关系及转换
2010-09-30 13:39 969在.NET Framework 中,经常使用XML 作为存储和 ... -
用Visual Studio来自动化测试
2010-09-30 13:32 1103自动化测试的实现 编写自动化测试也许对很多测试人员来说比较陌 ... -
10个C#编程和Visual Studio使用技巧
2010-09-30 13:29 779C#是一门伟大的编程语言,与C++和Java相比,它的语法更简 ...
相关推荐
C#创建不规则窗体的几种方式,对winform的不规则窗体开发一定是最不错的学习哟!
.NET20 一种简单的窗口控件UI状态控制方法 翻译MSDN文章 —— 泛型FAQ:最佳实践 Visual C# 3.0 新特性概览 C# 2.0会给我们带来什么 泛型技巧系列:如何提供类型参数之间的转换 C#2.0 - Object Pool 简单实现 ...
4.7 无标题窗体拖动的两种方法 183 4.8 让程序只启动一次——单实例运行 184 4.9 实现系统托盘和热键呼出 185 4.10 进程与多线程的区别 190 4.11 创建多线程应用程序 191 4.12 WinForm开发常见问题 194 4.12.1 如何...
4.7 无标题窗体拖动的两种方法 183 4.8 让程序只启动一次——单实例运行 184 4.9 实现系统托盘和热键呼出 185 4.10 进程与多线程的区别 190 4.11 创建多线程应用程序 191 4.12 WinForm开发常见问题 194 4.12.1 如何...
1.2 .NET 与 C#.6 1.3 C#语言的特点.8 1.4 小 结 .11 第二章 运行环境 全面了解.NET.12 2.1 .NET 结构.12 2.2 公用语言运行时环境与公用语言规范.13 2.3 开 发 工 具 .17 2.4 小 结 .19 第三章 编写...
6.如果在一个B/S结构的系统中需要传递变量值,但是又不能使用Session、Cookie、Application,您有几种方法进行处理? 答 : this.Server.Transfer 7.请编程遍历页面上所有TextBox控件并给它赋值为string.Empty? ...
下拉列表只列出了几种常见的,若需要从中提取图片的分页的链接末尾不符合其中任何一种正则表达式,用户可自行手动输入。 如果不从二级页面中提取图片,只提取指定网页中的图片,分页正则表达式一栏不填或者选择...
下拉列表只列出了几种常见的,若需要从中提取图片的分页的链接末尾不符合其中任何一种正则表达式,用户可自行手动输入。 如果不从二级页面中提取图片,只提取指定网页中的图片,分页正则表达式一栏不填或者选择...
ExtAspNet - ExtJS based ASP.NET Controls with Full AJAX Support ExtAspNet是一组专业的Asp.net控件库,拥有原生的AJAX支持和丰富的UI效果, 目标是创建没有ViewState,没有JavaScript,没有CSS,没有...
-在2009-03-03 v1.3.0曾经提到这个兼容问题,并有这样的规则,如果Asp.net的按钮AJAX提交,必须设置UseSubmitBehavior="false" --也就是说生成的input的type不能是"submit",而这个限制在有些情况下是不可原谅的...
7.7.2 创建规则类,离开最不成熟的阶段 7.7.3 设置规则列表 7.7.4 使用规则列表 7.7.5 处理子列表 7.7.6 一个API改进 7.7.7 自定义 7.7.8 为使用者提供元数据 7.7.9 是否适合用模式来解决此问题 7.7.10 复杂规则又是...
代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...
代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...
代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...
代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...
代码里用了备份dll的方法,因此在自定义的函数中可以直接调用在内存中备份的dll代码,而不需要再把函数头部改来改去。 IOCP反弹远控客户端模型,外加上线服务端,全部代码注释! 如题。这个是IOCP远程控制软件的...
用递归的方法画分形图 ...完全支持动态换肤(*.rss),支持不规则窗体,支持美工设计自定义界面生成方案。 完全多线程,自定义窗口类换肤支持。 内含15种专业皮肤(.rss)文件。 内含SkinDesigner 皮肤文件开发工具。 ...
18:单线程下载时不能创建临时文件. 19:下载流文件(rm,Media Player). Notepad++ V5.6.8 源码! 如题。 OA精灵代码 c++版 一套oa系统。 ocxdlgtest dll的一个实例。 OD反汇编引擎(带VC修改版和原版) 如题。主要...