您的位置:首页 > 其它

Windows 程序设计 第四章 sysmets2

2012-09-28 19:45 363 查看
/*----------------------------------------------------
SYSMETS2.C -- System Metrics Display Program No. 2
(c) Charles Petzold, 1998
----------------------------------------------------*/

/*
第一次编译的时候出现下面的提示,后来就没有出现了

--------------------Configuration: chap04sysmets2 - Win32 Debug--------------------
Compiling...
sysmets2.c
NOTE: WINVER has been defined as 0x0500 or greater which enables
Windows NT 5.0 and Windows 98 features. When these headers were released,
Windows NT 5.0 beta 1 and Windows 98 beta 2.1 were the current versions.
For this release when WINVER is defined as 0x0500 or greater, you can only
build beta or test applications.  To build a retail application,
set WINVER to 0x0400 or visit http://www.microsoft.com/msdn/sdk to see if retail Windows NT 5.0 or Windows 98 headers are available.
See the SDK release notes for more information.

sysmets2.obj - 0 error(s), 0 warning(s)

*/

// #define WINVER 0x0500
#define WINVER 0x0501
#include <windows.h>
#include "sysmets.h"

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("SysMets2") ;
HWND         hwnd ;
MSG          msg ;
WNDCLASS     wndclass ;

wndclass.style         = CS_HREDRAW | CS_VREDRAW ; //包括了垂直滚动条
wndclass.lpfnWndProc   = WndProc ;
wndclass.cbClsExtra    = 0 ;
wndclass.cbWndExtra    = 0 ;
wndclass.hInstance     = hInstance ;
wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName  = NULL ;
wndclass.lpszClassName = szAppName ;

if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}

hwnd = CreateWindow (szAppName, TEXT ("Get System Metrics No. 2"),
WS_OVERLAPPEDWINDOW | WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int  cxChar, cxCaps, cyChar, cyClient, iVscrollPos /*=1 */ ;
HDC         hdc ;
int         i, y ;
PAINTSTRUCT ps ;
TCHAR       szBuffer[10] ;
TEXTMETRIC  tm ;

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_VERT, 0, NUMLINES - 1, FALSE) ;  // 设置滚动条的范围 0 -- NUMLINES - 1
SetScrollPos   (hwnd, SB_VERT, iVscrollPos, TRUE) ;      //  设置(更新) 滚动条的位置, 在创建窗口是iVscrollPos=0 即滑块在最上顶上
return 0 ;

case WM_SIZE:
cyClient = HIWORD (lParam) ;  // 在WM_SIZE消息中, lParam的低位字 是客户区的宽度,高字位是高度  cyClient  高度
return 0 ;

case WM_VSCROLL:
switch (LOWORD (wParam)) // 在WM_VSCROLL 消息中,wParam的低位字是鼠标在滚动条上的动作,这个值是通知码,有SB_开头
{
case SB_LINEUP:          // 鼠标点击滚动条最上的那个三角箭 ,点击一下,iVscrollPos 减一.
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_THUMBPOSITION:   // 鼠标松开
iVscrollPos = HIWORD (wParam) ;// 对于SB_THUMBPOSITION而言, wParam的高位字是滑块的位置
break ;

default :
break ;
}

iVscrollPos = max (0, min (iVscrollPos, NUMLINES - 1)) ;  // 限定iVscrolPos 在0到NUMLINES - 1 取值范围内

if (iVscrollPos != GetScrollPos (hwnd, SB_VERT))  // 如果iVscrollPos的值变了,则更新其位置,并设置 窗口无效
{
SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;
InvalidateRect (hwnd, NULL, TRUE) ;  //  客户区无效,则产生 WM_PAINT 消息,TRUE 使其后调用的BeginPaint擦除原有的背景.
}
return 0 ;

case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;

for (i = 0 ; i < NUMLINES ; i++)
{
// y是每一行的坐标,为负数时该行文字实际输出到客户区的外面了
// 大于0时,才是输出到 客户区 ,即 i > iVscrollPos时,也就是那些行数位于滑块的下面部分才输出更新吗?
// 假设滑块是向下拉,实际是原来滑块下面的内容在上升,就是这部分需要重绘 ?
/* 测试了发现: 如果滑块在最底下,即iVscrollPos = NUMLINES-1,
在for循环中,i取0到NUMLINES-2时,y都为负数,客户区没有输出,当 i = NUMLINES-1时,
y= 0,此刻y对应客户区的第一行,显示的内容对应是sysmetrics[i] 即 sysmetrics的最后一行.
*/

y = cyChar * (i - iVscrollPos) ;

TextOut (hdc, 0, y,
sysmetrics[i].szLabel,
lstrlen (sysmetrics[i].szLabel)) ;

TextOut (hdc, 22 * cxCaps, y,
sysmetrics[i].szDesc,
lstrlen (sysmetrics[i].szDesc)) ;

SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;

TextOut (hdc, 22 * cxCaps + 40 * cxChar, y, szBuffer,
wsprintf (szBuffer, TEXT ("%5d"),
GetSystemMetrics (sysmetrics[i].iIndex))) ;

SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
}
EndPaint (hwnd, &ps) ;
return 0 ;

case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}


如果iVscrollPos初始化为1 则创建窗口时滑块的位置如下:

-----


//-------------------------------

//--- 如果把滑块拉到底,则显示的是 原库文件中 最后一行(最后一个元素).....如下图:

-----
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: