用C#实现不规则窗体

本文介绍如何利用背景图片和代码实现不规则形状的窗体,并详细解释了通过捕捉鼠标点击和移动事件来实现窗体移动的方法。


作者:光脚丫思考 524130780@QQ.COM
文档创建时间:1/1/2010 9:52:59 PM

如何实现不规则窗体?
TransparencyKey:获取或设置将表示窗体透明区域的颜色。
FormBorderStyle:获取或设置窗体的边框样式。
BackgroundImage:获取或设置在控件中显示的背景图像。

首先,使用图像处理软件制作出所要实现的窗体样式,最后实现的窗体样式就和绘制的图片一样。然后,将窗体的BackgroundImage属性设置为所绘制的图片。根据图片的大小设置窗体的大小,即窗体的宽度等于图片的宽度,窗体的高度等于图片的高度。之所以这样做,是为了避免背景图片在窗体上的重复显示。
接着,将窗体的FormBorderStyle设置为None,也即不要显示窗体的边框。这样便只显示带有背景的窗体内容区,此时看起来整个窗体就和所指定的背景图片一致。但是此时实现的窗体样式仍然是规规矩矩的四边形。只要将图片中的背景颜色修改为透明色,那么整个窗体的样式就和图片中的绘图区域保持一致了。要实现这点可以将窗体的TransparencyKey设置为图片的背景颜色,这样以来,当窗体运行时,窗体的背景图片中包含此颜色的区域都将被透明化。(应该是这样的,可是实现的代码中貌似不是这样的,那个背景色还是存在的。)
还有一点,由于将窗体的FormBorderStyle设置为None,窗体便没有了标题栏,因此默认情况下窗体不可移动。下面将自己实现窗体的移动效果。


如何实现窗体的移动?
Location:设置或获取窗体在屏幕中的位置。
通过修改Location的属性值达到修改窗体在屏幕中位置的目的。通常是通过单击鼠标左键并移动鼠标来移动窗体的。也就是说,鼠标在窗体上移动的情况至少有2种,其一是不单击鼠标左键的移动,此时代码不需要随着鼠标的移动来移动窗体;其二是单击鼠标左键的同时移动鼠标,此时就需要跟随鼠标来移动窗体了。要实现的要过和通过窗体标题栏移动是一样的,只是我们要让它在窗体的任意区域都能够移动。
可以通过Control.MousePosition属性获取鼠标单击左键时的坐标,此坐标属于屏幕坐标系统。同样的,窗体的Location也是屏幕坐标系统,这和窗体上的控件的Location是不一样的,控件的Location是窗体范围内的坐标系统,即,坐标X值和坐标Y值是相对于窗体左上角X=0,Y=0的位置而确定的。而Control.MousePosition和窗体的Location则是相对于屏幕左上角的位置而言的。
知道了鼠标左键单击时所处的屏幕坐标点,也知道窗体左上角在鼠标左键单击时的屏幕坐标点,通过这2个坐标点就可以计算出窗体左上角相对于鼠标单击时的屏幕坐标点的偏移量。然后,随着鼠标的不断移动,代码随时获取鼠标移动后所处的屏幕坐标点,将这个新的坐标点和前面计算出的偏移量再次进行计算,就可以获取屏幕随着鼠标移动后应处的位置,再把这个值赋给窗体的Location属性,窗体不就随着鼠标而移动了吗!!!^_^

代码如下:

首先定义两个似有变量,一个用来保存鼠标单击点和窗体左上角的偏移量,一个用来标记鼠标左键是否正处于按下状态。

/// <summary> /// 用来记录鼠标的偏移量。 /// </summary> Point MouseOffset = new Point(); /// <summary> /// 用来标记鼠标左键是否已经按下,如果按下则为true;否则为false。 /// </summary> bool IsMouseLeftButtonDown = false;


当鼠标在窗体上单击左键时,获取鼠标此时的屏幕坐标值,并与窗体的Location进行计算,得出偏移量。

private void MainForm_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { this.IsMouseLeftButtonDown = true; Point MousePosition = Control.MousePosition; int XOffset = MousePosition.X - this.Location.X; int YOffset = MousePosition.Y - this.Location.Y; this.MouseOffset = new Point(XOffset, YOffset); } }


接着就该开始移动鼠标了,在移动鼠标时确定按下鼠标左键,然后获取鼠标移动后的坐标值,与前面计算的偏移量进行计算,得出窗体左上角的屏幕坐标值,并将其赋给窗体的Location。

private void MainForm_MouseMove(object sender, MouseEventArgs e) { if (this.IsMouseLeftButtonDown) { Point MousePosition = Control.MousePosition; MousePosition.Offset(-this.MouseOffset.X, -this.MouseOffset.Y); this.Location = MousePosition; } }

代码中为什么偏移量的X、Y值都取负值呢?这是由窗体左上角位置和鼠标单击时位置的对应关系确定的。既然是在窗体上单击鼠标,那么其单击点的X和Y值就必定要比窗体左上角的X和Y值大,取负值实际上等于是减去偏移量的值。

当鼠标左键松开时,就该停止移动窗体了。
private void MainForm_MouseUp(object sender, MouseEventArgs e) { this.IsMouseLeftButtonDown = false; }

把IsMouseLeftButtonDown设置为false之后,鼠标的MouseMove事件还是会继续触发的,只是将不会在执行移动窗体的那段代码,因为If条件已经不成立了。

搜索了一下前面的那个位图的背景色不能被去掉的问题,有说法是这样的:在24位色以下的环境中可以显示正常,但在24位色以上时黄色背景不能消失。为了确认这种说法的正确性,我将【屏幕的颜色质量】设置16位,还真就给正确显示了。不过16位的颜色质量确实是不及32位的。总不能为了运行这个不规则的窗体程序,每次都来修改屏幕颜色质量吧?那也太过分了一点!当然可以自己编写代码来解决这个问题,但此文到此为止。^_^

完整代码如下:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace IrregularWindows { public partial class MainForm : Form { /// <summary> /// 用来记录鼠标的偏移量。 /// </summary> Point MouseOffset = new Point(); /// <summary> /// 用来标记鼠标左键是否已经按下,如果按下则为true;否则为false。 /// </summary> bool IsMouseLeftButtonDown = false; public MainForm() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { } /// <summary> /// 关闭应用程序。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ExitButton_Click(object sender, EventArgs e) { this.Close(); } private void MainForm_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { this.IsMouseLeftButtonDown = true; Point MousePosition = Control.MousePosition; int XOffset = MousePosition.X - this.Location.X; int YOffset = MousePosition.Y - this.Location.Y; this.MouseOffset = new Point(XOffset, YOffset); } } private void MainForm_MouseMove(object sender, MouseEventArgs e) { if (this.IsMouseLeftButtonDown) { Point MousePosition = Control.MousePosition; MousePosition.Offset(-this.MouseOffset.X, -this.MouseOffset.Y); this.Location = MousePosition; } } private void MainForm_MouseUp(object sender, MouseEventArgs e) { this.IsMouseLeftButtonDown = false; } } }

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值