《Windows程序设计》的一个问题

clever101
博客专家认证
2011-02-21 06:25:44
《Windows程序设计》里面有一个小节:建立更好的滚动,其中的一个例程的代码是:



#include "stdafx.h"
#include "SYSMETS1.h"

LRESULT CALLBACK WndProc(HWND hWnd,UINT msg, WPARAM wp,LPARAM lp);

int WINAPI WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd)
{
static TCHAR szAppName[] = _T("SysMets1");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
// load the icon of application
wndclass.hIcon = ::LoadIcon(NULL,IDI_APPLICATION);
// load the cursor of application
wndclass.hCursor = ::LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
// register the window class
if (!::RegisterClass(&wndclass))
{
::MessageBox(NULL,TEXT("This program require Window NT"),szAppName,MB_ICONERROR);
return 0;
}
// create really window
hwnd = ::CreateWindow(szAppName,_T("Get System Metric No.1"),WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
::ShowWindow(hwnd,nShowCmd);
::UpdateWindow(hwnd); // immedially post WM_PAINT message
// when get the meaages,translte the message and dispatch message.
while (::GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd,UINT message, WPARAM wp,LPARAM lp)
{
static int cxChar;
static int cxCaps;
static int cyChar;
static int cyClient; // the height of client
static int cxClient; // the width of client
static int nPaintBeg;
static int nPaintEnd;
static int nMaxWidth;
int nVertPos = 0;
int nHorzPos = 0;
SCROLLINFO si;
HDC hdc = NULL;
PAINTSTRUCT ps;
TCHAR szBuffer[10];
TEXTMETRIC tm;
switch (message)
{
case WM_CREATE:
{
hdc = ::GetDC(hWnd);
::GetTextMetrics(hdc,&tm); // get text size of system
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);
//::SetScrollPos(hWnd,SB_VERT,nVscrollPos,TRUE);
// save the width of three columns
nMaxWidth = 40*cxChar+22*cxCaps;
return 0;
}
case WM_SIZE:
{
// cyClient = HIWORD(lp); // get the height of client
// save the width and height of window when changed the size of window
cxClient = LOWORD(lp);
cyClient = HIWORD(lp);
// set vertical scroll bar range and page size
si.cbSize = sizeof(SCROLLBARINFO);
si.fMask = SIF_RANGE|SIF_PAGE;
si.nMin = 0;
si.nMax = NUMLINES - 1;
si.nPage = cyClient/cyChar;
SetScrollInfo(hWnd,SB_VERT,&si,TRUE);
// set horizontal scroll bar and page size
si.cbSize = sizeof(SCROLLBARINFO);
si.fMask = SIF_RANGE|SIF_PAGE;
si.nMin = 0;
si.nMax = 2 + nMaxWidth/cxChar;
si.nPage = cxClient/cxChar;
SetScrollInfo(hWnd,SB_HORZ,&si,TRUE);
return 0;
}
case WM_VSCROLL:
{
// get all vertical scroll bar information
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL;
::GetScrollInfo(hWnd,SB_VERT,&si);
// save the position for comparison later on
nVertPos = si.nPos;
switch (LOWORD(wp))
{
case SB_LINEUP:
{
si.nPos -=1;// the height decrease 1 unit
break;
}
case SB_LINEDOWN:
{
si.nPos +=1;// the height increase 1 unit
break;
}
case SB_PAGEUP:
{
// back to prev page, the cyClient/cyChar is the number of row in one page
si.nPos -= cyClient/cyChar;
break;
}
case SB_PAGEDOWN:
{
// back to next page
si.nPos += cyClient/cyChar;
break;
}
case SB_THUMBPOSITION:
{
si.nPos = HIWORD(wp);
break;
}
default:
break;
}
// set the position and then retrieve it.Due to adjustments
// by Windows it may not be the same as the value set.
si.fMask = SIF_POS;
SetScrollInfo(hWnd,SB_VERT,&si,TRUE);
GetScrollInfo(hWnd,SB_VERT,&si);
//if the position has changed,scroll the window update it
if (si.nPos!=nVertPos)
{
::ScrollWindow(hWnd,0,cyChar*(nVertPos-si.nPos),NULL,NULL);
::UpdateWindow(hWnd);
}
return 0;
}
case WM_HSCROLL:
{
// get all the vertical scroll bar information
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
// save the position for comparison later on
::GetScrollInfo(hWnd,SB_HORZ,&si);
nHorzPos = si.nPos;
switch (LOWORD(wp))
{
case SB_LINELEFT:
{
si.nPos -=1;
break;
}
case SB_LINERIGHT:
{
si.nPos +=1;
break;
}
case SB_PAGELEFT:
{
si.nPos -= si.nPage;
break;
}
case SB_PAGERIGHT:
{
si.nPos += si.nPage;
break;
}
case SB_THUMBPOSITION:
{
si.nPos = si.nTrackPos;
break;
}
default:
break;
}
// set the position and then retrieve it.due to adjustments
// by windows it may not be the same as the value set
si.fMask = SIF_POS;
::SetScrollInfo(hWnd,SB_HORZ,&si,TRUE);
::GetScrollInfo(hWnd,SB_HORZ,&si);
// if the postion has changed ,scroll the window
if (si.nPos!=nHorzPos)
{
// why (nHorzPos-si.nPos)
::ScrollWindow(hWnd,cxChar*(nHorzPos-si.nPos),0,NULL,NULL);
}
return 0;
}
case WM_PAINT:
{
hdc = ::BeginPaint(hWnd,&ps);
// get vertical scroll bar position
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
::GetScrollInfo(hWnd,SB_VERT,&si);
nVertPos = si.nPos;
// get horizontal scroll bar position
GetScrollInfo(hWnd,SB_HORZ,&si);
nHorzPos = si.nPos;
// find painting limits
int nPaintBeg = max(0,nVertPos+ps.rcPaint.top/cyChar); // the begin row
int nPaintEnd = min(NUMLINES-1,nVertPos+ps.rcPaint.bottom/cyChar); // the end row

for (int i =nPaintBeg;i<=nPaintEnd;i++)
{
// calculate the y position of draw region, when y position less 0,skip
int x = cxChar*(1-nHorzPos); // why is 1-nHorzPos
int y = cyChar*(i-nVertPos);

::TextOut(hdc,x,y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));
::TextOut(hdc,x+22*cxCaps,y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));
::SetTextAlign(hdc,TA_RIGHT|TA_TOP);
::TextOut(hdc,x+22*cxCaps+40*cxChar,y,szBuffer,wsprintf(szBuffer,_T("%5d"),::GetSystemMetrics(sysmetrics[i].Index)));
::SetTextAlign(hdc,TA_LEFT|TA_TOP);
}
::EndPaint(hWnd,&ps);
return 0;
}
case WM_DESTROY:
// close the application
::PostQuitMessage(0);
return 0;
default:
break;
}
// default process
return ::DefWindowProc(hWnd,message,wp,lp);
}



为什么这里是

if (si.nPos!=nHorzPos)
{
// why (nHorzPos-si.nPos)
::ScrollWindow(hWnd,cxChar*(nHorzPos-si.nPos),0,NULL,NULL);
}



我查了MSDN:
BOOL ScrollWindow( HWND hWnd,
int XAmount,
int YAmount,
const RECT *lpRect,
const RECT *lpClipRect
);
Parameters

hWnd
[in] Handle to the window where the client area is to be scrolled.
XAmount
[in] Specifies the amount, in device units, of horizontal scrolling. If the window being scrolled has the CS_OWNDC or CS_CLASSDC style, then this parameter uses logical units rather than device units. This parameter must be a negative value to scroll the content of the window to the left.
YAmount
[in] Specifies the amount, in device units, of vertical scrolling. If the window being scrolled has the CS_OWNDC or CS_CLASSDC style, then this parameter uses logical units rather than device units. This parameter must be a negative value to scroll the content of the window up.
lpRect
[in] Pointer to the RECT structure specifying the portion of the client area to be scrolled. If this parameter is NULL, the entire client area is scrolled.
lpClipRect
[in] Pointer to the RECT structure containing the coordinates of the clipping rectangle. Only device bits within the clipping rectangle are affected. Bits scrolled from the outside of the rectangle to the inside are painted; bits scrolled from the inside of the rectangle to the outside are not painted.
Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

这里nHorzPos指旧的滚动条位置,si.nPos为新的滚动条位置,那么::ScrollWindow(hWnd,cxChar*(nHorzPos-si.nPos),0,NULL,NULL);为什么不是::ScrollWindow(hWnd,cxChar*(si.nPos-nHorzPos),0,NULL,NULL);,而是::ScrollWindow(hWnd,cxChar*(nHorzPos-si.nPos),0,NULL,NULL);呢?MSDN上说XAmount
[in] Specifies the amount, in device units, of horizontal scrolling. If the window being scrolled has the CS_OWNDC or CS_CLASSDC style, then this parameter uses logical units rather than device units. This parameter must be a negative value to scroll the content of the window to the left.

就是向左移动必须是一个负值。向左移动nHorzPos必定大于si.nPos,cxChar为单位字符的偏移量,是一个正值,nHorzPos大于si.nPos,nHorzPos-si.nPos也必定是一个正值,这岂不是和MSDN冲突。但是我把代码改为::ScrollWindow(hWnd,cxChar*(si.nPos-nHorzPos),0,NULL,NULL);却是不对的。


...全文
106 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
yiruirui0507 2011-02-21
  • 打赏
  • 举报
回复
看清楚
This parameter must be a negative value to scroll the content of the window to the left.
Waistcoat21 2011-02-21
  • 打赏
  • 举报
回复
This parameter must be a negative value to scroll the content of the window to the left.

这里指的是窗口的内容,你向右拉滚动条时窗口内容是向左移动的。

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧