跟我学做c#窗体皮肤.docx
《跟我学做c#窗体皮肤.docx》由会员分享,可在线阅读,更多相关《跟我学做c#窗体皮肤.docx(37页珍藏版)》请在冰豆网上搜索。
跟我学做c#窗体皮肤
跟我学做c#皮肤美化
(一)
--概述与导航
每每看着QQ,360等等那些软件漂亮的外衣时,你是不是总是在想我的软件什么时候才能穿上这么漂亮的外衣呢?
不过现在当你看到这篇文章的时候不必再发出这样的疑问了,因为接下来我会带领大家一步一步”画出”这些漂亮的外衣!
在写这系列文章之前要感谢博客园的苏飞,我也是看来他的文章后才开始接触皮肤的制作的!
我写的这系列文章中有和苏飞相同的地方,也有不同的地方。
还有因为我想使这个系列的文章能使刚刚接触皮肤编程的初学者都能跟着我一步一步的实现皮肤的制作,所以我会讲解的很详细很详细。
呵呵,不知道这点算不算和苏飞大哥的一点小小的区别呢?
!
另外我写的这一系列暂时还不会包括换肤功能在里面,而且控件的健壮性,功能的全面性上也可能有不足的地方,希望大家包涵,毕竟我也是刚刚接触皮肤制作这一方面的内容,写的不好或者难免有一些错误的地方还请大家包涵。
当然,如果大家有好的建议或者是想和我交流这方面的内容,我也很乐意。
我的邮箱qianlf2008@
接下来所有的控件我都会编写在一个用户控件库QLFUI中,以后的软件中想要应用这些皮肤只要简单的继承或者使用控件就是了。
整个控件库可以简单的分成两大类:
用户控件类和窗体类。
用户控件类就是普通的用户控件比如说Button控件,让其不再单调!
窗体类就是写一个带有皮肤的窗体,以后其他的窗体只要继承一下就会自动带有了皮肤(多方便)。
说了这么多还是先让大家看看最终做出来的效果图吧!
以后我讲解的内容大体是这个样子的:
(因为时间原因可以会有有一些控件会增加或减少,不过我会尽量都讲解全的)
控件类:
---Button控件的制作
---CheckBox控件的制作
---RadioButton控件的制作
窗体类:
---MainForm窗体的制作(只要继承这个窗体基本上就能披上最简单的外衣了)
本文归qianlifeng和如鹏网所共有,装载请注明出处,谢谢!
跟我学做c#皮肤美化
(二)
--Button控件的制作
概述与导航
先来看看我们最终要做的效果图(分别对应普通、悬停、按下时的状态):
下面就开始正式做。
首先让我们新建一个控件库项目,命名为QLFUI。
如图:
然后将默认的UserControl1重命名为Button。
接下来,我们就要在这上面来做文章了。
先来稍稍设置一下,让这个用户控件看起来更像一个按钮吧!
Button的
Size:
78,30
BackgroundImageLayout:
Stretch
然后拖一个label控件到这个用户控件上,并设置label1的属性为
AutoSize:
false,
Dock:
fill,
TextAlign:
MiddleCenter,
BackColor:
Transparent,
Font:
宋体,9pt
这几个属性。
好了,是不是开始像一个按钮了呢?
哦,差点忘了最后还要将整个控件(BUTTON)的背景色设置为Trasparent透明色。
因为如果不设置成透明色那么透明的图片下面就会显示出button的背景色(默认灰色),不好看。
好了,现在样子的已经大概有了,接下来就是编程了。
先贴代码,然后我一个一个解释:
[DefaultEvent("Click")]
publicpartialclassButton:
UserControl
{
#region变量
//三种不同状态下的图片
Image_normalImage=null;
Image_moveImage=null;
Image_downImage=null;
#endregion
#region属性
[Category("QLFSkinDll")]
publicImageNormalImage
{
get
{
return_normalImage;
}
set
{
_normalImage=value;
}
}
[Category("QLFSkinDll")]
publicImageDownImage
{
get{return_downImage;}
set
{
_downImage=value;
}
}
[Category("QLFSkinDll")]
publicImageMoveImage
{
get{return_moveImage;}
set
{
_moveImage=value;
}
}
[Category("QLFSkinDll")]
publicstringCaption
{
get{returnthis.label1.Text;}//控件运行时会自动运行get方法得到值
set
{
this.label1.Text=value;
}
}
#endregion
#region构造函数
publicButton()
{
this.SetStyle(ControlStyles.AllPaintingInWmPaint|ControlStyles.OptimizedDoubleBuffer,true);
//默认的是自带的图片样式,如果使用该按钮则必须手工指定当前按钮你想要的背景图片
_normalImage=Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"QLFUI.Res.button.btnnomal.bmp"));
_moveImage=Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"QLFUI.Res.button.btnfore.bmp"));
_downImage=Image.FromStream(Assembly.GetExecutingAssembly().GetManifestResourceStream(@"QLFUI.Res.button.btndown.bmp"));
MakeTransparent(_normalImage);
MakeTransparent(_moveImage);
MakeTransparent(_downImage);
InitializeComponent();
this.BackgroundImage=_normalImage;
}
#endregion
#region辅助函数
privatevoidMakeTransparent(Imageimage)
{
Bitmapbitmap=imageasBitmap;
bitmap.MakeTransparent(Color.FromArgb(255,0,255));
}
#endregion
#region事件
privatevoidlabel1_MouseEnter(objectsender,EventArgse)
{
this.BackgroundImage=_moveImage;
}
privatevoidlabel1_MouseDown(objectsender,MouseEventArgse)
{
this.BackgroundImage=_downImage;
}
privatevoidlabel1_MouseLeave(objectsender,EventArgse)
{
this.BackgroundImage=_normalImage;
}
privatevoidlabel1_MouseUp(objectsender,MouseEventArgse)
{
this.BackgroundImage=_normalImage;
}
privatevoidlabel1_Click(objectsender,EventArgse)
{
this.OnClick(e);
}
#endregion
}
先看第一句:
[DefaultEvent("Click")],这句话是什么意思呢?
我们知道平常我们拖一个按钮后,在设计模式下双击这个按钮就会自动产生这个按钮的Click事件。
这个默认的Click事件从哪里来的呢,毫无疑问就是[DefaultEvent("Click")]这一句来设置的啦!
这里默认的是Click事件,如果写成[DefaultEvent("MouseEnter")]就是MouseEnter事件啦!
接下来的四句分别定义了按钮三种不同状态下的bitmap。
下面的四个属性分别是三种不同状态下Image的属性和按钮的文字属性Caption,大家一看应该就明白。
具体要解释的就是[Category("QLFSkinDll")]。
这句话的意思是将这些属性分类,看个图片大家就都明白了:
以后在项目中设置属性时,我们定义的属性就自动分类在QLFSkinDll下面了。
接下来是构造函数:
publicButton(){}中的内容。
第一句是开始了窗体的双缓冲。
双缓冲的意思就是现在内容中将图像画好了然后再显示到界面上去。
在c#中图像一多最怕的就是图像闪烁的问题,开启了双缓冲虽说不能完全避免图像闪烁,但起码也能有一定的效果,我们就先开着吧^^!
接下来的三句就是给三个状态的图像赋值了,这里我是把图像嵌入进来了,并没有放置在外部。
要应用嵌入的资源分两步走:
第一步在项目中点击图片的属性,然后将“生成操作”改为嵌入的资源。
第二步应用就是我们用到的代码啦:
Assembly.GetExecutingAssembly().GetManifestResourceStream(@"QLFUI.Res.button.btnnomal.bmp"),这句话前面的照写,后面的路径规则是“命名空间+文件夹名+你的文件名+文件名后缀”,当然如果你的文件直接放在项目下就没有文件夹名了。
聪明的大家应该明白吧?
呵呵!
其中我们要用到的文件大家可以从我给的项目例子中复制。
接下来的MakeTransparent(_normalImage);MakeTransparent(_moveImage);MakeTransparent(_downImage);三句先不看,可以注释掉,下面会讲解它的作用的。
第八句InitializeComponent()是系统自带的初始化控件一些代码,我们不用去管它。
最后一句this.BackgroundImage=_normalImage;就是设置按钮的其实的图片的样子啦!
好啦,写了这么久,咱们还是先来看看能运行出个什么样子出来吧!
看看目前的状态下,它离我们的目标还差多远!
见图:
从图中我们可以看到明显的一个问题,就是按钮的边缘有粉红色。
而且如果你也正好做到这里也会发现鼠标经过按钮时,按钮没有任何反应(废话,我们还什么都没做呢)。
好了,接下来就有目标了,解决这两个问题我们这个按钮美化的就差不多了!
先来解决第一个问题,去掉粉红色。
我们需要用到Bitmap的一个函数MakeTransparent(Color),这个函数的作用是使指定的颜色对Bitmap透明。
也就是说我们只要将这个函数的Color设置为我们需要去掉的粉红色不就行了?
!
继续看代码,我们先写一个函数privatevoidMakeTransparent(Imageimage),这个函数的作用就是将传进来的图片的指定的颜色进行透明处理。
函数里就两句话,第一句话先将Image转为Bitmap。
第二句话就是进行透明处理,这里的Color.FromArgb(255,0,255)就是我们要去的粉红色啦。
那什么时候进行去色呢?
毫无疑问,当然是在给三种状态赋值后紧接着就去色啦!
所以我们在构造函数中的5,6,7句加上透明处理。
(倒过来讲这个作用,大家习惯不习惯呢?
)好了,现在我们再来运行一下:
看图:
呵呵,正如预料的那样,粉红色没有了(图中的灰色其实是透明的,只要在另外一个项目中引用一下就知道了),第一个问题解决!
再来看第二个问题,要实现按钮的变色肯定是跟鼠标的事件相关啦,比如说鼠标一进入按钮的范围之内我们就让按钮的背景改变,按下和离开按钮的时候也响应的改变背景。
所以我们用到这四个事件(注意,事件都是label1的事件,因为我们将label覆盖在按钮上,所以我们点击的其实是label1):
MouseEnter,MouseDown,MouseLeave,MouseUp。
具体的事件里面执行的代码也很简单,就是更换按钮的背景图片。
好了,让我们再运行一下看看效果:
OK!
两个问题都解决了,我们的按钮运行的好像也很正常!
鼠标进入,移出,按下的时候也会变换背景!
但是,如果你另外建一个项目,并双击产生点击事件并编写相应代码时就会发现点击事件没作用了。
多么郁闷的一件事情啊,点击事件都没作用了,我们还要这个按钮干嘛啊!
别急,让我们来解决它。
首先要明白的就是我们在其他项目中引用的这个的button控件的点击事件是整个用户控件的点击事件(还记得我们在整个button类的上方设置了默认的点击事件吗?
),而当我们去点击按钮时我们实际点击的只是label1。
问题很明了了,我们点击的是label1,设置的却是整个用户控件的事件,当然触发不了事件了。
既然问题已经搞明白了,下面就去解决它。
继续看代码:
既然我们点击的是label1那么我们就在label1的点击事件中做文章,如代码所示,我们在label1的点击事件中触发了整个类(this)的onclick事件,然后这个onclick会去找相应的类的click事件,就是我们在其他项目中直接双击的那个事件啦!
OK,至此这个按钮空间的美化就做好了看看效果吧!
本文归qianlifeng和如鹏网所共有,转载请注明出处,谢谢!
跟我学做c#皮肤美化(三)
--CheckBox控件的制作
概述与导航
先看最终的效果图:
或许大家已经猜出来我这个checkbox是怎么实现的吧?
不错,就是前面的框是一个图片,后面的文字是label。
经过前面button的讲解我想有能力的人完全可以单独制作出来。
还不熟悉的现在就开始跟我一步一步的来吧!
GO。
。
。
打开上次的项目QLFUI,新建一个名为CheckBox的用户控件。
如图
同样的,我们先设置一下,使其看起来像一个checkbox。
具体设置如下:
CheckBox控件,Size:
70,13MinimumSize:
70,13BackColor:
Transparent然后拖一个picturebox并设置以下属性:
Size:
13,13Location:
0,0,BackgroundImageLayout:
Stretch再拖一个label上来设置以下属性:
AutoSize:
falseLocation:
15,0Size:
50:
13
最终应该是这个样子:
好了,样子有了接下来就是编码了!
还是一样,先贴代码,然后我一句一句解释:
【代码】
CheckBox类的开头我定义了四个image的变量用来分别表示选中和未选中状态下鼠标的移进移出的图像!
接下来的boolcheck变量就是代表该控件是否已经被选中(checkbox最重要的属性就是这个了吧?
!
)。
接下来,就是2个属性了,我代码里面也注释的很清楚。
这里只有两个地方需要解释一下:
1,[Description("显示的文字")]是干什么的?
看图你就明白了
,
这下明白了吧?
对,就是用来解释你这个属性的(别人用你的控件都不知道什么意思,我们当然要适当的注释一下啦)!
第二点要注意的就是,在设置Checked这个属性的时候要注意更换图片,选中和不选中的时候的图片不同!
其他的属性我想大家经过button控件的讲解已经能很容易看明白里面的内容了。
这里就不再罗嗦了。
接下来看构造函数。
第一句this.SetStyle我就不说了,不懂可以看button里面的讲解。
接下来的六句话就是得到四种状态下的图片了,不过得到的好像不是很简单!
这是因为我们的原始图片是这样的
看见没有,图片是画在一张图片中的,所以我们需要使用bitmap的clone函数将不同矩形区域下的图片给截取出来。
这样解释大家应该明白了Clone的意思了吧。
剩下的两句不罗嗦了,和button里面的一样。
接下来该做什么呢,根据制作button控件的经验,我们就该开始编写鼠标的各种事件了,并在这些事件中处理不同的背景。
开始。
。
。
事件里面我们一共写了三个事件,与button不同的是这里并没有MouseUp事件,为什么呢?
因为不需要,哈哈!
开个玩笑,因为背景对于mouseup事件并不需要改变!
不过如果你高兴当然可以加上去。
事件里面的内容也很简单,就是根据当前check的状态,然后依据鼠标的状态更换picturebox的背景。
很简单,我就不多说了。
另外要注意的就是把label的对应的事件也与生成的鼠标事件关联起来(怎么关联?
直接在label的属性的对应事件里面选择那些个已经存在的事件就行了)
好了,来运行一下看看效果吧!
运行的好像还不错呢,我们设置的属性都能成功应用。
不过,如果我们在其他项目中引用这个控件并将CheckBoxText属性设置的稍微长一些,我们就会发现有一部分文字显示不出来了。
这是因为我们的控件的宽度是固定的70个像素,当label的长度更改时超过整个控件长度的部分就会被隐藏。
所以我们还需要在label的内容更改时同时改变整个控件的长度以完全显示文字的内容。
看代码:
我们写一个label文字更改时的事件label1_TextChanged,当label中的文字改变时就会触发这个事件。
事件里面的第一句就是根据文字的个数计算label需要显示的宽度。
字体的宽度是用(int)this.Font.Size+5来得到的(这个宽度我测试的基本能得到要求),得到了label的宽度我们只要将这个宽度加20(图片的宽度)就大概得到了整个控件的宽度,这样文字就能正常显示了。
当然为了以防万一我们还要加一个事件(基本用不上,不过保险嘛,呵呵)就是CheckBoxSizeChanged事件了(见代码),当我们手动拉动checkbox时手动改变label的长度,这样即使上面一个事件打不到要求有些文字没有显示出来,我们只要手动拖一下checkbox的长度那文字肯定就能显示出来了。
OK,checkbox控件制作完成。
本文归qianlifeng和如鹏网所共有,转载请注明出处,谢谢!
跟我学做c#皮肤美化(四)
--MainForm窗体的制作1
做了许多的用户控件,现在让我们换换口味,开始窗体的制作吧!
这个窗体的制作可以说是整个美化中比较重要的一部分,因为她显示的是整个美化的窗体。
而且内容也比较多,所以我会分几篇把她讲完,而且窗体制作的时候会和前面控件将的时候不一样,我不会在第一篇把最后的代码就放出来,而是希望做成跟着我一起一个版本一版本的完成不断的修改不断的发现问题并去完善。
这也是我做这个时候的一个思路:
先做一个大致的框架,然后在其基础上增加功能或者发现问题,最后完成功能和解决问题。
不知道大家感觉这样是不是更好一点呢?
好了,不多说了,先看最终的效果图:
怎么样?
是不是有点心动了?
下面就正式开始吧!
首先在以前的项目QLFUI上新建一个窗体(不是用户控件咯)并重新命名为MainForm。
如图:
接着来设置几个属性,如下:
FormBorderStyle:
None
Size:
300,300
接下来就是用picturebox和panel来布局了。
这一部分可能比较繁琐。
首先总体介绍一下大概的布局。
见图:
因为我们做的窗体是圆角的,所以窗体的四个角上(红色)我们会放上四个picturebox。
标题栏和状态栏(蓝色)会是两个panel。
二个边框线(绿色)是两个picturebox。
最后的主体部分(棕色)是一个panel。
说完了大体的布局,下面就来动手做啦。
一个一个来:
左上角
Name:
ptbtl
Location:
0,0
Size:
10,31
上方的标题栏
Modifiers:
Protected;
Name:
panelt
Location:
10,0
Size:
280,31
右上角
Name:
ptbtr
Location:
290,0
Size:
10,31
左侧的边框线
Name:
ptbml
Location:
0,31
Size:
2,232
主窗体部分
Modifiers:
Protected;
BackgroundImageLayout:
Stretch
Name:
panelm
Location:
2,31
Size:
296,232
右侧的边框线
Name:
ptbmr
Location:
298,31
Size:
2,232
左下角
Name:
ptbbl
Location:
0,263
Size:
10,37
下方的状态栏
Modifiers:
Protected;
Name:
panelb
Location:
10,263
Size:
280,37
右下角
Name:
ptbbr
Location:
290,263
Size:
10,37
最后还有右上方的三个按钮可不要忘记了,注意按钮都是在panelt里面设置的
而且这三个按钮都是我们前面做的按钮哦,终于派上用场啦!
最小化按钮
Caption:
0
Name:
btmin
Location:
180,0
Size:
31,22
最大化按钮
Caption:
0
Name:
btmax
Location:
211,0
Size:
31,22
关闭按钮
Caption:
0
Name:
btclose
Location:
243,0
Size:
37,22
还原按钮
Caption:
0
Name:
btres
Location:
211,-30
Size:
31,22
最后再加上一个label作为窗体的标题
Name:
lbtitle
Location:
6,9
Size:
35,12
BackColor:
Transparent
呼,终于结束了!
不知道大家有没有晕乎乎的感觉,反正我是有点儿了,呵呵。
最后的布局图应该是这个样子滴:
老规矩,界面的事情弄完了,现在开始编码了。
上代码:
【代码】
变量部分:
变量我在代码里都注明了其作用。
这里只会说说为什么要这些变量。
首先needMaxbt和needMinbt是指示该窗体是否需要最大化或最小化按钮的,毕竟窗体有很多种吧,比如说一个消息框就没必要用最大化按钮吧,所以我们这边也就设置的灵活一点,下面会将这两个变量封装成属性以便在设计模式下方便的选择。
接下来的四个变量
orginWidth;
orginHeight;
X;
Y;
都是用来记录窗体的信息的,分别是窗体的宽,高,x坐标值,y坐标值。
为什么要设置一些变量呢?
说起来也比较郁闷,这些都是为了窗口的最大化和还原准备的。
可能有人会问了最大化不就一句话嘛this.WindowState=FormWindowState.Maximized;何必还要这些个变量呢。
关键郁闷就郁闷在这里啦,假如直接用这一句