使用Visual C#制作可伸缩个性化窗体

原创 2004年08月17日 22:41:00
引言:
谁都希望自己的应用程序能让人留下一个深刻的印象,让自己的程序窗体有一件与众不同的"外衣"是一个好办法。试想:在一大堆的普通窗口中突然跳出一个很酷的界面,一定能让人眼睛一亮进而产生兴趣的。
在VB,VC中如何定制可伸缩个性化窗口早就不是什么秘密了,已经有了大量相关的文章进行介绍,无非都是如何调用系统API之类的方法,但是在.Net中调用API却相对比较麻烦,所以使用.Net制作个性化窗体的文章也有一些,一般都是使用透明背景加图片的方式,所以不能移动或者不能任意放大缩小窗体。那有没有不需要调用系统API的方法来实现可伸缩的个性化窗体的办法呢?当然有,.Net Framework提供了一套非常强大的系统类库,我们下面就要做一个使用"纯".Net打造的可伸缩个性化窗体。
我们需要将窗体所有的"皮肤"全部换成我们自己定义的,包括标题栏,边框和系统按纽等,所以我们首先需要定做一套自己的皮肤图形文件。因为窗体是可伸缩的,所以我们不能简单的取一整幅图片来作为窗体皮肤,而是根据需要先将图片切割为不同的部分,一般来说,有以下图示几大部分(红线为切割线):
根据方位,将图片各部分命名为:Bottom_Left,Bottom_Middle,Bottom_Right,Middle_Left,Middle_Right,Top_Left,Top_Middle,Top_Right,SysButton_Min,SysButton_Max,SysButton_Close,SysButton_Restore等。注意,有些图片是可以伸缩的地方,比如Middle_Left,Bottom_Middle等处的图片可以只是一小块,以后需要进行重复贴图。而有些固定大小的图片,比如Bottom_Left,Top_Left等以后只用贴一次,实际应用的时候要注意区分。
采用以上原则,你便可以制作皮肤图片,图示如下:
然后可以将这些图片放到ImageList控件或资源文件中供程序调用。(关于如何制作资源文件请参考:Visual C#资源文件编程--创建资源文件
接下来,我们使用Visual Studio .Net新建一个Windows应用程序的项目,在窗体的属性设置中,将窗体的FormBorderStyle属性设置为None(无边框样式),如下图所示:
定义一个资源管理器:
private ResourceManager rm ;
然后使用以下的方法在Form的构造函数中将图片取出来(资源文件名为Skin.resources):
rm = new ResourceManager("SkinWindow.Skin", Assembly.GetExecutingAssembly());
Bottom_Left = (Bitmap)rm.GetObject("Bottom_Left");
…(其它的图片也按照此方法取)
重载Form的OnPaint事件:
Graphics g = e.Graphics;
//手工画窗体的各个部分
DrawMiddle_Left(e.Graphics);//画左边框
DrawBottom_Middle(e.Graphics);//画下边框
DrawMiddle_Right(e.Graphics);//画右边框
DrawBottom_Left(e.Graphics);//画左下角
DrawBottom_Right(e.Graphics);//画右下角
DrawTop_Left(e.Graphics);//画标题栏左边
DrawTop_Right(e.Graphics);//画标题栏右边
DrawTop_Middle(e.Graphics);//画标题栏中间
DrawSys_Button(e.Graphics);//画系统按纽
以下是上述画皮肤方法的具体实现部分,我只举一个画左边框的代码示例,其它的部分请读者举一返三:
private void DrawMiddle_Left(Graphics g)
{
    Brush brush 
= new TextureBrush(Middle_Left, new Rectangle(00
Middle_Left.Width, Middle_Left.Height));
    g.FillRectangle(brush, 
0, TITLE_WIDTH, Middle_Left.Width, 
Height 
- Bottom_Middle.Height - TITLE_WIDTH);
}


衣服穿上了,现在我们的程序就有了不同的外观:
看上去已经很酷了,不过只是花架子,因为边框,标题栏,系统按纽都是我们自己画上去的假的边框,标题栏和系统按纽,所以这个窗体既不能移动也不能自由的放大缩小,点关闭都没用。以前我们写程序从来都不需要关心这个的,这些都是窗体的基本功能呀?没有从来都没有想到这个竟然还会是个问题吧?
怎么办呢?答案就是我们自己来做,不过会比较麻烦,因为取消掉了边框,所以Windows不会帮你发出系统事件,你捕捉不到系统发生了什么事情的话,就没有办法写下响应代码,所以我们要自己检测鼠标的坐标,并根据鼠标的动作,自己来发出事件消息,然后进行响应。
首先我们先定义出一些响应事件的代码,我定义了一个抽象的基类MouseAction,用来表示所有的鼠标事件,它有一个抽象方法Action:
public abstract class MouseAction
{
public abstract void Action(int ScreenX, int ScreenY, System.Windows.Forms.Form form);
}
然后再来定义出它的各个派生类来表示出具体每个鼠标事件响应的代码。
下面是一个向右拉伸窗口事件的代码响应:

 

public class MouseSizeRight : MouseAction
    
{
        
private int lx;
        
public MouseSizeRight(int LocationX)
        
{
            lx 
= LocationX;
        }


        
public override void Action(int ScreenX, int ScreenY, System.Windows.Forms.Form form)
        
{
            form.Width 
= ScreenX - lx;
            form.Invalidate();
        }

    }


非常简单和容易理解,我就不再赘述,其它的各个事件也都一样简单,这里也不给出所有事件的实现代码,只是列举一下还需要实现的代码响应类:
MouseSizeLeft:拉伸左边框
MouseSizeBottom:拉伸下边框
MouseSizeTop:拉伸上边框
MouseSizeTopLeft:拉伸左上角
MouseSizeTopRight:拉伸右上角
MouseSizeBottomLeft:拉伸左下角
MouseSizeBottomRight:拉伸右下角
MouseDrag:鼠标拖动
鼠标拖动同样也很简单,不过却稍不同于窗口的缩放拉伸,这里举出它的实现代码:

 

public class MouseDrag : MouseAction
    
{
        
private int x, y;
        
public MouseDrag(int hitX, int hitY)
        
{
            x 
= hitX;
            y 
= hitY;
        }


        
public override void Action(int ScreenX, int ScreenY, System.Windows.Forms.Form form)
        
{
            form.Location 
= new Point(ScreenX - x, ScreenY - y);
        }

    }


接下来我们开始编写发出事件的代码,先定义几个变量:
private int LEFT = 5, RIGHT = 5, BOTTOM = 5, TOP = 5, TITLE_WIDTH = 45;//边框和标题栏的大小
private int x = 0, y = 0;//保存鼠标的临时坐标
private MouseAction mouse;//鼠标的事件响应对象
然后在Form的MouseDown事件中记录下鼠标的当前坐标:
x = e.X;
y = e.Y;
附:e为System.Windows.Forms.MouseEventArgs
然后再根据鼠标的坐标定义出事件响应对象:

 

//鼠标点击左上边框
if((e.X <= LEFT + 10 && e.Y <= TOP) || (e.Y <= TOP + 10 && e.X <= LEFT))
{
    mouse 
= new MouseSizeTopLeft(Location.X, Location.Y, Width, Height);
    
return;
}


当然有的事件也可以直接响应:

 

//鼠标点击系统关闭按纽
if(e.X > Width - 20 && e.Y > 6 && e.X < Width - 20 + SysButton_Min.Width && e.Y < 6 + SysButton_Min.Height)
{
    Close();
    
return;
}


大部分的事件响应实际上是在MouseMove事件中完成的:

 

private void Form_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
    
this.Parent.Cursor = CheckCursorType(e.X, e.Y);//改变鼠标的指针形状
    if(mouse != null)
    
{
        mouse.Action(Control.MousePosition.X, Control.MousePosition.Y, 
this);//执行时间响应
        
//注意坐标是Control.MousePosition这个静态变量给出的,它的值为鼠标在桌面上的全局坐标
    }

}


给出每个不同部位的鼠标的指针形状:

 

private Cursor CheckCursorType(int X, int Y)
{
    
if(((X <= LEFT + 10 && Y <= TOP) || (Y <= TOP + 10 && X <= LEFT)) 
        
|| ((X >= Width - RIGHT - 10 && Y >= Height - BOTTOM) 
        
|| (Y >= Height - BOTTOM - 10 && X >= Width - RIGHT)))
    
{
        
return Cursors.SizeNWSE;
    }

    
else if(((Y <= TOP + 10 && X >= Width - RIGHT) 
        
|| (Y <= TOP && X >= Width - RIGHT - 10)) 
        
|| ((X <= LEFT && Y >= Height - BOTTOM - 10
        
|| (Y >= Height - BOTTOM && X <= LEFT + 10)))
    
{
        
return Cursors.SizeNESW;
    }

    
else if(X >= Width - RIGHT || X <= LEFT)
    
{
        
return Cursors.SizeWE;
    }

    
else if(Y >= Height - BOTTOM || Y <= TOP)
    
{
        
return Cursors.SizeNS;
    }

    
else
    
{
        
return Cursors.Arrow;
    }

}


 

最后在MouseUp事件中将mouse变量释放掉:
private void Form_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
    mouse 
= null;
}


为了更加逼真,还可以加上标题栏的双击最大化或者还原的事件:
private void Form_DoubleClick(object sender, System.EventArgs e)
{
    
if(y > TOP && y < TITLE_WIDTH)
    
{
        
if(WindowState == FormWindowState.Normal)
        
{
            WindowState 
= FormWindowState.Maximized;
            SysButton 
= SysButton_Restore;
            Invalidate();
        }

        
else if(WindowState == FormWindowState.Maximized)
        
{
            WindowState 
= FormWindowState.Normal;
            SysButton 
= SysButton_Max;
            Invalidate();
        }

    }

}


防止窗体被缩小成一个点,最好给窗口的MinimumSize赋上一个适当的值,例如200,200。
总结:
现在编译你的程序,运行试试,你的窗体已经拥有正常窗体所拥有的全部功能,并且还具有与众不同的外观,不明就里的人一下子还猜不出来你是怎么弄的,好了,乘别人还不知道,赶快拿出去炫耀一下吧 :)。
 
 

【转】使用Visual C#制作可伸缩个性化窗体

【转】:微软中国社区http://www.microsoft.com/china/community/Column/60.mspx 引言: 谁都希望自己的应用程序能让人留下一个深刻的印象,让自己的...
  • rongrjianxin
  • rongrjianxin
  • 2014年02月12日 22:30
  • 230

C#基础:用记事本编写简单WinForm窗体程序

平时我们编写WinForm程序经常使用VS进行拖控件的方式,这样做虽然简单,但是无法深入了解WinForm程序的本质。其实,用记事本也可以编写出VS编写的WinForm程序。还是直接看代码吧: 1、...
  • cvMat
  • cvMat
  • 2016年12月08日 12:36
  • 1228

C#选择"Windows窗体应用程序"时不小心选了"控制台应用程序 解决办法

如果VisualStudio 选择"Windows窗体应用程序"时不小心选了"控制台应用程序" 时 的解决办法为: 以下以MicrosoftVisual Studio Permium 2012  版...
  • shengmingzaiyuxuexi
  • shengmingzaiyuxuexi
  • 2017年06月27日 12:46
  • 236

Skin控件 C# Winform窗体美化控件

Skin控件 C# Winform窗体美化控件     c# 程序皮肤控件2008-09-12 16:16Visual Studio 2005工具箱上右击选择“选择项”,慢慢等...在弹出的...
  • llxlett
  • llxlett
  • 2013年01月17日 12:59
  • 2015

C#自定义窗口形状

首先,设置窗体的背景从而建立窗体形状。   1.在窗体设计器中选中窗体使之获得焦点。   2.在属性对话框中进行如下设置:   ● 将FormBorderStyle...
  • shi020910
  • shi020910
  • 2013年03月16日 13:37
  • 2889

c# 制作简单的登录验证窗体

在实际应用中,我们避免不了使用登陆验证,验证操作人员的
  • u010312811
  • u010312811
  • 2014年05月16日 22:33
  • 1327

C#窗体皮肤制作(一):资源图片的获取

学过C#语言的朋友们,是不是感觉原来做一个窗体应用程序也是非常简单的,使用VS工具拖拽几下一个简单窗体应用程序就搞定了。唯一美中不足的就是看上去外观并不是那么的好看。总是非常羡慕QQ、360、Thun...
  • bbirdsky
  • bbirdsky
  • 2014年02月15日 10:28
  • 5334

C#窗体应用程序--测试插件

C#窗体应用程序–测试插件本人刚刚接触C#语言,并写了一个专门测试DLL插件的窗体应用程序。本文涉及的内容: 提示窗口 读取、设置文本框的值 中断方法的执行 获取指定路径中的文件 装入控件、获取控件信...
  • yy228313
  • yy228313
  • 2015年07月11日 16:16
  • 770

C#用DesignSurface实现一个简单的窗体设计器

System.ComponentModel.Design.DesignSurface是为设计组件提供一个用户界面,通过它可以实现一个简单的窗体设计器。     在构建之前,我们需要引入System....
  • tmchongye
  • tmchongye
  • 2017年03月20日 03:08
  • 4291

在mac上使用VS Code编写C#应用程序

Visual Studio Core是微软的跨平台的VS开发工具,依赖于dot net core的跨平台功能。 首先需要在mac上安装dot net core 开发包(包含dot net core 运...
  • x_studying
  • x_studying
  • 2016年10月04日 04:29
  • 8038
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:使用Visual C#制作可伸缩个性化窗体
举报原因:
原因补充:

(最多只允许输入30个字)