滚动条的使用1

滚动条的使用

1、  滚动条的创建

        在创建窗口的CreateWindow函数的风格参数中加上WM_VSCROLL 或 WM_HSCROLL风格,这样创建出来的窗口就带了滚动条。这里,滚动条不是单独的窗口,它只是窗口的一部分(可以用spy++验证),当加入滚动条后,滚动条嵌入的区域不算在客户区内,客户区自动缩进了。创建语句如下:


HWND hWnd;
	hWnd = CreateWindow(pszClassName,
						_T("MyApplication"),
						WS_OVERLAPPEDWINDOW | WS_VSCROLL,		//添加垂直滚动条
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						600,
						480,
						NULL,
						NULL,
						hInstance,
						NULL);


2、滚动条消息的产生

        当用户通过鼠标操作滚动条时,就会产生WM_VSCROLL消息(或者WM_HSCROLL消息),在程序中根据此消息的通知码(wParam参数)来做出相应的反应。这一过程是通过程序和Windows共同负责的,维护滚动条以及滑块在滚动条中的位置。

        对于Windows而言:

                它主要向拥有滚动条的窗口发送滚动条消息;

        对于程序而言:

                首先初始化滚动条的位置和滚动范围;

                而后根据通知码来更新滑块的位置,并且更新客户区域的内容。


3、滚动条的消息的通知码:

产生WM_VSCROLL消息或WM_HSCROLL消息时,wParam参数的低位字代表了通知码,即鼠标在滚动条上的操作,高位字为滚动条的位置(SB_THUMBPOSITION、SB_THUMBTRACK通知码时才有用)。lParam这里为NULL,如果这个消息是通过滚动条控件发生的,那么该参数为控件的句柄。对通知码的说明见下图:


 

                               #define SB_LINEUP                                                    0       //点击了向上的箭头按钮

                              #define SB_LINELEFT                                                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_BOTTOM                                                    7       //滚动条达到了最大值

                              #define SB_RIGHT                                                         7       //同上

                              #defineSB_ENDSCROLL                                             8

说明:

        1、  对于达到最值的通知码(SB_TOP、SB_LEFT、SB_BOTTOM、SB_RIGHT),当滚动条是窗口的一部分时,则不会收到这些通知码。

        2、  对于橙色的通知码,当鼠标释放时,会产生带有SB_ENDSCROLL通知码的滚动条消息,而其他两个通知码是对应的(鼠标释放和鼠标按下)



4、示例代码

#define  _CRT_SECURE_NO_WARNINGS
#define _CRT_NON_CONFORMING_SWPRINTFS

#define MAX_NUM_LINE 100		//显示文字的最大行数

#include <windows.h>
#include <tchar.h>


LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI _tWinMain(HINSTANCE hInstance,
					 HINSTANCE hPreInstance,
					 LPTSTR lpCmdLine,
					 int nShowCmd)
{
	TCHAR *pszClassName = _T("MyClass");

	WNDCLASS  wndClass;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;
	wndClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndClass.hInstance = hInstance;
	wndClass.lpszClassName = pszClassName;
	wndClass.lpszMenuName = NULL;

	BOOL bRet;
	bRet = RegisterClass(&wndClass);
	if (!bRet)
	{
		MessageBox(NULL, _T("注册窗口类失败"), NULL, MB_OK);
		return FALSE;
	}

	HWND hWnd;
	hWnd = CreateWindow(pszClassName,
						_T("MyApplication"),
						WS_OVERLAPPEDWINDOW | WS_VSCROLL,		//添加垂直滚动条
						CW_USEDEFAULT,
						CW_USEDEFAULT,
						600,
						480,
						NULL,
						NULL,
						hInstance,
						NULL);
	if (!hWnd)
	{
		MessageBox(NULL, _T("创建窗口失败!"), NULL, MB_OK);
		return FALSE;
	}

	ShowWindow(hWnd, nShowCmd);
	UpdateWindow(hWnd);

	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

//窗口过程
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static int cyChar;			//一个字符的高度
	static int iVscrollPos = 0;	//垂直滚动条所在位置
	static int cyClient;		//客户区的高度
	TEXTMETRIC tm;
	PAINTSTRUCT ps;
	HDC hdc;
	
	switch (uMsg)
	{
	case WM_CREATE:
		hdc = GetDC(hWnd);
		GetTextMetrics(hdc, &tm);
		cyChar = tm.tmHeight + tm.tmExternalLeading;	//每个字符的高和每行文字应该预留的间隔(可能为0)
		ReleaseDC(hWnd, hdc);

		SetScrollRange(hWnd, SB_VERT, 0, MAX_NUM_LINE, FALSE);	//设置滚动条滚动范围
		SetScrollPos(hWnd, SB_VERT, iVscrollPos, TRUE);			//设置滚动条滑块位置
		return 0;
	case WM_SIZE:
		cyClient = HIWORD(lParam);				
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		for (int i = 0; i < MAX_NUM_LINE; ++i)	//显示 MAX_NUM_LINE 行文字
		{
			TCHAR buffer[100];
			_stprintf(buffer, _T("第%4d 行"), i + 1);
			//TextOut(hdc, 0, i * cyChar, buffer, _tcslen(buffer));	
			TextOut(hdc,						//更新客户区显示的内容
					0, 
					(i - iVscrollPos) * cyChar, //实质是显示的位置发生了改变
					buffer, 
					_tcslen(buffer));
		}
		EndPaint(hWnd, &ps);
		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;
			break;
		case SB_PAGEDOWN:
			iVscrollPos += cyClient / cyChar;
			break;
		case SB_THUMBTRACK:					//如果鼠标不松开,此消息将不断产生
			iVscrollPos = HIWORD(wParam);
			break;
		case SB_THUMBPOSITION:				//鼠标松开时,产生此消息
			iVscrollPos = HIWORD(wParam);
			break;
		}
		iVscrollPos = max(0, min(iVscrollPos, MAX_NUM_LINE));	//确保滑块位置在滚动的范围内
		if (iVscrollPos != GetScrollPos(hWnd, SB_VERT))
		{
			SetScrollPos(hWnd, SB_VERT, iVscrollPos, TRUE);		//设置滑块位置
			InvalidateRect(hWnd, NULL, TRUE);					//更新客户区的内容
		}
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}



5、运行结果如下




缺点:当显示的行数太大时,则实时性有一定的缓慢;最后一行信息不应该显示到客户区的顶部,即某些文本显示要有适当的位置。


6、相关函数说明

BOOL SetScrollRange(
 HWND hWnd,    // handle to window
  intnBar,     // scroll bar
  intnMinPos,  // minimum scrolling position
  intnMaxPos,  // maximum scrolling position
 BOOL bRedraw  // redraw flag
);

设置滚动条的滚动范围,参数说明如下:

hWnd:滚动条所属的窗口句柄,如果是控件,那么则是控件的句柄

nBar:滚动条的类型,可以是值的其中一个:

SB_CTL

   该滚动条是一个滚动条控件

SB_HORZ

   窗口的标准水平滚动条

SB_VERT

   窗口的标准垂直滚动条

nMinPos:滚动范围的最小值

nMaxPos:滚动范围的最大值

bRedraw :设置范围后,决定是否根据新的范围来重绘滚动条

 

BOOL GetScrollRange( 
HWND hWnd,    // handle to window
int nBar,        // scroll bar options
LPINTlpMinPos,  // receives minimum position
LPINTlpMaxPos   // receives maximum position);

获取滚动条的滚动范围

 

int SetScrollPos( 
HWND hWnd,     // handle to window
int nBar,             //scroll bar 
int nPos,             //new position of scroll box
BOOLbRedraw     // redraw flag);

设置滚动条滑块的位置,该值是一个32位的数据,而wParam的高位字却是16位,在处理时应该注意到这点

 

int SetScrollInfo( 
HWND hwnd,         // handle to window
       int fnBar,               //scroll bar type
       LPCSCROLLINFO lpsi,     //scroll parameters 
BOOLfRedraw        // redraw flag
);

设置滚动条的相关信息,包括滚动范围、滑块位置、页大小,也决定是否重绘

主要说明的是SCROLLINFO结构体:

typedef struct tagSCROLLINFO { 
    UINT cbSize; 		//结构体大小
    UINT fMask; 		//掩码,指定要操作哪些属性
    int  nMin; 		//最小范围
    int  nMax; 		//最大范围
    UINT nPage; 		//页大小,即滑块的大小,这个值决定它所占滚动条的大小,其值在滚动范围之间,如果超过了范围,那么滚动条将消失,动态改变它的大小可以表达文档显示的完整度
    int  nPos; 		//滑块位置
    int  nTrackPos; 	//滑块在滚动中的位置,在处理SB_THUMBTRACK时可获取
}   SCROLLINFO, *LPSCROLLINFO; 

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

获取滚动条的相关信息


7、滚动条相关消息

         SBM_ENABLE_ARROWS           //操作箭头按钮

         SBM_GETPOS

         SBM_GETRANGE

         SBM_GETSCROLLBARINFO

         SBM_GETSCROLLINFO

         SBM_SETPOS

         SBM_SETRANGE

         SBM_SETRANGEREDRAW

         SBM_SETSCROLLINFO


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值