SCROLLBAR

#include <windows.h>
#include "sysmets.h"

static int cxChar,cyChar,cyClient;

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	SCROLLINFO si;
	PAINTSTRUCT ps;
	static int vpos;
	switch (msg)
	{
	case WM_CREATE:
		{
			hdc=GetDC(hWnd);
			TEXTMETRIC tm;
			GetTextMetrics(hdc,&tm);
			cxChar=tm.tmAveCharWidth;
			cyChar=tm.tmHeight+tm.tmExternalLeading;
			ReleaseDC(hWnd,hdc);
			return 0;
		}

	case WM_SIZE:
		{
			cyClient=HIWORD(lParam);
			si.cbSize=sizeof(si);
			si.fMask=SIF_RANGE|SIF_PAGE;
			si.nMin=0;
			si.nMax=NUMLINES-1;
			si.nPage=cyClient/cyChar;
			SetScrollInfo(hWnd,SB_VERT,&si,TRUE);
			return 0;
		}
	
	case WM_VSCROLL:
		{
			si.cbSize=sizeof(si);///少了这句scrollbar就不响应消息!
			//在第一次使用SCROLLINFO结构对象时,必须先设置si.cbSize属性!!!同wndclass的cbsize属性一样,不设置会出错!!!!(运行时错误!)
			si.fMask=SIF_ALL;
			GetScrollInfo(hWnd,SB_VERT,&si);
			vpos=si.nPos;
			switch(LOWORD(wParam))
			{
			case SB_LINEUP:
				si.nPos-=1;
				break;
			case SB_LINEDOWN:
				si.nPos+=1;
				break;
			case SB_PAGEUP:
				si.nPos-=si.nPage;
				break;
			case SB_PAGEDOWN:
				si.nPos+=si.nPage;
				break;
			case SB_THUMBPOSITION:
				si.nPos=si.nTrackPos;
				break;
			default:
				break;
			}
			si.fMask=SIF_POS;
			SetScrollInfo(hWnd,SB_VERT,&si,TRUE);
			GetScrollInfo(hWnd,SB_VERT,&si);
			if(vpos!=si.nPos)
			{
				ScrollWindow(hWnd,0,(vpos-si.nPos)*cyChar,NULL,NULL);
				UpdateWindow(hWnd);
			}
			return 0;
		}

	case WM_PAINT:
		{
			si.cbSize=sizeof(si);
			si.fMask=SIF_ALL;
			GetScrollInfo(hWnd,SB_VERT,&si);
			hdc=BeginPaint(hWnd,&ps);
			int istart=si.nPos+ps.rcPaint.top/cyChar;
			int iend= min(NUMLINES-1,si.nPos+ps.rcPaint.bottom/cyChar);
			for(int i=istart;i<=iend;i++)//如果写成i<iend,会出现点击linedown时,字符不能完整出现,只出现一大半
			{
				char szNum[10];
				int y=(i-si.nPos)*cyChar;
				TextOut(hdc,0,y,sysmetrics[i].szLabel,strlen(sysmetrics[i].szLabel));
				TextOut(hdc,30*cxChar,y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));
				SetTextAlign(hdc,TA_RIGHT|TA_TOP);
				TextOut(hdc,80*cxChar,y,szNum,wsprintf(szNum,"%d",GetSystemMetrics(sysmetrics[i].index)));
				SetTextAlign(hdc,TA_LEFT);
			}
			EndPaint(hWnd,&ps);
			return 0;
		}
	
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}

	return DefWindowProc(hWnd,msg,wParam,lParam);
}

int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, 

__in LPSTR lpCmdLine, __in int nShowCmd )
{
	WNDCLASSEX wc;
	wc.cbSize=sizeof(wc);
	wc.cbClsExtra=0;
	wc.cbWndExtra=0;
	wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.hCursor=LoadCursor(NULL,IDC_CROSS);
	wc.hIcon=LoadIcon(NULL,IDI_HAND);
	wc.hIconSm=NULL;
	wc.hInstance=hInstance;
	wc.lpfnWndProc=WndProc;
	wc.lpszClassName="MyScrollBar";
	wc.lpszMenuName=NULL;
	wc.style=CS_HREDRAW|CS_VREDRAW;
	RegisterClassEx(&wc);

	HWND hWnd=CreateWindow("MyScrollBar","system sysmet style",WS_OVERLAPPEDWINDOW|WS_VSCROLL,
		CW_USEDEFAULT,CW_USEDEFAULT,640,480,NULL,NULL,hInstance,0);
	if(!hWnd) return 0;
	ShowWindow(hWnd,SW_NORMAL);
	UpdateWindow(hWnd);

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

注意:

1:for(int i=istart;i<=iend;i++)如果写成i<iend,会出现产生SB_LINEDOWN消息时,字符可能不能完整出现,只出现一部分

原因:此窗口的最上面是严格对应sysmetric数组的某一行的,但是由于窗口的大小可以改变,窗口最下面可能会只显示某行的一部分。


当产生SB_LINEDOWN消息时,无效距形是从最下面向上推进的一个高度为cychar大小的矩形,但是此矩形不一定正好包含的是一个完整的sysmetric的一个元素,如上面所说.而for(int i=istart;i<=iend;i++)重绘的行数正好是无效区域的高度/cyChar+1(在一个有n行的无效区域内,可能会出现n+1行sysmetric数据(某两行各出现一部分,如上图))

2: 由于i<=iend的条件,所以i会NUMLINE,超出了sysmetric数组的边界,所以要用

int iend= min(NUMLINES-1,si.nPos+ps.rcPaint.bottom/cyChar);限制iend的范围

3:当创建SCROLLINFO,WNDCLASSEX等等对象时,首次使用前必须给.cbsize赋值,否则会出错(运行时错误)。


4:ScrollWindow()函数调用后,会给窗口关联的PAINTSTRUCT对象的无效区域初始化,同时此函数还会把窗口关联的scrollinfo中的数据npos设置为滚动后的新值。


5:


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值