问题:这是WINDOWS程序设计这本书上第四章输出文字中的一个例子(例4-4),主要功能
是练习处理滚动条,程序有些长,我只显示了垂直滚动条的部分.版排的不好,请大家见谅
我的问题是:1、当我单击垂直滚动条时,显示区域中的信息发生卷动,这个卷是由函数SCROLLWINDOW产生的,
   还是由WM_PAINT消息中的TEXTOUT输出的.如果是由函数SCROOLLWINDOW产生的,能否解释一下卷动的过程.
2、调用SCROOLLWINDOW函数后是否产生WM_PAINT消息.
3、WM_PAINT消息中的代码的除了初始化将信息输出到窗口中外,还有没有其它的作用?#include<windows.h>
#include"SYSMETS.H"LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow )
{
static TCHAR szAppName[] = TEXT("SysMets3");
WNDCLASS wndclass;
HWND hwnd;
MSG msg; 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("Program requires Windows NT"), szAppName,    
                              MB_ICONERROR );
return 0;
}

hwnd = CreateWindow( szAppName, TEXT("Get System Metrics NO.3"),
     WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL ,
     0, 0,
     1000, 400,
     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 = 0;
static int cyChar = 0;
static int cxCaps = 0;
static int iMaxWidth = 0;
static int cxClient = 0;
static int cyClient = 0;
int iVertPos = 0;
int iHorzPos = 0;
int iPaintBeg = 0;
int iPaintEnd = 0;
int iCount = 0;
int iXCoordinate = 0;
int iYCoordinate = 0; HDC hdc = 0;
PAINTSTRUCT ps;
TEXTMETRIC tm;
TCHAR szBuffer[ 10 ];
TCHAR szNewBuffer[ 10 ] = {0};
SCROLLINFO si;

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 ); iMaxWidth = 80 * cxChar + 22 * cxCaps; return 0;
}

case WM_SIZE:
{
cxClient = LOWORD( lParam );
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 ); si.cbSize = sizeof( si );
si.fMask = SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL;
si.nMin = 0;
si.nMax = 2 + iMaxWidth / cxChar;
si.nPage = cxClient / cxChar;
SetScrollInfo( hwnd, SB_HORZ, &si, TRUE );

return 0;
} //垂直滚动
case WM_VSCROLL:
{
//Get all the vertical scroll bar information 
si.cbSize = sizeof( si );
si.fMask = SIF_ALL;
GetScrollInfo( hwnd, SB_VERT, &si ); //Save the position for comparison later on 
iVertPos = si.nPos;

switch( LOWORD( wParam ) )
{
case SB_TOP:
{
si.nPos = si.nMin;
break;
}

case SB_BOTTOM:
{
si.nPos = si.nMax;
break;
}

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_THUMBTRACK:
{
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_VERT, &si, TRUE );
GetScrollInfo( hwnd, SB_VERT, &si ); //If the position has changed, scroll the window and 
                                    //update it
if( si.nPos != iVertPos )
{
ScrollWindow( hwnd, 0, cyChar * (  iVertPos - si.nPos ), NULL, NULL );                                              //UpdateWindow( hwnd );
}
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 ); iVertPos = si.nPos; //Get horizontal scroll bar position
GetScrollInfo( hwnd, SB_HORZ, &si );
iHorzPos = si.nPos;

//Find painting limits
iPaintBeg = max( 0, iVertPos + ps.rcPaint.top / cyChar );
         iPaintEnd = min( NUMLINES - 1, iVertPos + ps.rcPaint.bottom / 
                                            cyChar ); for( iCount = iPaintBeg; iCount <= iPaintEnd; iCount++ )
{
iXCoordinate = cxChar * ( 1 - iHorzPos );
iYCoordinate = cyChar * ( iCount - iVertPos ); TextOut( hdc, iXCoordinate, iYCoordinate, 
 sysmetrics[ iCount ].szLabel,
 lstrlen( sysmetrics[ iCount ].szLabel ) ); TextOut( hdc, iXCoordinate + 22 * cxCaps, 
                                             iYCoordinate,
sysmetrics[ iCount ].szDesc,
lstrlen( sysmetrics[ iCount ].szDesc ) ); TextOut( hdc, iXCoordinate + 22 * cxCaps + 40 * 
                                              cxChar, iYCoordinate,
 szBuffer, wsprintf( szBuffer, TEXT("%5d"), 
                                      GetSystemMetrics( sysmetrics[ iCount ].index ) ) );
} EndPaint( hwnd, &ps );
return 0;
}
                                                                                                                                                                                                                                
//QUIT PROGRAM
case WM_DESTROY:
{
PostQuitMessage( 0 );
return 0;
}
default:
break;
} return DefWindowProc( hwnd, message, wParam, lParam );}

解决方案 »

  1.   

    1,卷动的时候,先设置滚动条位置.但你完了你必须调用刷新界面的函数,如InvalidateRect (hwnd, NULL, TRUE)才能起作用.
    2.调用SCROOLLWINDOW函数后是否产生WM_PAINT消息.
    不会,必须你自己调用刷新的函数,然后才能产生WM_PAINT消息.
    3.只要你重新动了界面就会调用WM_PAINT.比如你的窗口最大化和最小化,变化大小的时候.还有别的窗口移动你的窗口上的时候都会调用等.
      

  2.   

    我将UpdateWindow( hwnd )(在SCROOLLWINDOW函数后)这条语句注释掉,并不影响程序的执行,我查过MSDN的帮助,之所以在SCROOLLWINDOW函数后加上UpdateWindow( hwnd )这条语句是为了滚动整个显示区域,我用单步调试发现,调用SCROOLLWINDOW函数后执行WM_PAINT消息中语句.
      

  3.   

    1、当我单击垂直滚动条时,显示区域中的信息发生卷动,这个卷是由函数SCROLLWINDOW产生的,
       还是由WM_PAINT消息中的TEXTOUT输出的.如果是由函数SCROOLLWINDOW产生的,能否解释一下卷动的过程./////////////////////////卷动是在WM_PAINT里的TEXTOUT输出的,
      

  4.   

    2 SCROOLLWINDOW 能否产生 wm_paint 消息,我到没有仔细研究过,但我记得
      该书中,有个地方讲到了,好像是比较靠前的部分。或者你可以单步 debug
      看一下。3 BeginPaint 和 EndPaint 除了有取得客户区设备描述表外还有,删除无效区
      的作用。
      

  5.   

    会产生WM_PAINT消息..
    不过不建议在OnPaint加太多的绘制,不然闪烁会很厉害的..
      

  6.   

    具体不是很清楚,印象中SCROOLLWINDOW好像有个flags参数来控制是否重绘窗体的吧
      

  7.   

    我将UpdateWindow( hwnd )(在SCROOLLWINDOW函数后)这条语句注释掉,并不影响程序的执行,我查过MSDN的帮助,之所以在SCROOLLWINDOW函数后加上UpdateWindow( hwnd )这条语句是为了滚动整个显示区域,我用单步调试发现,调用SCROOLLWINDOW函数后执行WM_PAINT消息中语句.
      

  8.   

    我想搞清楚,第1个问题即:
    当我单击垂直滚动条时,显示区域中的信息发生卷动,这个卷是由函数SCROLLWINDOW产生的,
    还是由WM_PAINT消息中的TEXTOUT输出的.如果是由函数SCROOLLWINDOW产生的,能否解释一下卷动的过程.
      

  9.   

    你好,我还有二个问题想请教各位大侠:
    1:我在VC中按F10单步调试程序时,按着按着,有时就显示的是程序的汇遍语言,这是怎么回事?
    2:我在调试程序时,比如就拿这个程序来说,我想看一下我单击滚动条后,PAINT消息中代码的执行的情况,我可以在PAINT消息中设置断点或者设置PAINT消息断点,然后单步调试,可是我开始看到的是窗口产生时,产生的PAINT消息的代码执行情况,谁能告诉我怎么可以直接调试到单击滚动条后PAINT消息的执行情况?
      

  10.   

    1 I don't know2 使用条件断点
      

  11.   

    很多情况都会产生 wm_paint 消息,所以调试起来比较困难,一种办法是上面说的
    条件断点,即在达到某种条件时才响应该断点,我不知道 vc 中条件断点如何设,
    一般我是在 ollydbg 和 ida 中用条件断点。
      

  12.   

    ollydbg和ida是什么意思,你一般是用什么开发工具?谢谢!