前言:從這學期開始就一直在學習自繪控制項(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分文章,只要回複了這個文章的朋友都可以去領分
from:http://blog.csdn.net/xiexievv/article/details/6596411