首先,win默认样式的按钮并不好看,
//
注:默认样式指的是”你随意删除一个文件,会弹出确认对话框,那里面的按钮就是默认样式”,并非指的是”基础自绘按钮”样式.
注2:”基础自绘按钮”指使用如create/createwindow函数创建的按钮,这种按钮默认情况下使用黑粗字体,
很丑,可以加载默认样式库成为”win默认样式”
//
那么为了美化,要么使用界面库,要么”高级自绘”.
界面库我用了几个,(都是免费的或者开源的)
1.迅雷BOLT我最喜欢,但是官方文档较少,可以说是没有,而且使用Lua脚本,有着奇葩的加载机制,虽然界面相对精美,但是我只能说,实在不适合一般开发人员,担任主程序或者首席程序员的可以研究一下.
2.HTMLayout,这个东西让我眼前一亮,使用HTML+CSS来绘制界面,这何其方便!但是它蛋疼的脚本交互,我只能说同上.另外此界面库很久没更新了.
3.Sciter,现在sdk到Ver.3了,可以看做HTMLayout的增强版,区别就是2者的脚本系统,这里不作多述,自行谷歌.这个适合有能力的开发者学习使用,个人很看好,很喜欢,但是我实在受不了它那蛋疼的使用json的脚本交互.
4.炫彩界面库,某种意义上,是个玩具,不多做评论.
5.金山界面库,还不如上面一个.限制太多.
其他还有一些界面库,但是我用不好或者不知道,不做评论.
如果不想使用界面库,那么可以使用费事的高级自绘.
高级自绘指(本文以按钮为例)”BS_OWNERDRAW”样式,根据MSDN的解释,”一旦使用BS_OWNERDRAW样式,则其他所有样式将被忽略(以WS_开头的Windowstyle不会被忽略)”,正常情况下,使用”BS_DEFPUSHBUTTON”,按钮会有3态,正常/Hover/Down/Up(正常与UP可视为一态),客官可以自行体会.
但是使用了”BS_OWNERDRAW”后,这些样式都没有了,一般情况下,需要重写”DrawItem”函数,并且和”OnMouseMove/OnMouseHover/OnMouseLeave”等配合使用,看了代码后我觉得真他妈麻烦.
于是想出一个蛋疼但有效的方法:
老样子,先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void CBmpButton::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
CDC dcMem;
dcMem.CreateCompatibleDC(&dc); // 创建 内存dc
CBitmap bmp;
BITMAP bitmap; //用这个对象 是因为可以得到图片的宽, 高, 看最后一句话
//PaintNum=0;
switch (PaintNum)
{
case 0:
bmp.LoadBitmap(IDB_Button_OK_Normal);   //加载 图片
bmp.GetBitmap(&bitmap);
dcMem.SelectObject(&bmp); // 把图片加载到 内存 dc
dc.StretchBlt(0,0,72,24,&dcMem,0,0,
bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);
break;
case 1:
bmp.LoadBitmap(IDB_Button_OK_Over); //加载 图片
bmp.GetBitmap(&bitmap);
dcMem.SelectObject(&bmp); // 把图片加载到 内存 dc
dc.StretchBlt(0,0,72,24,&dcMem,0,0,
bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);
break;
default:
bmp.LoadBitmap(IDB_Button_OK_Normal);   //加载 图片
bmp.GetBitmap(&bitmap);
dcMem.SelectObject(&bmp); // 把图片加载到 内存 dc
dc.StretchBlt(0,0,72,24,&dcMem,0,0,
bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);
break;
}
// 不为绘图消息调用 CBitmapButton::OnPaint()
}
void CBmpButton::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
PaintNum=1;
CBitmapButton::OnLButtonDown(nFlags, point);
}
void CBmpButton::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
PaintNum=0;
CBitmapButton::OnLButtonUp(nFlags, point);
}

首先,建立一个类,继承自CBitmapButton类,本例子为CBmpButton,
int一个PaintNum,用来控制WM_PAINT的绘制行为.
程序运行到WM_PAINT阶段时,根据PaintNum的值的不同,会绘制”Normal”和”Over”(这里应该是”Dwon”,懒得改文件名了),
默认情况下,Paint找不到case 0和case 1,则运行默认语句,即加载Normal位图,
当我们按下鼠标左键(未放开)时,程序将PaintNum的值修改为1,同时触发WM_PAINT进行重绘(注,这里重绘的是子窗口,父窗口不一定会重绘),
那么我们的按钮就变成”Over”位图了,此时放开鼠标左键,程序将PaintNum的值修改为0,同时重绘,就又是正常”Normal”位图了.

这个方法不敢说有多好,但是绝对简单,易懂.
我真他妈机智.
图:↓
Normal:
NormalButton

Down:
DownButton