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中間件 條碼系統中間層 物聯網軟件集成