滚动条
windows应用程序使用两种滚动条:
垂直滚动条: 将显示区域/文件的内容向上或者向下移动
水平滚动条: 将显示区域/文件的内容向左或者向右移动
滚动条的工作方式:
使用者向下卷动是想看文件下面的内容,而程序实际需要将文件的内容向上移动
windows文件和表头标识符依据的是使用者观点定义的:
向上卷动意味着朝文件的开头移动,而向下卷动则意味着朝文件尾部移动
给窗口添加滚动条:
利用CreateWindow函数生成窗口的时候,将窗口样式WS_VSCROLL和WS_HSCROLL位旗标加上即可生成具有垂直滚动条和
水平滚动条的窗口。
垂直滚动条将延伸为显示区域的整个高度,而水平滚动条则延伸为显示区域的整个宽度
对于特定的显示驱动程序和显示分辨率;垂直滚到条的宽度和水平滚到条的高度是固定不变的。
可以通过:
GetSystemMetrics呼叫来获取垂直滚动条的宽度和水平滚动条的高度信息。
滚动条的消息处理:
windows系统负责处理对滚动条的所有鼠标操作
窗口滚动条没有自动的键盘接口,如果滚动条需要键盘接口,则需要编制响应的消息响应程序
滚动条的范围和位置
滚动条具有两个常用属性:
滚动条的范围: 分别代表最大值和最小值
当垂直滚动条方块在卷动列的顶部的时候,卷动方块具有最小值
当垂直滚动条方块在卷动列的底部的时候,卷动方块具有最大值
当水平滚动条方块在卷动列的左部的时候,卷动方块具有最小值
当水平滚动条方块在卷动列的右部的时候,卷动方块具有最大值
缺省情况下: 滚动条的范围从0都100, 可以通过呼叫系统提供的函数来改变滚动条范围。
通过下面函数改变这些值:
BOOL SetScrollRange(HWND,int iBar,int iMinPos,int iMaxPos,BOOL bRedraw)
参数:hwnd 需要改变的滚动体属性的窗口的句柄
iBar 确定是垂直方向还是水平方向需要重新设置,可以取值:
SB_CTL:设置滚动条控制的范围
SB_HORZ: 表示设置水平滚动条的范围
SB_VERT: 表示设置垂直滚动条的范围
iMinPos: 设置的最小范围值
iMaxPos 设置的最大范围值
bRedraw 指定滚动条是否重画以反映设置改变,如果为TRUE则需要重画,为FALSE则不需要重画
如果在SetScrollRage函数之后还调用了其他的影响滚动条位置的函数则应将bRedraw
设置为FALSE,避免过多的重画。
滚动条的位置: 代表卷动方块在滚动条范围内的具体位置。
滚动条位置总是离散值,例如范围从0到4的滚动条具有5个卷动方块位置
可以通过下面的函数设置滚动条的位置:
BOOL SetScrollPos(HWND hwnd,int iBar, int iPos,BOOL bRedraw);
参数:hwnd 同SetScrollRange
iBar 同SetScrollRange
iPos 设定的滚动条的新的位置,在iMaxPos和iMinPos范围之间
bRedraw 同SetScrollRange
获取滚动条的信息:
GetScrollRange和GetScrollPos函数
处理机制:
在程序内使用滚动条时,由系统和程序共同管理滚动条及其卷动方块的位置
windows的处理:
1、当使用者在滚动条内单击鼠标的时候,提供反相显示的闪烁提示
2、当使用者在滚动条内拖动卷动方块时移动卷动方块
3、为包含滚动条窗口的窗口消息处理程序发送滚动条消息
4、处理所有的滚动鼠标事件
应用程序需处理:
1、初始化滚动条范围和位置
2、处理窗口消息处理程序的滚动条消息
3、更新滚动条内卷动方块的位置
4、更改显示区域的内容以响应对滚动条的更改
滚动条消息
在用鼠标单击滚动条或者拖动卷动方块时会产生滚动条消息:
WM_VSCROLL 上下移动
WM_HSCROLL 左右移动
在滚动条上的每个鼠标动过都将产生两个消息: 一个在按下鼠标按钮时产生,一个在释放按钮是产生
滚动条消息的附加信息: wParam和lParam, 对于窗口而建立的滚动条,其lParam可以忽略;lParam
只用于作为子窗口而建立的滚动条(通常是对话框)
wParam消息
wParam消息参数被分为低字组和高字组,wParam的低字组是一个数值,他指出了鼠标对滚动条进行的操作
低字组数值被看做一个通知码。 通知码值以SB_开头定义了一些预定义标识符;例如:
#define SB_LINEUP 0 //垂直向上卷动一行
#define SB_LINELST 0
#define SB_LINEDOWN 1
#define SB_LINERIGHT 1
#define SB_PAGEUP 2
#define SB_PAGELEFT 2
#define SB_PAGEDOWN 3
#define SB_PAGERIGHT 3
#define SB_THUMBPOSITION 4
#define SB_THUMBTRACK 5
#define SB_TOP 6
#define SB_LEFT 6
#define SB_BUTTON 7
#define SB_RIGHT 7
#define SB_ENDSCROLL 8
windows关于滚动条的消息
在滚动条的各个部位按住鼠标键,程序就能收到多个滚动条消息,当释放鼠标键后程序会收到一个带有SB_ENDSCROLL通知码的消息
通常可以忽略这个消息,windows不会改变卷动方块的位置。可以在程序中通过呼叫SetScrollPos来改变卷动块的位置。
SB_THUMBTRACK和SB_THUMBPOSITION通知码消息
产生时机: 把鼠标的光标放在卷动方块上并按住鼠标键移动时就会产生带有通知码SB_THUMBTRACK和SB_THUMBPOSITION的滚动条消息
wParam消息参数:
如果产生了SB_THUMBTRACK的通知码消息,那么wParam参数的高字组是使用者在拖动卷动方块时的当前位置,该值在iMaxPos和
iMinPos之间。
如果产生了SB_THUMBPOSITION时,wParam参数的高字组是使用者释放鼠标键后卷动方块的最终位置。
在处理其他通知码滚动条消息时wParam参数的高字组应该不处理。
在程序中通常不同时处理这两个通知码消息;
处理SB_THUMBTRACK通知码时,使用者拖动卷动块时,程序需要实时移动显示区域的内容。而处理SB_THUMBPOSITION则可以在
使用者停止卷动方块时移动显示区域的内容。
SetScrollPos函数
在程序收到SB_THUMBTRACK消息时如果不调用SetScrollPos函数处理,则释放鼠标后卷动块会回到原来的位置。
使用SetScrollRange的时候使用int 32位的数值是有效的,但是wParam的高字组是16位的,这样可能造成不能完全正确的反映
滚动条的鼠标消息,需要调用:
GetScrollInfo函数来得到消息。
作为一个小总结下面给出一个简单的应用的实例代码:
/*
*
* 滚动条消息处理函数实例
*
*/
#include <windows.h>
#include <winuser.h>
#include <stdio.h>
LRESULT CALLBACK MainWndProc(HWND, UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR szPstr,
int iCmdShow)
{
HWND MainHwnd;
TCHAR *szAppName=TEXT("Scroll");
TCHAR *wndClassName=TEXT("Scroll");
MSG msg;
WNDCLASS mainwndclass;
mainwndclass.cbClsExtra=0;
mainwndclass.cbWndExtra=0;
mainwndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
mainwndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
mainwndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
mainwndclass.hInstance=hInstance;
mainwndclass.lpfnWndProc=MainWndProc;
mainwndclass.lpszClassName=wndClassName;
mainwndclass.lpszMenuName=NULL;
mainwndclass.style=CS_VREDRAW | CS_HREDRAW;
if(!RegisterClass(&mainwndclass))
{
MessageBox(NULL,TEXT("You need a NT system to run this program!"),TEXT("Warnging"),MB_OK);
return 0;
}
MainHwnd=CreateWindow(wndClassName,
TEXT("Scroll"),
WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCROLL,
100,
100,
640,
480,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(MainHwnd,iCmdShow);
UpdateWindow(MainHwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
TCHAR szBuffer[10];
static int cxChar,
cxCaps,
cyChar,
cyClient,
iVscrollPos;
int i,
y;
switch(message)
{
case WM_CREATE:
hdc=GetDC(hwnd);
GetTextMetrics(hdc,&tm);
cxChar=tm.tmAveCharWidth;
cxCaps=(tm.tmPitchAndFamily & 1 ? 3 : 2 )*cxChar/2;
cyChar=tm.tmHeight+tm.tmExternalLeading;
ReleaseDC(hwnd,hdc);
SetScrollRange(hwnd,SB_CTL,100,100,FALSE);
SetScrollPos(hwnd,SB_VERT,0,TRUE);
return 0;
case WM_SIZE:
cyClient=HIWORD(lParam);
return 0;
case WM_VSCROLL:
switch(LOWORD(wParam))
{
case SB_LINEUP:
iVscrollPos-=1;
break;
case SB_LINEDOWN:
iVscrollPos+=1;
break;
case SB_PAGEUP:
iVscrollPos-=cyClient/cyChar; //cyClient是显示区域的高度,
break;
case SB_PAGEDOWN:
iVscrollPos+=cyClient/cyChar;
break;
case SB_THUMBPOSITION:
iVscrollPos=HIWORD(wParam);
break;
default :
break;
} //switch(wParam)
iVscrollPos=max(0,min(iVscrollPos,1000));
if(iVscrollPos != GetScrollPos(hwnd,SB_VERT))
{
SetScrollPos(hwnd,SB_VERT,iVscrollPos,TRUE);
InvalidateRect(hwnd,NULL,TRUE);
}
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
TextOut(hdc,0,0,TEXT("My first Scroll Pronram!"),strlen("My first Scroll Pronram!"));
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}