用sdk建立完善的滚动

来源:互联网 发布:怎么在淘宝开店流程 编辑:程序博客网 时间:2024/06/05 03:53
//要把滚动功能做得尽善尽美真不是容易
//一个完善的滚动功能,应该可以让用户用键盘和鼠标调整滚动条的位置
//而且滑块的大小不应该是固定的
//这需要调用SetScrollInfo和GetScrollInfo来处理
//WM_VSCROLL和WM_HSCROLL消息
//同时还要处理WM_KEYDOWN消息和WM_MOUSEWHEEL消息
//还要在WM_SIZE消息中更新滚动条的信息
//总结:
//1.在窗口大小改变时,即处理WM_SIZE消息时更新滚动条的信息以改变滚动条滑块的大小
//而这会同时改变位置的范围.这须要调用SetScrollInfo
//2.处理WM_VSCROLL和WM_HSCROLL,根据消息参数改变滚动条的位置
//这其中要多次调用SetScrollInfo和GetScrollInfo
//3.处理WM_KEYDOWN和WM_MOUSEWHEEL完善功能

//以下的程序在窗口中显示了显示器的内容
//由于窗口没有显示器大,所以需要滚动条


#define _WIN32_WINNT 0x0500        //为了使用WM_MOUSEWHEEL
#include 
<windows.h>

//过程函数的返回值都是LRESULT,类型都是CALLBACK
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpszCmdLine,int nCmdShow)
{
    HWND hwnd;        
//主窗口句柄,在CreateWindow中赋值
    MSG msg;        //消息变量,在GetMessage中使用
    WNDCLASS wndclass;        //窗口类
    TCHAR* szAppName = TEXT("CBViewer");    //类名和窗口名
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    //窗口背景
    wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);        //鼠标
    wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);    //图标
    wndclass.lpszClassName = szAppName;        //类名
    wndclass.cbClsExtra = 0;        //类的额外参数
    wndclass.cbWndExtra = 0;        //窗口的额外参数.用于基于同一窗口类的窗口各自区分.
                                    
//在自定义对话框类时必须指定为DLGWINDOWEXTRA的大小
    wndclass.lpszMenuName = NULL;    //菜单名.可以用作子窗口的id
    wndclass.style = CS_HREDRAW | CS_VREDRAW;    //窗口风格
    wndclass.lpfnWndProc = WndProc;        //窗口过程
    wndclass.hInstance = hInstance;        //包含窗口过程的实例句柄

    
if!RegisterClass(&wndclass) )        //注册窗口类
        return 0;
    hwnd 
= CreateWindow(                //创建窗口
                szAppName,                //窗口类名
                szAppName,                //窗口标题
                WS_OVERLAPPEDWINDOW,    //窗口风格
                CW_USEDEFAULT,            //初始的x坐标
                CW_USEDEFAULT,            //初始的y坐标
                CW_USEDEFAULT,            //初始的宽度
                CW_USEDEFAULT,            //初始的高度
                NULL,                    //父窗口
                NULL,                    //菜单
                hInstance,                //和窗口相关的实例句柄
                NULL                    //额外参数
                );
    ShowWindow( hwnd,nCmdShow );        
//显示窗口
    UpdateWindow( hwnd );                //更新窗口
    while( GetMessage(&msg,NULL,0,0) )    //消息循环
    {
        TranslateMessage(
&msg);            //将WM_XXXKEYXXX消息翻译为WM_CHAR消息
        DispatchMessage(&msg);            //传递消息到窗口过程
    }    
    
return msg.wParam;                    //返回
}
LRESULT WINAPI WndProc( HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam )
{
    
static int  nDeltaPerLine, nAccumDelta ; //在WM_MOUSEWHEEL中使用
    static HDC hdcMem;                         //用作BitBlt的源DC
    static HBITMAP  hbmp;                     //桌面位图
    static int cxScreen, cyScreen;             //屏幕大小
    switch( message )
    {
    
case WM_CREATE:    
        {        
            HWND hwndDesktop 
= GetDesktopWindow(); //桌面句柄
            HDC hdcDesktop = GetWindowDC(hwndDesktop); //桌面DC
            cxScreen  = GetSystemMetrics(SM_CXSCREEN); //桌面大小
            cyScreen = GetSystemMetrics(SM_CYSCREEN);
            hbmp 
= CreateCompatibleBitmap(               //与桌面DC兼容的位图
                hdcDesktop,
                cxScreen,
                cyScreen);
            hdcMem 
= CreateCompatibleDC(hdcDesktop);  //与桌面DC兼容的内存DC
            SelectObject(hdcMem, hbmp);
            
//将桌面内容保存到内存位图中, 以在WM_PAINT中画到客户窗口
            BitBlt(hdcMem, 00, cxScreen, cyScreen, hdcDesktop, 00, SRCCOPY);
            ReleaseDC(hwndDesktop, hdcDesktop);
        }
    
case WM_SETTINGCHANGE:
        {
            ULONG  ulScrollLines ;
            SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 
0&ulScrollLines, 0) ;
            
            
// ulScrollLines usually equals 3 or 0 (for no scrolling)
            
// WHEEL_DELTA equals 120, so nDeltaPerLine will be 40
            
            
if (ulScrollLines)
            {
                nDeltaPerLine 
= WHEEL_DELTA / ulScrollLines ;
            }
            
else
            {
                nDeltaPerLine 
= 0 ;
            }
            
return 0 ;
        }
    
case WM_SIZE:
        {
            SCROLLINFO sif;
            
//设置垂直滚动条的信息
            sif.cbSize = sizeof(sif);
            sif.fMask 
= SIF_RANGE | SIF_PAGE;
            sif.nMax 
= GetSystemMetrics(SM_CYSCREEN);
            sif.nMin 
= 0;
            sif.nPage 
= HIWORD(lParam);
            SetScrollInfo(hwnd, SB_VERT, 
&sif, TRUE);
            
//设置水平滚动条的信息
            sif.cbSize = sizeof(sif);
            sif.fMask 
= SIF_RANGE | SIF_PAGE;
            sif.nMax 
= GetSystemMetrics(SM_CXSCREEN);
            sif.nMin 
= 0;
            sif.nPage 
= LOWORD(lParam);
            SetScrollInfo(hwnd, SB_HORZ, 
&sif, TRUE);

            
return 0;
        }
    
case WM_VSCROLL:
        {
            
int nVertPos;
            SCROLLINFO sif;

            sif.cbSize 
= sizeof(sif);
            sif.fMask 
= SIF_ALL;
            GetScrollInfo(hwnd, SB_VERT, 
&sif);
            
//保存滚动条的当前位置.如果处理完消息后,滚动条的位置没变,我们就不用更新窗口了
            nVertPos = sif.nPos;

            
switch( LOWORD(wParam) )
            {
            
case SB_LINEUP:
                sif.nPos 
-= sif.nPage/10;
                
break;
            
case SB_LINEDOWN:
                sif.nPos 
+= sif.nPage/10;
                
break;
            
case SB_PAGEUP:
                sif.nPos 
-= sif.nPage;
                
break;
            
case SB_PAGEDOWN:
                sif.nPos 
+= sif.nPage;
                
break;
            
case SB_THUMBTRACK:
                sif.nPos 
= HIWORD(wParam);
                
break;
            }
            sif.cbSize 
= sizeof(sif);
            sif.fMask 
= SIF_POS;
            
//设置滚动条的信息,然后再重新取得它的信息.因为windows会另外自动调整
            
//滚动条的信息,而不是直接使用你设置的信息
            
//例如对于sif.nMax,windows把它设置为sif.nMax = sif.nMax-sif.nPage+1
            SetScrollInfo(hwnd, SB_VERT, &sif, TRUE);
            GetScrollInfo(hwnd, SB_VERT, 
&sif);

            
if( nVertPos != sif.nPos )
            {
                ScrollWindow(hwnd, 
0, nVertPos - sif.nPos, NULL, NULL);
                UpdateWindow(hwnd);
            }
            
return 0;
        }
    
case WM_HSCROLL:    //水平滚动条几乎和垂直的一样处理,只是消息名称变了一点
        {
            
int nHorzPos;
            SCROLLINFO sif;

            sif.cbSize 
= sizeof(sif);
            sif.fMask 
= SIF_ALL;
            GetScrollInfo(hwnd, SB_HORZ, 
&sif);
            
//保存滚动条的当前位置.如果处理完消息后,滚动条的位置没变,我们就不用更新窗口了
            nHorzPos = sif.nPos;

            
switch( LOWORD(wParam) )
            {
            
case SB_LINELEFT:
                sif.nPos 
-= sif.nPage/10;
                
break;
            
case SB_LINERIGHT:
                sif.nPos 
+= sif.nPage/10;
                
break;
            
case SB_PAGELEFT:
                sif.nPos 
-= sif.nPage;
                
break;
            
case SB_PAGERIGHT:
                sif.nPos 
+= sif.nPage;
                
break;
            
case SB_THUMBTRACK:
                sif.nPos 
= HIWORD(wParam);
                
break;
            }
            sif.cbSize 
= sizeof(sif);
            
//设置滚动条的信息,然后再重新取得它的信息.因为windows会另外自动调整
            
//滚动条的信息,而不是直接使用你设置的信息
            
//例如对于sif.nMax,windows把它设置为sif.nMax = sif.nMax-sif.nPage+1
            SetScrollInfo(hwnd, SB_HORZ, &sif, TRUE);
            GetScrollInfo(hwnd, SB_HORZ, 
&sif);

            
if( nHorzPos != sif.nPos )
            {
                ScrollWindow(hwnd, nHorzPos 
- sif.nPos, 0, NULL, NULL);
                UpdateWindow(hwnd);
            }
            
return 0;
        }
    
case WM_KEYDOWN:
        {
            
switch(wParam)
            {
        
//模拟滚动信息.这样处理的话,当我们的程序逻辑改变的时候,只要修改一个地方的代码即可
            case VK_LEFT: 
                SendMessage(hwnd, WM_HSCROLL, SB_LINELEFT, (LPARAM)NULL);
                
break;
            
case VK_RIGHT:
                SendMessage(hwnd, WM_HSCROLL, SB_LINERIGHT, (LPARAM)NULL);
                
break;
            
case VK_UP:
                SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)NULL);
                
break;
            
case VK_DOWN:
                SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)NULL);
                
break;
            
case VK_PRIOR:
                SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)NULL);
                
break;
            
case VK_NEXT:
                SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)NULL);
                
break;
            }
            
return 0;
        }
    
case WM_MOUSEWHEEL: //用鼠标滚轮也可以调整滚动条的位置
        {
            
if (nDeltaPerLine == 0)
            {
                
break ;
            }
            nAccumDelta 
+= (short) HIWORD (wParam) ;     // 120 or -120
            
            
while (nAccumDelta >= nDeltaPerLine)
            { 
                
//当滚动滑轮同时按下CTRL, 我们调整水平滚动条的位置
                
//否则调整垂直滚动条的位置
                
//在这里,和处理键盘消息一样,还是用模拟滚动消息的方法
                SendMessage (hwnd, 
                    LOWORD(wParam) 
& MK_CONTROL ? WM_HSCROLL : WM_VSCROLL,
                    LOWORD(wParam) 
& MK_CONTROL ? SB_LINELEFT : SB_LINEUP,
                    
0);
                nAccumDelta 
-= nDeltaPerLine ;
            }
            
            
while (nAccumDelta <= -nDeltaPerLine)
            {
                SendMessage (hwnd,
                    LOWORD(wParam) 
& MK_CONTROL ? WM_HSCROLL : WM_VSCROLL,
                    LOWORD(wParam) 
& MK_CONTROL ? SB_LINEDOWN : SB_LINEDOWN,
                    
0) ;
                nAccumDelta 
+= nDeltaPerLine ;
            }
            
            
return 0 ;
        }
    
case WM_PAINT:
        {
            HDC hdc;
            PAINTSTRUCT ps;
            SCROLLINFO sif;
            
int nVertPos, nHorzPos;
            
//取得滚动信息以决定我们的图画到哪到位置
            sif.cbSize = sizeof(sif);
            sif.fMask 
= SIF_POS;
            GetScrollInfo(hwnd, SB_VERT, 
&sif);
            nVertPos 
= sif.nPos;
            
//取得滚动信息以决定我们的图画到哪到位置
            sif.cbSize = sizeof(sif);
            sif.fMask 
= SIF_POS;
            GetScrollInfo(hwnd, SB_HORZ, 
&sif);
            nHorzPos 
= sif.nPos;
            
//画图
            hdc = BeginPaint(hwnd, &ps);
            BitBlt(hdc, 
-nHorzPos, -nVertPos, cxScreen, cyScreen, hdcMem, 00, SRCCOPY);
            EndPaint(hwnd, 
&ps);
            
return 0;
        }
    
case WM_DESTROY:
        DeleteDC(hdcMem);    
//别忘了做清理工作!!!
        DeleteObject(hbmp);
        PostQuitMessage(
0);
        
return 0;
    }
    
return DefWindowProc( hwnd,message,wParam,lParam );
}
 
原创粉丝点击