C++實(shí)例:SDK中控制滾動(dòng)條

字號(hào):

SDK的復(fù)雜性了,所謂復(fù)雜性,即在一個(gè)程序中,大大小小的事情都得程序編寫者親力親為,Windows幫的忙很少,我在想,要是使用文本框之類的組件也得一句一句的寫滾動(dòng)條控制代碼,那不累死!
    一、滾動(dòng)條細(xì)節(jié)問題
    滾動(dòng)條這玩意兒眾所周知了,一個(gè)滾動(dòng)條由三個(gè)部分組成:向上(左)移動(dòng)按鈕、卷動(dòng)方塊和向下(右)移動(dòng)按鈕,剛看到書上說這個(gè)「卷動(dòng)方塊」時(shí)還差點(diǎn)兒沒明白過來。
    滾動(dòng)條上常用的有五種操作:
    1.點(diǎn)擊向上(左)移動(dòng)按鈕,向上(左)移動(dòng)一行
    2.點(diǎn)擊向下(右)移動(dòng)按鈕,向下(右)移動(dòng)一行
    3.點(diǎn)擊卷動(dòng)方塊上方空白處,向上翻一頁(yè)
    4.點(diǎn)擊卷動(dòng)方塊下方空白處,向下翻一頁(yè)
    5.拖動(dòng)卷動(dòng)方塊
    滾動(dòng)條分水平滾動(dòng)條和垂直滾動(dòng)條,在Windows中就對(duì)應(yīng)WM_HSCROLL和WM_VSCROLL兩種消息,其中WM_HSCROLL是供左右移動(dòng)的消息,WM_VSCROLL是供上下移動(dòng)的消息。也就是說,響應(yīng)滾動(dòng)條的五種操作都是在這兩個(gè)消息下執(zhí)行的,比如當(dāng)用戶對(duì)垂直滾動(dòng)條進(jìn)行操作時(shí),就會(huì)給Windows發(fā)出一個(gè)WM_VSCROLL消息,至于對(duì)這個(gè)垂直滾動(dòng)條具體執(zhí)行的是什么操作,是向上移動(dòng)一行還是向下移動(dòng)一行,這就要引出一個(gè)「通知碼」的概念。
    這個(gè)「通知碼」是怎么來的呢?當(dāng)發(fā)送WM_VSCROLL或WM_HSCROLL消息時(shí),會(huì)附帶有wParam和lParam參數(shù)。其中l(wèi)Param的作用沒太弄明白,至于wParam參數(shù),其分為一個(gè)低位字和高位字,我對(duì)這兩個(gè)概念的認(rèn)識(shí)也比較模糊。其中低字組是一個(gè)數(shù)值,而這個(gè)數(shù)值就是「通知碼」。
    「通知碼」是以SB(scroll bar)開頭的標(biāo)識(shí)符定義(全是大寫名稱),這些標(biāo)識(shí)符比較好理解,比如SB_UP向上移動(dòng)一行,SB_DOWN是向下移動(dòng)一行。考試大提示:那現(xiàn)在如果要寫響應(yīng)將滾動(dòng)條向下移動(dòng)一行的代碼,該如何寫呢?看看下面的代碼:
    case WM_VSCROLL: //響應(yīng)垂直滾動(dòng)條操作的消息
    switch(LOWORD(wParam))
    {
    case SB_DOWN: //向下移動(dòng)通知碼標(biāo)識(shí)符
    //程序執(zhí)行代碼
    break;
    }
    頭痛呀,本來有著很清晰的思路,但現(xiàn)在無(wú)緣無(wú)故多了個(gè)LOWORD,書中的前面幾章也沒講這東西,只說了這是一個(gè)宏,在用GetSystemMetrics獲取窗體顯示區(qū)域大小時(shí),到是用過LOWORD宏,除此之外還有一個(gè)HIWORD宏。
    case WM_SIZE:
    x = LOWORD(lParam);
    y = HIWORD(lParam);
    上面這段代碼就是用來獲取窗體顯示區(qū)域的寬度和高度,不過使用的參數(shù)是lParam。看來要想明明白白的繼續(xù)滾動(dòng)條其它的知識(shí)點(diǎn),還得先弄清楚這兩個(gè)宏,另外還有l(wèi)Param和wParam這兩個(gè)參數(shù),也是很常見的參數(shù),得弄清楚。
    先了解一下lParam和wParam兩個(gè)參數(shù),lParam是一個(gè)UINT數(shù)據(jù)類型(unsigned int),wParam是一個(gè)LONG數(shù)據(jù)類型。在這兩個(gè)參數(shù)中分別包含一個(gè)16位低位字和一個(gè)16位高位字。通過sizeof計(jì)算出,一個(gè)UINT類型占用4個(gè)字節(jié),一個(gè)LONG也是占用4個(gè)字節(jié),因?yàn)?個(gè)字節(jié)等于8比特,那4個(gè)字節(jié)的數(shù)據(jù)類型就是32比特,由此可知UINT和LONG是32位數(shù)據(jù)類型。我的基礎(chǔ)知識(shí)不牢,又不得不惡補(bǔ)了一下。知道了lParam和wParam是32位數(shù)據(jù)類型,再來說說16位低位字和16位高位字。
    其中LOWORD是獲取一個(gè)16位低位字,HIWORD是獲取一個(gè)16位高位字,我估摸著就是將一個(gè)32位的數(shù)據(jù)類型分解成兩個(gè)16位數(shù)據(jù)類型。
    通過wParam的低位字和高位字就能獲取滾動(dòng)條的「通知碼」和卷動(dòng)方塊位置。
    wParam低位值 wParam高位值
    SB_THUMBTRACK 卷動(dòng)方塊時(shí)的目前位置
    SB_THUMBPOSITION 使用者釋放鼠標(biāo)鍵后卷動(dòng)方塊的最終位置
    其它的卷動(dòng)列操作 忽略
    這樣一來就明白了上面switch語(yǔ)句的作用。
    二、控制滾動(dòng)條操作方法
    SetScrollRange (hwnd, iBar, iMin, iMax, bRedraw) ; //設(shè)置滾動(dòng)條卷動(dòng)方塊滾動(dòng)范圍
    SetScrollPos (hwnd, iBar, iPos, bRedraw) ; //設(shè)置卷動(dòng)方塊的位置
    BOOL GetScrollRange(HWND hWnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos); //獲取滾動(dòng)條卷動(dòng)廣場(chǎng)滾動(dòng)范圍
    int GetScrollPos(HWND hWnd, int nBar); //獲取卷動(dòng)方塊的位置
    下面給個(gè)簡(jiǎn)單的示例代碼:
    int iVscrollPos; //滾動(dòng)條卷動(dòng)方塊位置
    SetScrollRange (hwnd, SB_VERT, 0, 20, FALSE) ; //滾動(dòng)條范圍為20
    SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ; //初始化滾動(dòng)條位置
    case WM_VSCROLL: //垂直滾動(dòng)條操作消息
    switch (LOWORD (wParam)) //wParam 16位低位值,即「通知碼」
    {
    case SB_LINEDOWN: //滾動(dòng)條向下移動(dòng)一行
    iVscrollPos += 1;
    break;
    case SB_LINEUP: //滾動(dòng)條向上移動(dòng)一行
    iVscrollPos -= 1;
    break;
    case SB_PAGEDOWN: //滾動(dòng)條向下翻一頁(yè)
    break;
    case SB_PAGEUP: //滾動(dòng)條向上翻一頁(yè)
    break;
    case SB_: //將卷動(dòng)方塊移置頂部
    iVscrollPos = 0;
    break;
    case SB_BOTTOM: //將卷動(dòng)方塊移置底部
    break;
    case SB_THUMBPOSITION: //拖動(dòng)卷動(dòng)方塊釋放鼠標(biāo)后
    break;
    case SB_THUMBTRACK: //托運(yùn)卷動(dòng)方塊
    break;
    case SB_ENDSROLL: //完成滾動(dòng)操作?
    break;
    }
    上面的代碼只是修改了iVscrollPos的值,要想讓滾動(dòng)條發(fā)生視覺改變,還得使用SetScrollPos來重新定位卷動(dòng)方塊的位置。
    //用min和max宏來調(diào)控iVscrollPos,確保iVscrollPos的值在SetScrollRange設(shè)置的范圍之內(nèi)
    iVscrollPos = max (0, min (iVscrollPos, NUMLINES - 1)) ;
    if (iVscrollPos != GetScrollPos (hwnd, SB_VERT)) //如果卷動(dòng)方塊有變動(dòng)
    {
    //SB_VERT表示設(shè)置垂直滾動(dòng)條的卷動(dòng)方塊位置,用SB_HORZ標(biāo)識(shí)符是設(shè)置水平滾動(dòng)條的卷動(dòng)方塊位置
    SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;
    //滾動(dòng)條的卷動(dòng)方塊已經(jīng)作了改變,現(xiàn)在得設(shè)置重繪顯示區(qū)域大小了
    //在這里是使用InvalidateRect來設(shè)置整個(gè)顯示區(qū)域?yàn)闊o(wú)效,即重繪整個(gè)顯示區(qū)域
    InvalidateRect (hwnd, NULL, TRUE) ;
    }
    好了,這第一種控制滾動(dòng)條的方法就這么著了,其實(shí)就用到了SetScrollPos和SetScrollRange兩個(gè)函數(shù),相對(duì)比較簡(jiǎn)單。書中說這是一種很古老的方法了,在WIN32 API中新提供了兩個(gè)操作滾動(dòng)條的函數(shù):SetScrollInfo和GetScrollInfo函數(shù)。這兩個(gè)函數(shù)可以完成上面幾個(gè)函數(shù)的功能,而且還多了兩個(gè)特性:
    第一個(gè)特性
    可以修改卷動(dòng)方塊大小,主要是修改卷動(dòng)方塊的高度。
    第二個(gè)特性
    可以接受32位參數(shù)。在前面的方法中,是在一個(gè)32位數(shù)據(jù)類型中提取一個(gè)16位低位字和一個(gè)16位高位字來獲取滾動(dòng)條的各種信息,比如卷動(dòng)方塊位置,通知碼等,而使用WIN32 API中這兩個(gè)新的函數(shù)可以直接接受32位的參數(shù)。