windows程序设计上4.4.3新的sysmets上的例子的部分源码
大概讲解一下这个例子的用途,使用了setscrollinfo等函数来滚动客户区域. iPaintBeg ,iPaintEnd 分别是是什么意思呢?
为了彻底搞清楚意思,我用日志来记录其只,然后观察推测,(1)当程序执行后,日志里的值为:
iPaintBeg:0--------iPaintEnd:45, iVerPos:0(2)当我点击垂直滚动条的时候,日志的值为:
iPaintBeg:45--------iPaintEnd:46, iVerPos:1
注意45---46,说明循环执行两次!!! 你向下点击一下滚动条,结果执行2次循环
点击一次,其实根本就意味着客户区域里的内容向上移动一行!!! 所有内容都得移动,但是代码跟踪挑时候,发现才执行了2次, 请问如何做到,所有内容都向上移动一行??? 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) ; char buf[100]={0};
sprintf(buf,"iPaintBeg:%d--------iPaintEnd:%d, iVerPos:%d\r\n", iPaintBeg, iPaintEnd,iVertPos);
if(g_File.m_hFile!=INVALID_HANDLE_VALUE)
{
g_File.Write(buf,strlen(buf));
}
for (i = iPaintBeg ; i <= iPaintEnd ; i++)
{
x = cxChar * (1 - iHorzPos) ;
y = cyChar * (i - iVertPos) ;
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, TEXT ("%5d"),
GetSystemMetrics (sysmetrics[i].iIndex))) ;
SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
}
EndPaint (hwnd, &ps) ;
}
return 0 ;
大概讲解一下这个例子的用途,使用了setscrollinfo等函数来滚动客户区域. iPaintBeg ,iPaintEnd 分别是是什么意思呢?
为了彻底搞清楚意思,我用日志来记录其只,然后观察推测,(1)当程序执行后,日志里的值为:
iPaintBeg:0--------iPaintEnd:45, iVerPos:0(2)当我点击垂直滚动条的时候,日志的值为:
iPaintBeg:45--------iPaintEnd:46, iVerPos:1
注意45---46,说明循环执行两次!!! 你向下点击一下滚动条,结果执行2次循环
点击一次,其实根本就意味着客户区域里的内容向上移动一行!!! 所有内容都得移动,但是代码跟踪挑时候,发现才执行了2次, 请问如何做到,所有内容都向上移动一行??? 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) ; char buf[100]={0};
sprintf(buf,"iPaintBeg:%d--------iPaintEnd:%d, iVerPos:%d\r\n", iPaintBeg, iPaintEnd,iVertPos);
if(g_File.m_hFile!=INVALID_HANDLE_VALUE)
{
g_File.Write(buf,strlen(buf));
}
for (i = iPaintBeg ; i <= iPaintEnd ; i++)
{
x = cxChar * (1 - iHorzPos) ;
y = cyChar * (i - iVertPos) ;
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, TEXT ("%5d"),
GetSystemMetrics (sysmetrics[i].iIndex))) ;
SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
}
EndPaint (hwnd, &ps) ;
}
return 0 ;
然后设置setwindoworign
之后刷新
我知道scrollwindow这个函数 msdn有例子。but,,but我问的不是这个,我是在问:你当你点击垂直滚动条的时候, getscrollinfo,setscrollinfo , getscrollinfo等操作设置滚动条,然后调用scrollwindo( 距离) 触发wm_paint开始执行case wm_paint里的代码。我的问题是 wm_paint里的那2个变量到底是什么???为什么只需要执行2次,就可以把所有的内容都向上移动一行?
这个 任务 是 SCrollWindow 完成的,SCrollWindow 对 显示器 直接 操作,操作完成后(非常快),就 产生了 下面 一行 空 的 区域,这个 是 程序 需要 重绘的 区域。注意只有 一行 要 重绘!
所以 如果 控件 有 背景图的 话, 最后那行的背景 要 根据 滚动条 位置来 确定 相应 位置。
http://download.csdn.net/detail/schlafenhamster/5019808
就算scrollwindow帮你完成了这些工作, 可是 for循环为什么执行2次,而不是一次?提供一段代码: case WM_VSCROLL:
// Get all the vertial 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)
{ char buf[100]={0};
sprintf(buf,"ScrollWindow函数中的第3个参数的 iVertPos - si.nPos的值为:%d\r\n",iVertPos - si.nPos); if(g_File.m_hFile!=INVALID_HANDLE_VALUE)
{
g_File.Write(buf,strlen(buf));
}
ScrollWindow (hwnd, 0, cyChar * (iVertPos - si.nPos),
NULL, NULL) ;
UpdateWindow (hwnd) ;
}
return 0 ;日志记录可以显示 ,当你点击向下的滚动条的时候,iVerPos-si.nPos 的值为-1, 则说明待需要滚动的是一样。而for循环2次。 这个逻辑我难以理解
是不是 i <= iPaintEnd 应该是 i < iPaintEnd
这种方法与ScrollWindow是不同的, ScrollWindow是改变窗口到视口坐标的映射, 然后重绘以达到滚动窗口的效果。
就是这么简单, 不要想太复杂了。
最后调ScrollWindow明白吗?
这里你当然可以调用, 但是这个不是必然的, SrollWindow只是一种方法,其原理是改变窗口视口坐标映射, 你也可以自己用SetROP2, SetWindowOrigin, SetViewportOrigin等函数+加上InvalidateRect达到同样效果, 另外你也可以根据滚动条的位置自己重画, 方法是多种多样的, 楼主的例子明显就是重画的。
WM_VSCROLL或WM_HSCROLL 前 后
调用GetWindowOrigin, GetViewportOrigin 看看变了没有