MFC基础,MFC自绘控件学习总结.---转
前言:从这学期开始就一直在学习自绘控件(mfc),目标是做出一款播放器界面,主要是为了打好基础,因为我基础实在是很烂....说说我自己心得体会以及自绘控件的方法吧,算是吐槽吧,说的不对和不全的地方,或者有更好的方法,请不吝赐教。
我的机器环境是:Windows7旗舰版 Service Pack 1,Visual studio 2005
1).重绘某个控件时,强烈推荐使用子类化方法,比如想自绘Button控件, 首先添加自己的类CMYButton 继承自 CButton ,声明一个CMYButton 对象,然后使用 SubclassDlgItem(UINT nID, CWnd* pParent ); // 第一个参数表示控件ID,第二个参数表示指向父窗口对象指针,一般用this表示(如果不想用SubclassDlgItem。那么可以使用CMYButton自身提供的Create方法 动态创建一个Button),这样子就可以在自己类中添加重写WindowProc()这个窗口过程函数了,非常,非常,重要 ,其他控件自绘都参考这一条.
2).我入手的第一个控件是 Button,我终于知道我的基础有多烂,很多基本的函数如GetDlgItem() , SubclassDlgItem() 都不知道,查资料,看源码 ,费了不少时间才基本完成Button的自绘,另外自绘
的按钮默认情况下是不能响应键盘按下Enter的,需要额外做一些处理。(关键词:BS_OWNERDRAW ,DrawItem),(在后期我仿造qq登陆的Button加了个效果,Hover和Leave时是渐变的,只在设置
对话框里面的Button使用了)
3).然后是 RadioButton ,CheckBox 其实和Button异曲同工的,推荐了解3个API函数CheckRadioButton(),SetCheck(),GetCheck().
4).另外对于不规则按钮实现需要掌握 SetWindowRgn(),CombineRgn(),SelectClipRgn() 3个API函数,其他不规则窗口,控件也可以参考这个方法。
5).然后是Edit控件自绘,不算是完全自绘,只重绘了非客户区(如果没特殊需要也没必要重绘客户区),和改变背景颜色,改变字体,不过后期我加了个效果,鼠标在Edit上和离开Edit时边框是渐变的(关
键词:CtlColor,WM_NCPAINT),RichEdit也可以用这个方法
6).然后是ToolTip(气泡提示控件),微软提供了NM_CUSTOMDRAW这个通告消息,以WM_NOTIFY形式发送,可以用MFC类向导添加到自己的派生类中,不过我推荐重写OnPaint函数,完全自绘(难点:
需要根据文本内容计算出控件的大小,显示位置等)
在后期我实现了,淡入,点击/超时 淡出的效果(需要映射TTN_POP 和TTN_SHOW两个通告消息),不过挪开淡出效果没能实现,求指导。
7).然后是Sliderctrl, 微软提供了NM_CUSTOMDRAW这个通告消息,以WM_NOTIFY形式发送,可以用MFC类向导添加到自己的派生类中,前期我是用的这种方法,不过后期发现这种方法局限性很大,
推荐重写OnPaint函数,完全自绘(关键点:在PreSubclassWindow 里面把 Thumb(拇指按钮),Channel(凹槽),以及整个控件大小保存起来,以便在OnPaint里面绘制)
8).然后是Staic控件,这个比较简单,重写OnPaint函数 画上文本,把DC设为透明模式就行了,有人会说直接在CtlColor直接SetBkMode(TRANSPARENT)就行了,不用在OnPaint处理,但这是有个问
题的, 如果要求文本一直变化,旧的文本没有擦除,新设置的文本又盖上了。所以根据这个控件的用途,自己选择适合的方法吧。
9).然后是Menu,这个较难,严格来说Menu 并不算控件,他是派生自CObject类的,微软提供了MeasureItem,DrawItem两个虚函数类供自绘 ,MeasureItem作用是计算出菜单的高度和宽度,系统
会自动根据文本内容最长那项来作为Menu的宽度。DrawItem作用顾名思义就是画了,但是有个致命的问题,自绘出来的Menu 有个系统默认的边框,十分邪恶和难看,(ModifyStyle和
SetWindowLong去不掉边界的)这时到自己派生的CMYMenu里面 发现微软只给咱们提供了仅仅5个虚函数,没有提供WindowProc()这个窗口过程函数,这不是坑爹嘛.......这时一般做法都是派生自
CWnd 自己实现菜单的功能.不过查了下资料任然可以自绘的:需要使用钩子 替换菜单的窗口过程,在WM_CREATE时 去掉边界Stytle 有兴趣的朋友可以Google一下。(难点:替换菜单窗口过程)
10). 然后是Combobox控件,这个较难, 微软提供了CompareItem,DeleteItem,DrawItem,MeasureItem 4个虚函数供自绘。我只用了后2个,(如果只加了 CBS_SORT 必须重写CompareItem这个
函数,除非使用了CBS_HASSTRINGS | CBS_SORT就可以不重写CompareItem()), 别以为这样子就完了,运行后,打开Combobox 显示的 List 有系统默认的边框!!!ModifyStyle和SetWindowLong
去不掉边界.老规矩查资料去,不看不知道,一看吓一跳,Combobox 是由3个控件组合成成的(难怪叫组合框),分别是Edit,Listbox,和combo本身(除去Edit ,Listbox剩下那部分),当时我就震惊了,迷茫
了! 这时需要添加OnCtlColor这个函数,在里面 使用SubclassWindow()这个API函数子类化 ListBox 和 Edit(在这之前 你还需要准备自绘好的 ListBox控件 和Edit控件)Combobox 有3种样式
CBS_SIMPLE, CBS_DROPDOWNLIST,CBS_DROPDOWN,第一种不说了不常用,第二种是不能输入只能点击选择,第三种可以输入可点击选择. 我的程序里面使用的是CBS_DROPDOWNLIST样式
11).Combobox 在 Windows7 下疑惑:关闭滑动打开组合框特效 ,自绘Combobox是可以去掉边界并进行窗口剪切的(圆角矩形) , 如果是 开启滑动打开组合框特效,系统会加上边框, 剪切的圆角又
变成直角了, 跟踪调试发现是在WM_WINDOWPOSCHANGING 消息里面搞的鬼 ,有兴趣的朋友可以对比看看,暂时为找到解决方案。。。
开启/关闭 滑动打开组合框特效 :计算机-右键属性-高级系统设置-高级-性能设置-视觉效果
12).然后是 TabCtrl ,微软提供了DrawItem,MeasureItem 2 个虚函数供自绘,需要加 TCS_OWNERDRAWFIXED这个Stytle,表明这个控件需要自绘,不过我没有用这种方式,我直接重写了OnPaint函数
完全自绘(难点:需要自己计算每个标签大小,位置,以及与之绑定的Dialog显示位置)
13).最后是窗体框架绘制(非客户区),这个较难,看了很多例子源码,也花了不少时间,WM_MOVE,WM_PAINT ,WM_NCPAINT,WM_NCACTIVATE,这4个消息自绘成功的关键 , 在绘制时候还需要
计算出边框/标题栏的大小和位置(Win7 和Xp 下 GetSystemMetrics()返回值是不同的)。
// 给出框架绘制不闪烁的关键代码 ,完全原创。
if(message == WM_NCACTIVATE && !wParam) // wParam=0, deactive
{
return 1; // 必须返回1,处理默认消息(如果不返回1,一切弹出的窗口(模态,非模态)不能点击)
}
if(message == WM_NCACTIVATE && wParam) // wParam =1, active
{
return 0; // 这个随便返回(0和1都行)
}
if(message==WM_NCPAINT)
{
return 0; // 阻止默认框架绘制(An application returns zero if it processes this message 摘自MSDN)
}
这种方式是保留了边界和标题栏,其实就是盖住了原来的画上自己的,只要不闪烁就是成功的。当然也可以去掉系统默认的边界 和 标题栏,在客户区算出一个边界和标题栏,处理一些消息,能实现更好
的框架自绘,做出更漂亮的界面。
14)可能是我这个人比较蛋疼吧,想着既然做了个播放器界面为什么不给他实现一个播放的功能呢,微软提供了 MCI—媒体控制接口,自己封装了一个播放类,实现了一些播放基本功能。这样子第一个
版本就算完成了吧。
---测试环境: 6台Win7 和 2台Xp
---界面测试:Win7 和 Xp 运行均正常(有个缺陷见第11条)
---播放测试: 我的电脑上可以 播放rmvb,RM ,AVI,MP4,WMV,FLV ,部分测试Win7电脑6个格式全部能播放,但部分测试的Win7电脑只能播放 AVI 和MP4,WMV格式(为什么?求解答...).
---另外WMV格式增加播放速度和减少播放速度,貌似是不行的。
---在XP系统 下能打开视频文件但只能听见声音看不见图像,求解答?
这结果确实比较蛋疼,大家可以测试下看看界面是否正常,播放功能是否正常
15)鉴于MCI版本播放测试不是很令人满意,我又再一次蛋疼了,因为一个前辈说让我用Activex 控件试试。好吧,花了2天时间,研究了下Activex 控件, 用OleView研究了Aplayer这个控件,
APlayer_001.dll 这个DLL文件就是Aplayer Activex控件(Activex 控件使用前必须先注册,如果只是在代码里面注册了APlayer_001.dll,程序可以运行但是播放不了文件,因为在播放文件的时候
Aplayer控件 还会根据播放文件类型 再加载 一些DLL文件和AX文件,那些文件加起来有80多M,坑爹啊这是....)其实Aplaer 是迅雷看看播放器的一个组件, 如果安装了迅雷的话,在 C:\
\Program Files\\Common Files\\Thunder Network 可以找到 Aplaer 这个文件夹,如果没有安装迅雷或者没有Aplayer这个组件程序是不能运行的。
备注:这个APlayer本身有个缺陷,在播放 Rmvb和mkv文件时,点击定位不准确。对于大的文件,很难发现这个缺陷,可以找个 一两分钟的短视频文件用迅雷看看打开 点击定位试试,缺陷非常明显。
由于Aplayer 流程 和MCI不太一样,所以花了点时间做了第二个版本。
---测试环境:6台Win7 和 2台Xp
---界面测试:Win7 和 Xp 运行均正常(有个缺陷见第11条)
---播放测试:Win7上可以播放RMVB,RM, AVI,MP4,WMV,FLV ,MKV, MP3, WMA, WAV
---在XP系统下 打开文件任然只能听见声音看不见图像,对于XP系统这个播放问题,还未找到解决方案,求指导(难道是因为我注册的是Win7的APlayer?)。
---另外程序有个缺陷 :在第一次 点击Aplayer控件的时候会缩小,调试发现根本没有进入 WM_LBUTTONDOWN,直接 WM_WINDOWPOSCHANGING,WM_WINDOWPOSCHANGED,WM_SIZE
,不知道这个消息从哪里发过来的....(我用了个不是很好的方法解决了,既然是在第一次点击的时候才会缩小,我在PreSubclassWindow里面 :PostMessage(WM_LBUTTONDOWN,MK_LBUTTON,
(LPARAM)&UserDown);PostMessage(WM_LBUTTONUP,MK_LBUTTON,(LPARAM)&UserDown);)这2个消息,貌似没再出现了缩小情况了,但昨天我运行的时候又出现这个问题了,出现的概率很低....
无语啊)
16)
程序的测试全部由自己完成,很多功能没来得及测试,所以程序可能会出现这样那样的问题,一个人力不从心啊,希望拍砖温柔点啊。
程序热键,做的不好,不是全局和后台的,必须窗口获得焦点才能响应.
在后期增加了托盘功能。
增加了播放列表功能,最多支持10个文件,大于10个覆盖第10个,双击列表中的文件名,就可以播放这个文件。不过播放列表我没有单独做个窗口是放在设置对话框第3个标签的。
应同学的强烈要求增加了拖拽打开文件功能(我过滤了一些文件扩展名,不是每个文件类型拖拽都有效,mci版本和Activex版本支持的格式不同 ,过滤情况也不一样)
程序最初叫IKAN Player 但是发现 PPLive 已经用了这个名字, 改成了ICAN Player....
附加说明:我现在大3在读,现在正在实习找工作阶段,上次面试的时候把程序给面试官演示的时候,他说了句“这种程序网上随便一搜一大把”.....他这个想法我很能理解,如果我是面试官,我也会持怀疑态度的. 所以现在不方便给出源码,希望大家理解我,以后一定会给出项目源码的.
帖子不知道怎么上传附件,程序放在CSDN 资源区内,不需要资源分的,大家下下来看下吧。
给出链接: http://download.csdn.net/source/3428958
论坛上也有我的帖子:http://topic.csdn.net/u/20110710/19/5209f358-31c8-4057-b108-02155a417fd0.html?61362
大家运行下,看看有没有什么问题和异常啊,欢迎回帖,既然论坛不让我开300分的帖子,打算后面在开2个100分帖子,只要回复了这个帖子的朋友都可以去领分
RFID管理系统集成商 RFID中间件 条码系统中间层 物联网软件集成