首页 > 代码库 > 纯c++实现之滚动窗口

纯c++实现之滚动窗口

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

技术分享

我们以左上角为坐标原点,用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差不多,可以设置大写留余地。


下面直接上完整代码,可以运行的,只实现了拖动滚动块事件,其他事件自己补充吧

[cpp] view plain copy
    1. #include <windows.h>  
    2.   
    3. #define  IDC_CANVAS                  200  
    4.   
    5. HWND hwnd_screen = NULL;//屏幕句柄,这里的屏幕既是我们创建的顶级窗口  
    6. HWND hwnd_canvas = NULL;//画布句柄  
    7. HINSTANCE   Ghinstance = NULL;//程序实例  
    8.   
    9. //注意:以下提到的“屏幕”指的都是我们创建的模拟屏幕,也就是顶级窗口,而不是我们计算机的屏幕  
    10.   
    11. int         canvas_width        = 2000;//画布长度  
    12. int         canvas_height       = 1500;//画布宽度  
    13.   
    14. int         screen_width        = 0;//屏幕长度  
    15. int         screen_height       = 0;//屏幕宽度  
    16.   
    17. int         position_width      = 0;//当前位置的横坐标  
    18. int         position_height     = 0;//当前位置的纵坐标  
    19.   
    20. int         hb_pos              = 0;//竖直方向滚动条当前位置  
    21. int         vb_pos              = 0;//水平方向滚动条当前位置  
    22.   
    23.   
    24. LRESULT CALLBACK ScreenProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);//屏幕事件处理函数  
    25. LRESULT CALLBACK CanvasProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);//画布事件处理函数  
    26.   
    27.   
    28. //入口函数  
    29. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {  
    30.   
    31. //========================================创建屏幕begin==================================================     
    32.     WNDCLASSEX wc;  
    33.     MSG Msg;  
    34.   
    35.     memset(&wc,0,sizeof(wc));  
    36.     wc.cbSize        = sizeof(WNDCLASSEX);  
    37.     wc.lpfnWndProc   = ScreenProc;  
    38.     wc.hInstance     = hInstance;  
    39.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);  
    40.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);  
    41.     wc.lpszClassName = "WindowClass";  
    42.     wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);  
    43.   
    44.     if(!RegisterClassEx(&wc)) {  
    45.         MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);  
    46.         return 0;  
    47.     }  
    48.       
    49.     //程序实例和屏幕句柄放到全局变量里  
    50.     Ghinstance = hInstance;  
    51.     hwnd_screen = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,  
    52.         CW_USEDEFAULT,  
    53.         CW_USEDEFAULT,  
    54.         800,  
    55.         600,  
    56.         NULL,NULL,hInstance,NULL);  
    57.   
    58.     if(hwnd_screen == NULL) {  
    59.         MessageBox(NULL, "Screen Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);  
    60.         return 0;  
    61.     }  
    62.       
    63. //========================================创建屏幕end==================================================    
    64.       
    65.       
    66. //你也可以把创建画布的过程放到屏幕的WM_CREATE事件中,放这里是使读者思路能清晰些     
    67. //========================================创建画布begin==================================================  
    68.     wc;  
    69.   
    70.     memset(&wc,0,sizeof(wc));  
    71.     wc.cbSize        = sizeof(WNDCLASSEX);  
    72.     wc.lpszClassName = "Canvas";  
    73.     wc.lpfnWndProc   = CanvasProc;  
    74.     wc.hInstance     = Ghinstance;//这里可以直接使用全局变量了  
    75.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);  
    76.     wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);  
    77.       
    78.     if(!RegisterClassEx(&wc)) {  
    79.         MessageBox(NULL, "Canvas Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);  
    80.         return 0;  
    81.     }                 
    82.       
    83.     hwnd_canvas= CreateWindow(  
    84.             "Canvas",  
    85.             "",  
    86.             WS_CHILD | WS_VISIBLE | WS_BORDER,  
    87.             0, 0, canvas_width, canvas_height,  
    88.             hwnd_screen,//这里可以直接使用全局变量了,注意,如果是放屏幕的WM_CREATE里面,这时候是还不能使用这个全局变量的,WM_CREATE事件结束后CreateWindow方法才会返回创建窗口的句柄  
    89.             (HMENU)IDC_CANVAS,  
    90.             Ghinstance,//这里可以直接使用全局变量了  
    91.             0  
    92.             );  
    93.       
    94.     if(hwnd_canvas == NULL) {  
    95.         MessageBox(NULL, "Canvas Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);  
    96.         return 0;  
    97.     }     
    98.   
    99. //========================================创建画布end==================================================  
    100.       
    101.     //该显示的显示  
    102.     ShowWindow(hwnd_screen, nCmdShow);  
    103.     UpdateWindow(hwnd_screen);  
    104.       
    105.     //该显示的显示      
    106.     ShowWindow(hwnd_canvas, SW_SHOW);  
    107.     UpdateWindow(hwnd_canvas);      
    108.       
    109.        
    110.     //消息循环  
    111.     while(GetMessage(&Msg, NULL, 0, 0) > 0) {  
    112.         TranslateMessage(&Msg);  
    113.         DispatchMessage(&Msg);  
    114.     }  
    115.     return Msg.wParam;  
    116. }  
    117.   
    118. //屏幕的事件  
    119. LRESULT CALLBACK ScreenProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {  
    120.       
    121.     //只需要处理WM_SIZE、WM_HSCROLL、WM_VSCROLL三个消息  
    122.     switch(Message) {  
    123.       
    124.         //窗口大小改变时,更新全局变量中的屏幕大小,更新滚动条上滚动块的位置  
    125.         case WM_SIZE: {  
    126.               
    127.             //更新屏幕大小begin-----------------------------  
    128.             screen_width = LOWORD (lParam);  
    129.             screen_height = HIWORD (lParam);  
    130.             //更新屏幕大小end-----------------------------  
    131.               
    132.             //更新滚动条上滚动块的位置begin----------------------  
    133.             hb_pos = position_width * 100 / (canvas_width - screen_width);//根据恒等式1  
    134.             vb_pos = position_height * 100 / (canvas_height - screen_height);  
    135.               
    136.             SCROLLINFO  si;  
    137.             si.cbSize=sizeof(SCROLLINFO);             
    138.             si.fMask=SIF_POS;             
    139.                           
    140.             si.nPos = vb_pos;  
    141.             SetScrollInfo(hwnd_screen,SB_VERT,&si,true);  
    142.                           
    143.             si.nPos = hb_pos;  
    144.             SetScrollInfo(hwnd_screen,SB_HORZ,&si,true);              
    145.             //更新滚动条上滚动块的位置end----------------------  
    146.               
    147.               
    148.             //其实还应该更新滚动条上滚动块的长度,这里先忽略吧  
    149.             //int hb_length = GValue::s_width * (GValue::s_width - 40) / GValue::c_width;//根据恒等式2  
    150.             //int vb_length = GValue::s_height * (GValue::s_height - 40) / GValue::c_height;  
    151.               
    152.             break;  
    153.         }  
    154.           
    155.           
    156.         //水平方向滚动条事件  
    157.         case WM_HSCROLL : {       
    158.               
    159.             SCROLLINFO  si;  
    160.             si.cbSize=sizeof(SCROLLINFO);  
    161.             si.fMask=SIF_ALL;  
    162.             GetScrollInfo(hwnd_screen,SB_HORZ,&si);//先拿滚动条信息  
    163.               
    164.             switch(LOWORD(wParam)){//这里只处理按下滚动条拖动的事件,其他滚动条事件自己实现吧  
    165.               
    166.                 //分析可知按住滚动条拖动过程中,需要修改当前位置、然后基于当前位置移动画布,最后修改滚动条位置(你不修改的话视觉效果上会弹回去的)、  
    167.                 case SB_THUMBTRACK: {                                         
    168.                     position_width = si.nTrackPos * (canvas_width - screen_width) / 100;//更改当前位置          
    169.                     MoveWindow(hwnd_canvas, 0 - position_width, 0 - position_height, canvas_width, canvas_height, true);//移动画布  
    170.                       
    171.                     si.nPos=si.nTrackPos;  
    172.                     break;  
    173.                 }  
    174.                   
    175.                 //TODO 滚动条的其他事件               
    176.                   
    177.                 default: {  
    178.                     break;  
    179.                 }  
    180.             }  
    181.               
    182.             //回写滚动条滚动块的位置,时视觉上正常  
    183.             si.fMask=SIF_POS;  
    184.             SetScrollInfo(hwnd_screen, SB_HORZ, &si, true);           
    185.               
    186.             break;  
    187.         }  
    188.           
    189.         //竖直方向滚动条事件,与上面相似不解释了  
    190.         case WM_VSCROLL : {  
    191.               
    192.             SCROLLINFO  si;  
    193.             si.cbSize=sizeof(SCROLLINFO);  
    194.             si.fMask=SIF_ALL;  
    195.             GetScrollInfo(hwnd_screen, SB_VERT, &si);  
    196.               
    197.             switch(LOWORD(wParam)){  
    198.                 case SB_THUMBTRACK: {  
    199.                       
    200.                     position_height = si.nTrackPos * (canvas_height - screen_height) / 100;  
    201.                     MoveWindow(hwnd_canvas, 0 - position_width, 0 - position_height, canvas_width, canvas_height, true);  
    202.                       
    203.                     si.nPos=si.nTrackPos;  
    204.                     break;  
    205.                 }  
    206.                   
    207.                 default: {  
    208.                     break;  
    209.                 }  
    210.             }  
    211.               
    212.             si.fMask=SIF_POS;  
    213.             SetScrollInfo(hwnd_screen, SB_VERT, &si, true);           
    214.               
    215.             break;  
    216.         }  
    217.           
    218.         //鼠标滚轮  
    219. /*      case WM_MOUSEWHEEL : { 
    220.              
    221.             //向下 
    222.             if(HIWORD(wParam) < 0) { 
    223.                 vb_pos = vb_pos + 10; 
    224.                 if(vb_pos > 100) { 
    225.                     vb_pos = 0; 
    226.                 }                
    227.             } else { 
    228.                 vb_pos = vb_pos - 10; 
    229.                 if(vb_pos < 0) { 
    230.                     vb_pos = 0; 
    231.                 } 
    232.             } 
    233.              
    234.             break; 
    235.         } 
    236. */        
    237.               
    238.         case WM_CLOSE: {  
    239.             DestroyWindow(hwnd);  
    240.             break;  
    241.         }  
    242.           
    243.         case WM_DESTROY: {  
    244.             PostQuitMessage(0);  
    245.             break;  
    246.         }  
    247.           
    248.         default:  
    249.             return DefWindowProc(hwnd, Message, wParam, lParam);  
    250.     }  
    251.     return 0;  
    252. }  
    253.   
    254. //窗口的事件  
    255. LRESULT CALLBACK CanvasProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {  
    256.       
    257.     switch(Message) {  
    258.           
    259.         //从画布左上角到右下角画一条线,以便观察滚动效果  
    260.         case WM_PAINT: {  
    261.             PAINTSTRUCT ps;  
    262.             HDC hdc;      
    263.               
    264.             RECT rc;  
    265.             GetClientRect(hwnd_canvas, &rc);  
    266.   
    267.             hdc = BeginPaint(hwnd_canvas, &ps);  
    268.               
    269.             MoveToEx(hdc, 0 , 0 , NULL);  
    270.             LineTo(hdc, rc.right, rc.bottom);  
    271.               
    272.             EndPaint(hwnd_canvas, &ps);  
    273.               
    274.             break;  
    275.         }     
    276.       
    277.         case WM_CLOSE: {  
    278.             DestroyWindow(hwnd);  
    279.             break;  
    280.         }  
    281.           
    282.         case WM_DESTROY: {  
    283.             PostQuitMessage(0);  
    284.             break;  
    285.         }  
    286.           
    287.         default:  
    288.             return DefWindowProc(hwnd, Message, wParam, lParam);  
    289.     }  
    290. }     

纯c++实现之滚动窗口