《使用VisualC#制作可伸縮個(gè)性化窗體》由會(huì)員分享,可在線閱讀,更多相關(guān)《使用VisualC#制作可伸縮個(gè)性化窗體(7頁珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
1、專欄作品
使用Visual C#制作可伸縮個(gè)性化窗體
盧彥
引言:
誰都希望自己的應(yīng)用程序能讓人留下一個(gè)深刻的印象,讓自己的程序窗體有一件與眾不同的"外衣"是一個(gè)好辦法。試想:在一大堆的普通窗口中突然跳出一個(gè)很酷的界面,一定能讓人眼睛一亮進(jìn)而產(chǎn)生興趣的。
在VB,VC中如何定制可伸縮個(gè)性化窗口早就不是什么秘密了,已經(jīng)有了大量相關(guān)的文章進(jìn)行介紹,無非都是如何調(diào)用系統(tǒng)API之類的方法,但是在.Net中調(diào)用API卻相對(duì)比較麻煩,所以使用.Net制作個(gè)性化窗體的文章也有一些,一般都是使用透明背景加圖片的方式,所以不能移動(dòng)或者不能任意放大縮小窗體。那有沒有不需要調(diào)用系統(tǒng)API的方法來實(shí)現(xiàn)可
2、伸縮的個(gè)性化窗體的辦法呢?當(dāng)然有,.Net Framework提供了一套非常強(qiáng)大的系統(tǒng)類庫,我們下面就要做一個(gè)使用"純".Net打造的可伸縮個(gè)性化窗體。
我們需要將窗體所有的"皮膚"全部換成我們自己定義的,包括標(biāo)題欄,邊框和系統(tǒng)按紐等,所以我們首先需要定做一套自己的皮膚圖形文件。因?yàn)榇绑w是可伸縮的,所以我們不能簡單的取一整幅圖片來作為窗體皮膚,而是根據(jù)需要先將圖片切割為不同的部分,一般來說,有以下圖示幾大部分(紅線為切割線):
根據(jù)方位,將圖片各部分命名為:Bottom_Left,Bottom_Middle,Bottom_Right,Middle_Left,Middle_Right,T
3、op_Left,Top_Middle,Top_Right,SysButton_Min,SysButton_Max,SysButton_Close,SysButton_Restore等。注意,有些圖片是可以伸縮的地方,比如Middle_Left,Bottom_Middle等處的圖片可以只是一小塊,以后需要進(jìn)行重復(fù)貼圖。而有些固定大小的圖片,比如Bottom_Left,Top_Left等以后只用貼一次,實(shí)際應(yīng)用的時(shí)候要注意區(qū)分。
采用以上原則,你便可以制作皮膚圖片,圖示如下:
然后可以將這些圖片放到ImageList控件或資源文件中供程序調(diào)用。(關(guān)于如何制作資源文件請(qǐng)參考:Visual C
4、#資源文件編程--創(chuàng)建資源文件)
接下來,我們使用Visual Studio .Net新建一個(gè)Windows應(yīng)用程序的項(xiàng)目,在窗體的屬性設(shè)置中,將窗體的FormBorderStyle屬性設(shè)置為None(無邊框樣式),如下圖所示:
定義一個(gè)資源管理器:
private ResourceManager rm ;
然后使用以下的方法在Form的構(gòu)造函數(shù)中將圖片取出來(資源文件名為Skin.resources):
rm = new ResourceManager("SkinWindow.Skin", Assembly.GetExecutingAssembly());
Bottom_Le
5、ft = (Bitmap)rm.GetObject("Bottom_Left");
…(其它的圖片也按照此方法取)
重載Form的OnPaint事件:
Graphics g = e.Graphics;
//手工畫窗體的各個(gè)部分
DrawMiddle_Left(e.Graphics);//畫左邊框
DrawBottom_Middle(e.Graphics);//畫下邊框
DrawMiddle_Right(e.Graphics);//畫右邊框
DrawBottom_Left(e.Graphics);//畫左下角
DrawBottom_Right(e.Graphics);//畫右下
6、角
DrawTop_Left(e.Graphics);//畫標(biāo)題欄左邊
DrawTop_Right(e.Graphics);//畫標(biāo)題欄右邊
DrawTop_Middle(e.Graphics);//畫標(biāo)題欄中間
DrawSys_Button(e.Graphics);//畫系統(tǒng)按紐
以下是上述畫皮膚方法的具體實(shí)現(xiàn)部分,我只舉一個(gè)畫左邊框的代碼示例,其它的部分請(qǐng)讀者舉一返三:
private void DrawMiddle_Left(Graphics g)
{
Brush brush = new TextureBrush(Middle_Left, new Rectangle(0
7、, 0,
Middle_Left.Width, Middle_Left.Height));
g.FillRectangle(brush, 0, TITLE_WIDTH, Middle_Left.Width,
Height - Bottom_Middle.Height - TITLE_WIDTH);
}
衣服穿上了,現(xiàn)在我們的程序就有了不同的外觀:
看上去已經(jīng)很酷了,不過只是花架子,因?yàn)檫吙?,?biāo)題欄,系統(tǒng)按紐都是我們自己畫上去的假的邊框,標(biāo)題欄和系統(tǒng)按紐,所以這個(gè)窗體既不能移動(dòng)也不能自由的放大縮小,點(diǎn)關(guān)閉都沒用。以前我們寫程序從來都不需要關(guān)心這個(gè)的,這些都是窗體的基本功能呀
8、?沒有從來都沒有想到這個(gè)竟然還會(huì)是個(gè)問題吧?
怎么辦呢?答案就是我們自己來做,不過會(huì)比較麻煩,因?yàn)槿∠袅诉吙?,所以Windows不會(huì)幫你發(fā)出系統(tǒng)事件,你捕捉不到系統(tǒng)發(fā)生了什么事情的話,就沒有辦法寫下響應(yīng)代碼,所以我們要自己檢測(cè)鼠標(biāo)的坐標(biāo),并根據(jù)鼠標(biāo)的動(dòng)作,自己來發(fā)出事件消息,然后進(jìn)行響應(yīng)。
首先我們先定義出一些響應(yīng)事件的代碼,我定義了一個(gè)抽象的基類MouseAction,用來表示所有的鼠標(biāo)事件,它有一個(gè)抽象方法Action:
public abstract class MouseAction
{
public abstract void Action(int ScreenX, in
9、t ScreenY, System.Windows.Forms.Form form);
}
然后再來定義出它的各個(gè)派生類來表示出具體每個(gè)鼠標(biāo)事件響應(yīng)的代碼。
下面是一個(gè)向右拉伸窗口事件的代碼響應(yīng):
public class MouseSizeRight : MouseAction
{
private int lx;
public MouseSizeRight(int LocationX)
{
lx = LocationX;
}
public override void Action(int ScreenX, int ScreenY, Sys
10、tem.Windows.Forms.Form form)
{
form.Width = ScreenX - lx;
form.Invalidate();
}
}
非常簡單和容易理解,我就不再贅述,其它的各個(gè)事件也都一樣簡單,這里也不給出所有事件的實(shí)現(xiàn)代碼,只是列舉一下還需要實(shí)現(xiàn)的代碼響應(yīng)類:
MouseSizeLeft:拉伸左邊框
MouseSizeBottom:拉伸下邊框
MouseSizeTop:拉伸上邊框
MouseSizeTopLeft:拉伸左上角
MouseSizeTopRight:拉伸右上角
MouseSizeBottomLeft:拉伸
11、左下角
MouseSizeBottomRight:拉伸右下角
MouseDrag:鼠標(biāo)拖動(dòng)
鼠標(biāo)拖動(dòng)同樣也很簡單,不過卻稍不同于窗口的縮放拉伸,這里舉出它的實(shí)現(xiàn)代碼:
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.Window
12、s.Forms.Form form)
{
form.Location = new Point(ScreenX - x, ScreenY - y);
}
}
接下來我們開始編寫發(fā)出事件的代碼,先定義幾個(gè)變量:
private int LEFT = 5, RIGHT = 5, BOTTOM = 5, TOP = 5, TITLE_WIDTH = 45;//邊框和標(biāo)題欄的大小
private int x = 0, y = 0;//保存鼠標(biāo)的臨時(shí)坐標(biāo)
private MouseAction mouse;//鼠標(biāo)的事件響應(yīng)對(duì)象
然后在Form的MouseDown事件中記
13、錄下鼠標(biāo)的當(dāng)前坐標(biāo):
x = e.X;
y = e.Y;
然后再根據(jù)鼠標(biāo)的坐標(biāo)定義出事件響應(yīng)對(duì)象:
//鼠標(biāo)點(diǎn)擊左上邊框
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;
}
當(dāng)然有的事件也可以直接響應(yīng):
//鼠標(biāo)點(diǎn)擊系統(tǒng)關(guān)閉按紐
if(e.X > Width - 20 && e.Y > 6 && e.X < W
14、idth - 20 + SysButton_Min.Width && e.Y < 6 + SysButton_Min.Height)
{
Close();
return;
}
大部分的事件響應(yīng)實(shí)際上是在MouseMove事件中完成的:
private void Form_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
this.Parent.Cursor = CheckCursorType(e.X, e.Y);//改變鼠標(biāo)的指針形狀
if(mouse != null)
{
m
15、ouse.Action(Control.MousePosition.X, Control.MousePosition.Y, this);//執(zhí)行時(shí)間響應(yīng)
//注意坐標(biāo)是Control.MousePosition這個(gè)靜態(tài)變量給出的,它的值為鼠標(biāo)在桌面上的全局坐標(biāo)
}
}
給出每個(gè)不同部位的鼠標(biāo)的指針形狀:
private Cursor CheckCursorType(int X, int Y)
{
if(((X <= LEFT + 10 && Y <= TOP) || (Y <= TOP + 10 && X <= LEFT))
|| ((X >= Width - R
16、IGHT - 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 - BOTT
17、OM && 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 F
18、orm_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
mouse = null;
}
為了更加逼真,還可以加上標(biāo)題欄的雙擊最大化或者還原的事件:
private void Form_DoubleClick(object sender, System.EventArgs e)
{
if(y > TOP && y < TITLE_WIDTH)
{
if(WindowState == FormWindowState.Normal)
{
WindowState = FormWin
19、dowState.Maximized;
SysButton = SysButton_Restore;
Invalidate();
}
else if(WindowState == FormWindowState.Maximized)
{
WindowState = FormWindowState.Normal;
SysButton = SysButton_Max;
Invalidate();
}
}
}
防止窗體被縮小成一個(gè)點(diǎn),最好給窗口的MinimumSize賦上一個(gè)適當(dāng)?shù)闹?,例?00,200。
總結(jié):
現(xiàn)在編譯你的程序,運(yùn)行試試,你的窗體已經(jīng)擁有正常窗體所擁有的全部功能,并且還具有與眾不同的外觀,不明就里的人一下子還猜不出來你是怎么弄的,好了,乘別人還不知道,趕快拿出去炫耀一下吧 :)。