创建带滚动条窗口的步骤:
以竖直方向的标准滚动条为例(横向方向的滚动条控件也类似):
1.创建一个基于对话框的MFC工程,或新建一个对话框资源,在对话框的属性-->外观 选项中把Vertical Scrollbar选项设为True。
2.在对话框的初始化函数中用SetScrollInfo函数设置滚动条的范围、页面大小、初始位置。
3.捕捉WM_VSCROLL消息,在消息处理函数OnVScroll中根据消息通知码设置滚动条的位置。
4.根据3中滚动条的位置变化调用ScroolWindow函数滚动窗口客户区。
5.ScrollWindow滚动窗口客户区后,Windows自动将滚动新出现的地方无效化,从而产生一条WM_PAINT消息。所以我们还需要在WM_PAINT的消息处理函数中自己绘制新出现的区域。
ps:若在其他消息处理函数中滚动了窗口客户区,也要记得同步设置滚动条。
详细:
要用滚动条,我们需要做什么?
在程序中使用滚动条,需要程序和Windows共同负责维护滚动条以及滑块在滚动条中的位置。Windows负责的任务如下:
程序要负责的任务如下:
注意上面windows负责的第3条和程序要负责的第3条。小弟以前理所当然的认为windows应该会负责移动滑块并更新滑块的位置。后来发现如果自己不在消息处理函数中重新设置滑块的位置,当你移动滑块松开鼠标后,滑块会自己回到原来的地方。原来要程序自己负责更新滑块的位置。我现在还想不清楚为什么windows不负责这个,这个不是很简单吗?
滚动条的范围、滑块的位置和窗口客户区的映射:
滚动条的范围是一对整数,分别代表滚动条的最大值和最小值。位置值滑块在范围中所处的值。当滑块在滚动条的最顶端的时候,滑块的位置是范围的最小值。相应的,滑块在滚动条的底部时,位置是范围的最大值。如果滑块在滚动条的中间,那位置的取值就是介于最大值和最小值的一个中间值了。默认状态下标准滚动条的范围是0~100,默认位置是0,可以通过SetScrollInfo函数来设置。而滚动条控件的默认范围是0~0。
看来滚动条的范围与滑块的位置和窗口客户区半毛钱关系都没有,全靠我们让它们产生关系。要想让让窗口客户区的内容随着滑块的滑动发生变化,我们必须在滚动条的消息处理函数中或WM_PAINT的消息处理函数中自己重绘窗口客户区的内容。
滚动条消息:
当用户单击滚动条、单击滚动条上的尖头或拖动滑块时,Windows向窗口过程发送WM_VSCROLL消息(垂直滚动条)或WM_HSCROLL消息(水平滚动条)。像其他消息一样WM_VSCROLL消息也伴随着消息参数。不同的消息参数代表了鼠标在滚动条上不同的动作。如果是基于windows sdk的编程方式可以根据窗口过的wParam的地位字判断,如果是MFC中可以根据OnVScroll的nSBCode参数判断。参数如下:(只列举和垂直滚动条有关的)
SB_BOTTOM 滑到底部
SB_ENDSCROLL 滑动结束.
SB_LINEDOWN 向下滑动一行.
SB_LINEUP 向上滑动一行.
SB_PAGEDOWN 向下滑动一页.
SB_PAGEUP 向上滑动一页.
SB_THUMBPOSITION 滑动到了现在所在的位置,位置在nPos参数中提供
SB_THUMBTRACK 滑块正在被拖动,滑块现在所处的位置由nPos参数提供
SB_TOP 滑块滑动到顶部了
附注:1.SB_THUMBPOSITION和SB_THUMBTRACK可能不好理解,前者是拖动滑块后,放开鼠标按键后才产生的消息。后者是在拖动滑块的过程中一直不停的产生的消息,直到你放开鼠标按键为止。
2.在滚动条上的任何鼠标动作都会至少产生两条消息:一条在鼠标按键按下时,另一条在鼠标按键松开时。按照小弟的经验任何动作结束时都会产生带有SB_ENDSCROLL参数的消息。
等等,上面的页面大小是什么?
你也许注意到在你浏览网页或者有滚动条的对话框时,随着网页页面内容的变多,滑块大小会变小。因为滑块的大小与显示在窗口中内容的多少是成比例的。
关系为 :滑块大小/滚动条长度 约等于 页面大小/范围 约等于 窗口客户区大小/所有要显示的内容多少
根据这个公式你可以决定什么时候该滚动窗口客户区的多少内容。
滚动条初始化建议:
可以在初始化函数中设置滚动条的范围、位置、页面大小。比如WM_INITDIALOG、WM_CREATE的消息处理函数中设置。但建议在WM_SIZE消息的处理函数中设置。因为对话框创建后再WM_CREATE消息之后会紧接着发送一条WM_SIZE消息,在WM_SIZE的处理函数中照样能初始化,而且窗口大小一般都会变化,每一次窗口客户区大小变化时,滚动条的页面大小和范围也要跟着变化才合理。
和滚动条相应的窗口客户区绘制建议:
可以在处理滚动条消息是直接绘制客户区,但大师Charles Petzold的建议是:“程序应该把所有的客户区绘制工作都限制在处理WM_PAINT消息时。因为程序必须能在收到WM_PAINT消息时绘制整个客户区,因而在处理其他消息时进行绘制很可能是在重复WM_PAINT消息的代码。”所以可以在滚动条消息处理函数中将需要重新绘制的区域通过InvalidateRect函数放到WM_PAINT的处理函数中绘制。如果想加快WM_PAIN消息的处理,可以在InvalidateRect函数之后调用UpdateWindow函数。
用方向键控制滚动条(待续。。。)
可能要用到的函数:
(SetScrollRange,GetScrollRange,SetScrollPos和GetScrollPos已过时,不建议使用,用SetScrollinfo替代更好)
SetScrolllnfo
函数功能:该函数设置滚动条参数,包括滚动位置的最大值和最小值,页面大小,滚动按钮的位置。如被请求,函数也可以重画滚动条。
int SetScrollInfo(
__in HWND hwnd,
__in int fnBar,
__in LPCSCROLLINFO lpsi,
__in BOOL fRedraw
);
参数:
hWnd:滚动条控件或带标准滚动条的窗体句柄,由fnBar参数决定。
fnBar:指定被设定参数的滚动条的类型。这个参数可以是下面值,含义如下:
SB_CTL:设置滚动条控件。而参数hwnd必须是滚动条控件的句柄。
SB_HORZ:设置所给定的窗体上标准水平滚动条参数。
SB_VERT:设置所给定的窗体上标准垂直滚动条参数。
lpsi:指向SCROLLINFO结构。在调用SetScrollInfo之前,设置SCROLLINFO结构中cbSize成员以标识结构大小,设置成员fMask以说明待设置的滚动条参数,并且在适当的成员中制定新的参数值。成员fMask可以为下面所列复合值,含义如下:
typedef struct tagSCROLLINFO
{
UINT cbSize;
UINT fMask;
int nMin;
int nMax;
UINT nPage;
int nPos;
int nTrackPos;
} SCROLLINFO, FAR *LPSCROLLINFO;
SIF_DfSABLENOSCROLL:如果滚动条的新参数使其为没必要,则使滚动条无效而不再移动它。
SIF_PAGE:设置滚动页码值到由Ipsi指向的SCROLLINFO结构的nPage成员中。
SIF_POS:设置滚动位置值到由lpsi指向的SCROLLINFO结构的nPos成员中。
SIF_RANGE:设置滚动范围值到由lpsl指向的SCROLLINFO结构的nMin和nMax成员中。
fRedraw:指定滚动条是否重画以反映滚动条的变化。如果这个参数为TRUE,滚动条将被重画,否则不被重画。
GetScrollInfo
函数功能:滚动条的参数,包括滚动条位置的最小值、最大值,页面大小,滚动滑块的位置。
BOOL GetScrollInfo(
__in HWND hwnd,
__in int fnBar,
__inout LPSCROLLINFO lpsi
);
参数:
hWnd:滚动条控制或有标准滚动条的窗体句柄,由fnBar参数确定。
fnBar:指定待找回滚动条参数的类型,此参数可以为如下值,其值含义:
SB_CTL:找回滚动条控制参数。其中参数hwnd一定是处理滚动条控制的句柄。
SB_HORZ:找回所指定窗体的标准水平滚动条参数。
SB_VERT:找回所指定窗体的标准垂直滚动条参数。
lpsi:指向SCROLLINFO结构。
(5)ShowScrollBar
函数功能:该函数显示或隐藏所指定的滚动条.
BOOL ShowScrollBar(
__in HWND hWnd,
__in int wBar,
__in BOOL bShow
);
参数:
hWnd:根据参数wBar值,处理滚动条控制或带有标准滚动条窗体。
wBar:指定滚动条是被显示还是隐藏。这个参数将是下面值之一,具体含义如下:
SB_BOTH:显示或隐藏窗体的标准的水平或垂直滚动条。
SB_CTL:显示或隐藏滚动条控制。参数hWnd必须是指向滚动条控制的句柄。
SB_HORZ:显示或隐藏窗体的标准的水平滚动条。
SB_VERT:显示或隐藏窗体的标准的垂直滚动条。
bShow:指定滚动条是被显示还是隐藏。此参数为TRUE,滚动条将被显示,否则被隐藏。
返回值:如果函数运行成功,返回值为非零;如果函数运行失败,返回值为零。若想获得更多的错误信息,请调用GetLastError函数。
ScrollWindow函数
函数功能:该函数滚动所指定的窗口客户区域内容。函数提供了向后兼容性,新的应用程序应使用ScrollWindowEx函数
BOOL ScrollWindow(
__in HWND hWnd,
__in int XAmount,
__in int YAmount,
__in const RECT *lpRect,
__in const RECT *lpClipRect
);
hWnd
[in]客户区域将被滚动的窗口的句柄。
XAmount
[in]指定水平滚动的距离,以设备单位计。如果窗口类风格为CS_OWNDC或CS_CLASSDC,则此参数则使用逻辑单位而非设备单位。当向左滚动窗体内容时,参数值必须为负。
YAmount
[in]指定垂直滚动的距离,以设备单位计。如果窗口类风格为CS_OWNDC或CS_CLASSDC,则此参数则使用逻辑单位而非设备单位。当向上滚动窗体内容时,参数值必须为负。
lpRect
[in]指向RECT结构的指针,该结构指定了将要滚动的客户区范围。若此参数为NULL,则整个客户区域将被滚动。
lpClipRect
[in]指向RECT结构的指针,该结构指定了要滚动的裁剪区域。只有这个矩形中的位才会被滚动。在矩形之外的位不会被影响,即使它们是在lpRect矩形之内。(见代码"测试一")假如lpClipRect为NULL,则不会在滚动矩形上进行裁剪。
返回值:
如果函数运行成功,返回值为非零;如果函数运行失败,返回值为零。若想获得更多的错误信息,请调用GetLastError函数。
ScrollWindowEx
函数功能:滚动窗口客户区
int ScrollWindowEx(
__in HWND hWnd,
__in int dx,
__in int dy,
__in const RECT *prcScroll,
__in const RECT *prcClip,
__in HRGN hrgnUpdate,
__out LPRECT prcUpdate,
__in UINT flags
);
参数:
hWnd:客户区域将被滚动的窗体句柄。
dx:在设备单元中,指定水平滚动数量。在向左滚动时此参数必须为负。
dy:在设备单元中,指定垂直滚动数量。在向上滚动时此参数必须为负。
prcScroll:指向RECT结构,它指定了将被滚动的客户区域部分。
prcClip:指向包含了类似于被剪下矩形的RECT结构。只有在剪下内部的小块图形才受影响。从矩形外向内部的滚动部分将被着色;而从内向外的滚动部分将不再被着色。
hrgnUpdate:处理已被修改的区域,保存这些由于滚动而无效的区域。此参数可以为空。
prcUpdate:指向RECT结构,它接收由于滚动使得矩形无效部分的边界。此参数值可以为空。
flags:指定控制滚动的标志。这个参数可以是下面的值:
SW_ERASE:通过发送WM_ERASEBKGND消息给窗体。
SW_INVALIDATE:在滚动后,使得由参数hrgnUpdate标识的无效区域被擦除。
SW_SCROLLCHILDREN:动所有由参数prcScroll指出交叉重叠矩形的子窗体。子窗体按照dx和dy规定的像素个数滚动。系统发送消息给所有由prcScroll指出交叉重叠矩形的子窗体,即使他们不移动。
返回值:如果函数运行成功,返回值为SIMPLEREGION(矩形的无效区域),COMPLEXREGION(非矩形的无效区域)或NULLREGION(没有使无效的区域)如果函数运行成功,返回值为ERROR。若想获得更多的错误信息,请调用GetLastError函数。