滚动条在Win32程序中是非常常见的一个控件,它的功能和地位也就不言而喻了,在文本输出中算是一个难点……

我将借用P先生的思路讲述两种不同风格滚动条,下面切入主题:(实例程序都是显示一张位图  当然,位图比客户区大得多,以显示出滚动条的作用)

(1)不可变长的滚动条

这是16windows中的版本,windows1.0就有了这个玩意儿

它的使用主要依托以下两个API函数:

设定滚动条范围:

BOOL SetScrollRange(
HWND
hWnd, // 窗口句柄
int nBar, // 滚动条的类型(SB_VERT、SB_HORZ、SB_CTL)
int nMinPos, // 范围的下边界
int nMaxPos, // 范围的上边界
BOOL bRedraw // 是否重绘滚动条块
);

设定滚动条的位置:

int SetScrollPos(
HWND
hWnd,
int
nBar,
int
nPos, // 滚动条的新位置
BOOL bRedraw
);

获取滚动条的位置:

int GetScrollPos(
HWND
hWnd,
int
nBar
);

我们先来瞧一瞧这种风格的滚动条的效果:

它们的使用应该还是比较简单,只是要注意两点:

1)图片显示移动的方向和滚动条的滚动方向应该是相反的,所以代码中你会看到贴位图的位置是一个负值

   BitBlt(hdc, -iHscrollPos, -iVscrollPos, cxBitmap, cyBitmap, hdcMem, 0, 0, SRCCOPY);

2)这种风格的滚动条需要我们程序员自行控制它的范围,使显示的位置始终在规定的范围内

    iVscrollPos = max(0, min(iVscrollPos, cyBitmap - cyClient));//垂直滚动条位置
iHscrollPos = max(0, min(iHscrollPos, cxBitmap - cxClient));//水平滚动条位置

主要代码详解:

加载位图,这个和之前讲的位图的应用是一样的

case WM_CREATE:
//加载位图
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
GetObject(hBitmap, sizeof(BITMAP), &bitmap); cxBitmap = bitmap.bmWidth;
cyBitmap = bitmap.bmHeight;
return 0 ;

设定滚动条参数

	case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam); //当窗口大小改变时 , 重新判断水平、垂直滚动条位置是否超出范围
iVscrollPos = max(0, min(iVscrollPos, cyBitmap - cyClient));
iHscrollPos = max(0, min(iHscrollPos, cxBitmap - cxClient)); //设定水平滚动条
SetScrollRange(hwnd, SB_HORZ, 0, cxBitmap - cxClient, FALSE);
SetScrollPos(hwnd, SB_HORZ, iHscrollPos, TRUE); //设定垂直滚动条
SetScrollRange(hwnd, SB_VERT, 0, cyBitmap - cyClient, FALSE);
SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
return 0;

滚动条消息处理(这里只给出垂直的,水平的类似)

	//处理垂直滚动条消息
case WM_VSCROLL:
switch(LOWORD(wParam))
{
case SB_LINEUP:
iVscrollPos -= 10 ;//每一行滚动10个像素
break ; case SB_LINEDOWN:
iVscrollPos += 10 ;
break ; case SB_PAGEUP://翻页就是一个客户区大小
iVscrollPos -= cyClient ;
break ; case SB_PAGEDOWN:
iVscrollPos += cyClient ;
break ; case SB_THUMBTRACK:
iVscrollPos = HIWORD (wParam) ;
break ; default :
break ;
} //保证滚动条的位置在规定的范围内
iVscrollPos = max(0, min(iVscrollPos, cyBitmap - cyClient)); //iVscrollPos与当前滚动条位置不同时 , 才更新滚动条的位置
if (iVscrollPos != GetScrollPos (hwnd, SB_VERT))
{
SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;
InvalidateRect (hwnd, NULL, FALSE) ;
//由于这里是图片, 就不要刷背景了(也就是最后一个参数设为FALSE), 免得闪屏很厉害
}
return 0;

(2)可变长的滚动条

Win32的标准风格
它要稍微复杂点儿,它同样有一套API来维护,以下是相关的API函数:

设定滚动条信息

int SetScrollInfo(
HWND
hwnd, // 窗口句柄
int fnBar, // 滚动条类型
LPCSCROLLINFO lpsi, // 滚动条信息结构体(稍后详解)
BOOL fRedraw // 是否重绘滚动条方块
);

获取滚动条信息

BOOL GetScrollInfo(
HWND
hwnd, // handle to window
int fnBar, // scroll bar type
LPSCROLLINFO lpsi // scroll bar parameters
);

滚动窗口(这里是指窗口的客户区)

BOOL ScrollWindow(
HWND
hWnd, // handle to window
int XAmount, // 水平滚动距离
int YAmount, // 垂直滚动距离
CONST RECT *lpRect, // 滚动区域范围(一般就是设为NULL,指客户区)
CONST RECT*lpClipRect // 剪裁区域(今天用不到,设定为NULL)
);

SCROLLINFO结构体

typedef struct tagSCROLLINFO {
UINT cbSize;//SCROLLINFO类型大小(主要是windows为了以后能兼容),也就是sizeof(SCROLLINFO)
UINT fMask; //设定滚动条需要设置的参数
int nMin; //滚动条上边界
int nMax; //滚动条下边界
UINT nPage; //每一页的大小(主要用于计算滚动条块的大小)
int nPos; //滚动条的位置
int nTrackPos; //滚动条滚动的位置
} SCROLLINFO, *LPSCROLLINFO;
typedef SCROLLINFO CONST *LPCSCROLLINFO;

同样,我们还是先来看看它的效果:

你会发现随着窗口大小的变化,滚动条方块也随着变化了,它变化的依据如下:

有一点需要注意的是:windows帮你做了以下一个设计 —— 滚动条实际滚动的范围是:nMax - nPage + 1,这主要是避免过多的滚动,当显示内容在后一行在客户区最后一行就行了,所以我们只需要从我们的视角来设定nMin和nMax,不要自己去考虑滚动条滚动的实际范围,windows都为我们做好了。

主要代码详解:

初始化滚动条参数

	case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam); //设定垂直滚动条范围和页面大小
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = cyBitmap;
si.nPage = cyClient;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE); //设定水平滚动条范围和页面大小
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = cxBitmap;
si.nPage = cxClient;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); return 0;

处理滚动条消息(同样也实现垂直的)

	//处理垂直滚动条消息
case WM_VSCROLL:
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_VERT, &si); iVertPos = si.nPos; switch(LOWORD(wParam))
{
case SB_TOP: //置顶(先按下Shift键不放,然后点击滚动条方块上侧区域就能置顶)
si.nPos = si.nMin ;
break ; case SB_BOTTOM://置底(同置顶)
si.nPos = si.nMax ;
break ; case SB_LINEUP:
si.nPos -= 10 ;//每一行滚动10个像素
break ; case SB_LINEDOWN:
si.nPos += 10 ;
break ; case SB_PAGEUP://翻页就是一个客户区大小
si.nPos -= cyClient ;
break ; case SB_PAGEDOWN:
si.nPos += cyClient ;
break ; case SB_THUMBTRACK:
si.nPos = HIWORD (wParam) ;
break ; default :
break ;
} si.fMask = SIF_POS;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
GetScrollInfo(hwnd, SB_VERT, &si); if(iVertPos != si.nPos)
{
//这里InvalidateRect、ScrollWindow,效果相同
InvalidateRect(hwnd, NULL, FALSE);
//ScrollWindow(hwnd, 0, iVertPos - si.nPos, NULL, NULL);
}
return 0;

有过Java开发的朋友可能知道,在Java中添加一个滚动条是多么容易啊,几行代码就OK了,但我想说的是:真正的程序员是了解自己编写的程序整个的来龙去脉,那么,试问Java的滚动条,有谁知道它是怎么来的吗?呵呵,当然,我说这些不具有任何感情色彩,只是我觉得真刀真枪的做才会有意义,各位觉得呢^_^

源代码下载

<Win32_8>由浅入深——滚动条的更多相关文章

  1. JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome

    今天为大家分享一下我自己制作的浏览器滚动条,我们知道用css来自定义滚动条也是挺好的方式,css虽然能够改变chrome浏览器的滚动条样式可以自定义,css也能够改变IE浏览器滚动条的颜色.但是css ...

  2. CSS3自定义滚动条样式 -webkit-scrollbar(转)

    有没有觉得浏览器自带的原始滚动条很不美观,同时也有看到很多网站的自定义滚动条显得高端,就连chrome32.0开发板都抛弃了原始的滚动条,美观多了.那webkit浏览器是如何自定义滚动条的呢? 前言 ...

  3. PropertyGrid控件由浅入深(二):基础用法

    目录 PropertyGrid控件由浅入深(一):文章大纲 PropertyGrid控件由浅入深(二):基础用法 控件的外观构成 控件的外观构成如下图所示: PropertyGrid控件包含以下几个要 ...

  4. PropertyGrid控件由浅入深(一):文章大纲

    Winform中PropertyGrid控件是一个非常好用的对象属性编辑工具,对于Key-Value形式的数据的处理也是非常的好用. 因为Property控件设计良好,在很小的空间内可以展示很多的内容 ...

  5. div中设置滚动条的问题

    <div srtle="width:100px;height:50px;"></div> 这样的一个div,当文本超出的时候我们就会设: overflow: ...

  6. 高分辨率下IE浏览器缩放导致出现右侧滚动条问题的解决

    0 问题描述 由于需要演示触控操作,采购了SurfacePro,SurfacePro的推荐分辨率为2736×1824,且默认缩放比例为200%,IE浏览器的默认缩放比例也是200%,这样就导致右侧出现 ...

  7. [C1] 分离 C1FlexGrid 滚动条

    一  场景介绍 Silverlight 5.0 的 C1FlexGrid 控件里自带的滚动条,是嵌入在 C1FlexGrid 宽度和高度的范围里的,效果如下图所示: (未隐藏自带滚动条) (隐藏自带的 ...

  8. js判断窗体或容器滚动条到底部

    NO1---jquery判断窗体滚动条到底部 $(window).scroll(function () {if ($(window).scrollTop() >= $(document).hei ...

  9. iframe关于滚动条的去除和保留

    iframe嵌入页面后,我们有时需要调整滚动条,例如,去掉全部的滚动条,去掉右边的滚动条且保留底下的滚动条,去掉底下的滚动条且保留右边的滚动条.那么我们应该怎么做呢? 一:去掉全部的滚动条 第一个方法 ...

随机推荐

  1. 【转】 iOS学习之sqlite的创建数据库,表,插入查看数据

    原文:  http://blog.csdn.net/totogo2010/article/details/7702207 iOS sqlite数据库操作.步骤是: 先加入sqlite开发库libsql ...

  2. ajax省市线三级联动

    <script type='text/javascript' src='http://ajax.useso.com/ajax/libs/jquery/1.7.2/jquery.min.js?ve ...

  3. 【USACO 3.1.1】最短网络

    [描述]      农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的场.当然,他需要你的帮助.     约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共 ...

  4. 制作chm格式的帮助文档

    学习java的人都用过jdk帮助文档,借助工具我们也可以自己生成chm格式的帮助文档, 原文:http://www.cnblogs.com/shenliang123/archive/2012/04/2 ...

  5. 解决 Ubuntu15.04 登陆界面无限循环 的问题

    本人新手,在学习linux 安装NVIDIA 驱动的时候出现了一个奇怪的问题:登陆界面输入正确的账户密码,短暂闪烁后又返回了登陆界面.经查阅多种资料,已解决此问题 以下内容来自:http://blog ...

  6. JavaScript-学习一_var

    JavaScript 数据类型 字符串(String).数字(Number).布尔(Boolean).数组(Array).对象(Object).空(Null).未定义(Undefined). < ...

  7. css实现鼠标移入table时出现滚动条且table内容不移位

    一般是这样: 表格的标题和内容分别由一个table组成,其中表格内容的table由一个class="table-body"的div包裹.css如下 .tContainer .tab ...

  8. java学用代码

    /** *Java获取IP代码 */ import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.ev ...

  9. python运维开发之第七天

    一.面向对象编程进阶 1.静态方法 @staticmethod 名义上归类管理,实际上跟类没什么关系 在静态方法里,访问不了类或实例中的任何属性 class Static_method(object) ...

  10. cocos2d-x把json数据解析到数组或字典中(libjson库)

    以前在cocos2d-x项目中用到json解析,集成了libjson库后发现网上提供的解析方法大多是在解析过程中取得值,并没有将解析结果有效的保存起来,于是摸索一番,把解析结果根据数据格式存到数组或字 ...