WIN32滚动条创建和使用详解

来源:互联网 发布:java 主线程sleep 编辑:程序博客网 时间:2024/06/01 13:30

        一直对WIN32编程感兴趣,刚开始是从MFC摸索的,总感觉不带劲,新近网上看了一些博客,自己也看了Window程序设计,终于用原版的WIN32写了窗口并处理了滚动条,在这里给大家分享一下。

        

        图片是最终的窗口效果,下面用一张图来讲解滚动条的作用和区域设置。

        

        黄线矩形为窗口区域,红线区域为图片大小,只有当图片的宽或者高大于客户区的时候才需要相应的滚动条,滚动条的作用即为显示图片在客户区以外的部分,将滚动条位置和范围与像素关联,水平滚动条的最大范围即为cxBitmap-cxClient,最小范围当然是0啦,当滚动条位置发生变化时,图片进行相应的偏移,窗口的大小发生变化时,即cxClient发生变化,需要重新设置水平滚动条的范围,并判断当前滚动条位置是否在新的cxBitmap-cxClient范围内,如果超出范围,需要进行纠正;垂直滚动条的调整原理和水平是一样的。

        实例整体很简单,定义一个典型的WINDOWS窗体:1.定义窗体属性;2.定义窗体处理程序;3.循环处理进程消息队列。详见代码注释。

         

#include <Windows.h>//WINDOWS程序的标准范式:定义WINDOWS入口函数WinMain//注册一个窗口对象//定义窗口的属性,即WNDCLASS结构的队员//定义窗口对应的处理函数,即WndProc回调函数//WinMain中循环处理进程消息队列LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){static TCHAR szAppName[] = TEXT("AppName");HWND   hwnd;MSG    msg;WNDCLASS   wndclass;int  cxclient, cyclient;wndclass.hInstance = hInstance;wndclass.lpszMenuName = NULL;wndclass.lpszClassName = szAppName;wndclass.cbClsExtra = NULL;wndclass.cbWndExtra = NULL;wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);wndclass.lpfnWndProc = WndProc;wndclass.style = CS_HREDRAW|CS_VREDRAW;//窗口在创建之前需要先注册窗口类if(!RegisterClass(&wndclass)){MessageBox(NULL, TEXT("Need Windows NT"), TEXT(""),MB_HELP); return 0;}//获取屏幕属性的一个很有用的函数,F12可以看到详细用法,这里是获取屏幕的宽和高cxclient = GetSystemMetrics(SM_CXSCREEN);cyclient = GetSystemMetrics(SM_CYSCREEN);hwnd = CreateWindow(szAppName,TEXT(""),                                //窗口标题,可以设置为空,TEXT()为微软提供的字节处理宏,当定了_UNICODE的时候即代表了UNICODE字符,否则为ASC11字符WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,        //第一个宏为窗口有标题栏,有最大化,有最小化,有退出,后面两个指定了窗口具有垂直和水平滚动条cxclient/3,            //设定窗口起点为屏幕三分之一高和三分之一宽cyclient/3,cxclient/3,          //设定窗口宽和高分别为屏幕的三分之一cyclient/3,NULL,NULL,NULL,       //hInstanceNULL);//创建窗口以后显示窗口ShowWindow(hwnd, TRUE);UpdateWindow(hwnd);//GetMessage消息循环从进程消息队列中匹配消息并转换后分发给对应窗口,窗口收到消息后调用注册的窗口处理函数处理翻译后的消息。//需要注意的是,如果想要从进程消息队列中获取所有消息,需要第二个参数设置成NULL,否则GetMessage无法获取WM_QUIT消息,即无法退出程序。//WM_QUIT属于进程但不属于进程的任意一个窗口,只有第二个参数NULL可以获取,GetMessage获取WM_QUIT后进程退出while(GetMessage(&msg, NULL, NULL, NULL)){TranslateMessage(&msg);DispatchMessage(&msg);}return msg.wParam;}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam){static int cxClient, cyClient, cxBitmap, cyBitmap;static HBITMAP bitmap;static int iHScrollBarPos, iVScrollBarPos;switch(message){case WM_CREATE:BITMAP bmpinfo;bitmap = (HBITMAP)LoadImage(NULL, TEXT("view.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);if(!bitmap){MessageBox(hwnd, TEXT("Load Image Error"), TEXT("My Demo"), MB_ICONERROR);}GetObject(bitmap, sizeof(BITMAP), &bmpinfo);cxBitmap = bmpinfo.bmWidth;cyBitmap = bmpinfo.bmHeight;break;case WM_PAINT:HDC hdc, hdcSrc;PAINTSTRUCT ps;hdc = BeginPaint(hwnd, &ps);hdcSrc = CreateCompatibleDC(hdc);SelectObject(hdcSrc, bitmap);BitBlt(hdc, -iHScrollBarPos, -iVScrollBarPos, cxBitmap, cyBitmap, hdcSrc, 0, 0, SRCCOPY);EndPaint(hwnd, &ps);DeleteDC(hdcSrc);break;case WM_SIZE://窗口大小改变时收到此消息,F12可查看消息参数意思,msdn查到获取新窗口宽和高的方法cxClient = LOWORD(lparam);cyClient = HIWORD(lparam);//设定滚动条的范围SetScrollRange(hwnd, SB_HORZ, 0, cxBitmap - cxClient, FALSE);SetScrollRange(hwnd, SB_VERT, 0, cyBitmap - cyClient, FALSE);//获取滚动条的新位置,即判断窗口大小改变以后滚动条是否超出了应有的最大范围iHScrollBarPos = min(cxBitmap - cxClient, max(0, iHScrollBarPos));iVScrollBarPos = min(cyBitmap - cyClient, max(0, iHScrollBarPos));//如果滚动条超过了最大范围,则重设滚动条范围并刷新窗口if(iHScrollBarPos != GetScrollPos(hwnd, SB_HORZ)){SetScrollPos(hwnd, SB_HORZ, iHScrollBarPos, TRUE);InvalidateRect(hwnd, NULL, FALSE);}if(iVScrollBarPos != GetScrollPos(hwnd, SB_VERT)){SetScrollPos(hwnd, SB_VERT, iVScrollBarPos, SB_VERT);InvalidateRect(hwnd, NULL, FALSE);}break;case WM_VSCROLL://垂直滚动条消息,F12查看消息可以从MSDN获取消息详细参数switch(LOWORD(wparam)){case SB_LINEUP://每次滚动图片变化10个像素iVScrollBarPos -= 10;break;case SB_LINEDOWN:iVScrollBarPos += 10;break;case SB_PAGEUP://每次翻页都滚动一整个客户区的大小iVScrollBarPos -= cyClient;break;case SB_PAGEDOWN:iVScrollBarPos += cyClient;break;case SB_THUMBTRACK:iVScrollBarPos = HIWORD(wparam);break;default :break;}//判断滚动后的滚动条是否超过最大值或最小值,如果超过最大值或者最小值,则取最大值或0,否则等于当前值iVScrollBarPos = min(cyBitmap - cyClient, max(0, iVScrollBarPos));//如果滚动条位置发生变化,则设置滚动条位置和刷新屏幕if(iVScrollBarPos != GetScrollPos(hwnd, SB_VERT)){SetScrollPos(hwnd, SB_VERT, iVScrollBarPos, TRUE);//最后参数设置为FALSE可以大幅度减少屏幕闪烁,可以尝试一下。InvalidateRect(hwnd, NULL, FALSE);}break;case WM_HSCROLL:switch(LOWORD(wparam)){case SB_LINEUP:iHScrollBarPos -= 10;break;case SB_LINEDOWN:iHScrollBarPos += 10;break;case SB_PAGEUP:iHScrollBarPos -= cxClient;break;case SB_PAGEDOWN:iHScrollBarPos += cxClient;break;case SB_THUMBTRACK:iHScrollBarPos = HIWORD(wparam);break;default :break;}iHScrollBarPos = min(cxBitmap - cxClient, max(0, iHScrollBarPos));if(iHScrollBarPos != GetScrollPos(hwnd, SB_HORZ)){SetScrollPos(hwnd, SB_HORZ, iHScrollBarPos, TRUE);InvalidateRect(hwnd, NULL, FALSE);}break;case WM_DESTROY://点击窗口右上角的X,系统会向窗口发出WM_DESTROY消息,该消息并不能退出窗口,真正退出窗口的是WM_QUIT消息,调用PostQuitMessage向进程消息队列发送WM_QUIT消息PostQuitMessage(1);DeleteObject(bitmap);return 0;break;default :break;}return DefWindowProc(hwnd, message, wparam, lparam);}







0 0
原创粉丝点击