天天看點

純c++實作之滾動視窗

别在MFC了,先分析下,上圖

純c++實作之滾動視窗

我們以左上角為坐标原點,用position_width和position_height來儲存目前顯示坐标。

根據msdn說明,滾動條預設情況下的值在0~100之間。

根據圖可以知道positon_width的活動範圍是0到canvas_width-screen-width,另一邊類似。

是以有恒等式1:position_width/(canvas_width-screen_width) = hb_pos/100,其中hb_pos是水準方向滾動條目前值。

滾動塊長度公式2:screen_width/canvas_width = 滾動塊長度/滾動條可滾動區域長度,滾動條可滾動區域長度大概是screen_width-40差不多,可以設定大寫留餘地。

下面直接上完整代碼,可以運作的,隻實作了拖動滾動塊事件,其他事件自己補充吧

#include <windows.h>  

#define  IDC_CANVAS                  200  

HWND hwnd_screen = NULL;//螢幕句柄,這裡的螢幕既是我們建立的頂級視窗  

HWND hwnd_canvas = NULL;//畫布句柄  

HINSTANCE   Ghinstance = NULL;//程式執行個體  

//注意:以下提到的“螢幕”指的都是我們建立的模拟螢幕,也就是頂級視窗,而不是我們計算機的螢幕  

int         canvas_width        = 2000;//畫布長度  

int         canvas_height       = 1500;//畫布寬度  

int         screen_width        = 0;//螢幕長度  

int         screen_height       = 0;//螢幕寬度  

int         position_width      = 0;//目前位置的橫坐标  

int         position_height     = 0;//目前位置的縱坐标  

int         hb_pos              = 0;//豎直方向滾動條目前位置  

int         vb_pos              = 0;//水準方向滾動條目前位置  

LRESULT CALLBACK ScreenProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);//螢幕事件處理函數  

LRESULT CALLBACK CanvasProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);//畫布事件處理函數  

//入口函數  

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {  

//========================================建立螢幕begin==================================================     

    WNDCLASSEX wc;  

    MSG Msg;  

    memset(&wc,0,sizeof(wc));  

    wc.cbSize        = sizeof(WNDCLASSEX);  

    wc.lpfnWndProc   = ScreenProc;  

    wc.hInstance     = hInstance;  

    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);  

    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);  

    wc.lpszClassName = "WindowClass";  

    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);  

    if(!RegisterClassEx(&wc)) {  

        MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);  

        return 0;  

    }  

    //程式執行個體和螢幕句柄放到全局變量裡  

    Ghinstance = hInstance;  

    hwnd_screen = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,  

        CW_USEDEFAULT,  

        800,  

        600,  

        NULL,NULL,hInstance,NULL);  

    if(hwnd_screen == NULL) {  

        MessageBox(NULL, "Screen Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);  

//========================================建立螢幕end==================================================    

//你也可以把建立畫布的過程放到螢幕的WM_CREATE事件中,放這裡是使讀者思路能清晰些     

//========================================建立畫布begin==================================================  

    wc;  

    wc.lpszClassName = "Canvas";  

    wc.lpfnWndProc   = CanvasProc;  

    wc.hInstance     = Ghinstance;//這裡可以直接使用全局變量了  

    wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);  

        MessageBox(NULL, "Canvas Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);  

    }                 

    hwnd_canvas= CreateWindow(  

            "Canvas",  

            "",  

            WS_CHILD | WS_VISIBLE | WS_BORDER,  

            0, 0, canvas_width, canvas_height,  

            hwnd_screen,//這裡可以直接使用全局變量了,注意,如果是放螢幕的WM_CREATE裡面,這時候是還不能使用這個全局變量的,WM_CREATE事件結束後CreateWindow方法才會傳回建立視窗的句柄  

            (HMENU)IDC_CANVAS,  

            Ghinstance,//這裡可以直接使用全局變量了  

            );  

    if(hwnd_canvas == NULL) {  

        MessageBox(NULL, "Canvas Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);  

    }     

//========================================建立畫布end==================================================  

    //該顯示的顯示  

    ShowWindow(hwnd_screen, nCmdShow);  

    UpdateWindow(hwnd_screen);  

    //該顯示的顯示      

    ShowWindow(hwnd_canvas, SW_SHOW);  

    UpdateWindow(hwnd_canvas);      

    //消息循環  

    while(GetMessage(&Msg, NULL, 0, 0) > 0) {  

        TranslateMessage(&Msg);  

        DispatchMessage(&Msg);  

    return Msg.wParam;  

}  

//螢幕的事件  

LRESULT CALLBACK ScreenProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {  

    //隻需要處理WM_SIZE、WM_HSCROLL、WM_VSCROLL三個消息  

    switch(Message) {  

        //視窗大小改變時,更新全局變量中的螢幕大小,更新滾動條上滾動塊的位置  

        case WM_SIZE: {  

            //更新螢幕大小begin-----------------------------  

            screen_width = LOWORD (lParam);  

            screen_height = HIWORD (lParam);  

            //更新螢幕大小end-----------------------------  

            //更新滾動條上滾動塊的位置begin----------------------  

            hb_pos = position_width * 100 / (canvas_width - screen_width);//根據恒等式1  

            vb_pos = position_height * 100 / (canvas_height - screen_height);  

            SCROLLINFO  si;  

            si.cbSize=sizeof(SCROLLINFO);             

            si.fMask=SIF_POS;             

            si.nPos = vb_pos;  

            SetScrollInfo(hwnd_screen,SB_VERT,&si,true);  

            si.nPos = hb_pos;  

            SetScrollInfo(hwnd_screen,SB_HORZ,&si,true);              

            //更新滾動條上滾動塊的位置end----------------------  

            //其實還應該更新滾動條上滾動塊的長度,這裡先忽略吧  

            //int hb_length = GValue::s_width * (GValue::s_width - 40) / GValue::c_width;//根據恒等式2  

            //int vb_length = GValue::s_height * (GValue::s_height - 40) / GValue::c_height;  

            break;  

        }  

        //水準方向滾動條事件  

        case WM_HSCROLL : {       

            si.cbSize=sizeof(SCROLLINFO);  

            si.fMask=SIF_ALL;  

            GetScrollInfo(hwnd_screen,SB_HORZ,&si);//先拿滾動條資訊  

            switch(LOWORD(wParam)){//這裡隻處理按下滾動條拖動的事件,其他滾動條事件自己實作吧  

                //分析可知按住滾動條拖動過程中,需要修改目前位置、然後基于目前位置移動畫布,最後修改滾動條位置(你不修改的話視覺效果上會彈回去的)、  

                case SB_THUMBTRACK: {                                         

                    position_width = si.nTrackPos * (canvas_width - screen_width) / 100;//更改目前位置          

                    MoveWindow(hwnd_canvas, 0 - position_width, 0 - position_height, canvas_width, canvas_height, true);//移動畫布  

                    si.nPos=si.nTrackPos;  

                    break;  

                }  

                //TODO 滾動條的其他事件               

                default: {  

            }  

            //回寫滾動條滾動塊的位置,時視覺上正常  

            si.fMask=SIF_POS;  

            SetScrollInfo(hwnd_screen, SB_HORZ, &si, true);           

        //豎直方向滾動條事件,與上面相似不解釋了  

        case WM_VSCROLL : {  

            GetScrollInfo(hwnd_screen, SB_VERT, &si);  

            switch(LOWORD(wParam)){  

                case SB_THUMBTRACK: {  

                    position_height = si.nTrackPos * (canvas_height - screen_height) / 100;  

                    MoveWindow(hwnd_canvas, 0 - position_width, 0 - position_height, canvas_width, canvas_height, true);  

            SetScrollInfo(hwnd_screen, SB_VERT, &si, true);           

        //滑鼠滾輪  

/*      case WM_MOUSEWHEEL : { 

            //向下 

            if(HIWORD(wParam) < 0) { 

                vb_pos = vb_pos + 10; 

                if(vb_pos > 100) { 

                    vb_pos = 0; 

                }                

            } else { 

                vb_pos = vb_pos - 10; 

                if(vb_pos < 0) { 

                } 

            } 

            break; 

        } 

*/        

        case WM_CLOSE: {  

            DestroyWindow(hwnd);  

        case WM_DESTROY: {  

            PostQuitMessage(0);  

        default:  

            return DefWindowProc(hwnd, Message, wParam, lParam);  

    return 0;  

//視窗的事件  

LRESULT CALLBACK CanvasProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {  

        //從畫布左上角到右下角畫一條線,以便觀察滾動效果  

        case WM_PAINT: {  

            PAINTSTRUCT ps;  

            HDC hdc;      

            RECT rc;  

            GetClientRect(hwnd_canvas, &rc);  

            hdc = BeginPaint(hwnd_canvas, &ps);  

            MoveToEx(hdc, 0 , 0 , NULL);  

            LineTo(hdc, rc.right, rc.bottom);  

            EndPaint(hwnd_canvas, &ps);  

        }     

}     

本文轉自莫水千流部落格園部落格,原文連結:http://www.cnblogs.com/zhoug2020/p/6076185.html,如需轉載請自行聯系原作者

繼續閱讀