滚动条函数scrollwindow研究

本文主要探讨了Windows API中的ScrollWindow函数,特别是其最后两个参数的含义。通过示例代码和四种不同情况的分析,解释了不同参数设置下滚动区域和剪裁矩形如何影响窗口内容的滚动和重绘。作者强调了滚动操作会触发WM_PAINT消息,但不会更新onpaint中的变量,同时指出ScrollWindow的实现逻辑涉及内存位图和重绘操作。

滚动条函数研究

 

下周工作需要,可能用到滚动条,所以在此先研究一下滚动条相关的知识(可怜我接触UI1年多,尽然没有用过滚动条%>_<%)

 

查了下资料,感觉滚动条用法比较简单,实在没有什么可说的,具体资料网上一查一大堆,这里就不再一一列举了;但是感觉网上困惑最多的也没有给出具体答案的是scrollwindow这个函数的最后两个参数的含义,对于初学者来说,初看也是十分的困惑,所以打算花点时间研究下这个,也算是加深印象,^_^

 

下面先上一段代码,也是从网上查抄来的,此公只有代码,却没有任何说明,似乎是嫌说明太累,^_^ ,那我就顺着他的代码来,并说明实验结果,给大家一个完整的答复,也不枉浪费大家的阅读时间!好,下面开始!

 

代码:(总体而言就是一个cpp文件)

 

 

#include "stdafx.h"

#include <windows.h>

#include <stdio.h>

 

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

 

int WINAPIWinMain(HINSTANCEhInstance,HINSTANCEyY,PSTR szCmdLine,int iCmdShow)

{

   static TCHAR szWndClassName[]=TEXT("yy");

   HWND hwnd;

   MSG msg;

   WNDCLASS wndclass;

 

   wndclass.style=CS_HREDRAW|CS_VREDRAW|CS_OWNDC;

   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= CreateSolidBrush( RGB(212,208,200) ) ;

   wndclass.lpszMenuName=NULL;

   wndclass.lpszClassName=szWndClassName;

 

   if(!RegisterClass(&wndclass)){

      MessageBox(NULL,TEXT("Thisprogram requires Windows NT!"),szWndClassName,MB_ICONERROR);

      return 0;

   }

 

   hwnd=CreateWindow(szWndClassName,

      TEXT("ScrollWindow()º¯Êý"),

      WS_OVERLAPPED   |  WS_CAPTION   |  WS_SYSMENU    |  WS_MINIMIZEBOX,

      CW_USEDEFAULT,

      CW_USEDEFAULT,

      300,

      300,

      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){

   HDC hdc;

   PAINTSTRUCT ps;

   static int temp;

   static RECT rectScroll;

   rectScroll.left=50;

   rectScroll.top=50;

   rectScroll.right=220;

   static RECT clipRectScroll;

 

   static int index = 100;

 

   char textme[MAX_PATH] ={0};

 

   TCHAR text[1000];

 

   static LOGFONT lf;  static HFONT hFont;  static int cxText, cyText ;

 

   switch(message){

  case WM_CREATE:

     //×ÖÌ壺

     lf.lfWeight=FW_LIGHT;

     lf.lfCharSet=GB2312_CHARSET;

     lf.lfHeight=13;

     hFont=CreateFontIndirect(&lf);

 

     hdc=GetDC(hwnd);

     SelectObject (hdc, GetStockObject(NULL_BRUSH));

     SelectObject(hdc,hFont);

     SetBkMode (hdc, TRANSPARENT) ;

 

     TEXTMETRIC tm ;

     GetTextMetrics (hdc,&tm) ;

     cxText=tm.tmAveCharWidth ;cyText=tm.tmHeight ;//+ tm.tmExternalLeading ;

     rectScroll.bottom=rectScroll.top+12*cyText;

    

     clipRectScroll.left=rectScroll.left+2*cxText;

     clipRectScroll.top=rectScroll.top+3*cyText;

     clipRectScroll.right=rectScroll.right-2*cxText;

     clipRectScroll.bottom=rectScroll.top+9*cyText;

    

     ReleaseDC(hwnd,hdc);

     return 0;

 

  case WM_CHAR:

    

     sprintf(textme,"index is :  %d", index);

     MessageBox(NULL, textme, textme, MB_OK);

     break;

 

  case WM_KEYUP:

 

     //ScrollWindow (hwnd, 0, -cyText, NULL, NULL) ;//1

 

     //ScrollWindow (hwnd, 0, -cyText, &rectScroll ,0) ;//2

 

     //ScrollWindow (hwnd, 0, -cyText, &rectScroll,&clipRectScroll) ;//3

 

     ScrollWindow (hwnd,0, -cyText, NULL,&clipRectScroll) ;//4

 

     return 0 ;

 

  case WM_PAINT:

     ++index;

     hdc=BeginPaint(hwnd,&ps);

     static int tt,xx,yy,zz;//ScrollWindowµÄÈ·²úÉúÁËWM_PAINTÏûÏ¢£¡

     //if(temp<3)

     //{

     TextOut(hdc,0,0,text,wsprintf (text, TEXT("BOOL ScrollWindow(     //tt:%d´Î"),++tt)  );

     TextOut(hdc,0,cyText,text,wsprintf (text, TEXT (" HWND hWnd,int XAmount,intYAmount," )   )  );

     TextOut(hdc,0,2*cyText,text,wsprintf (text, TEXT (" const RECT *lpRect,const RECT*lpClipRect" )   )  );

     TextOut(hdc,0,3*cyText,text,wsprintf (text, TEXT (");" )   )  );

     //temp++;

     //}

 

     Rectangle(hdc,rectScroll.left-1 ,rectScroll.top-1,rectScroll.right+1,rectScroll.bottom+1);

 

     Rectangle(hdc,clipRectScroll.left-1,clipRectScroll.top-1,clipRectScroll.right+1,clipRectScroll.bottom+1);

 

     DrawText (hdc, text,

        wsprintf (text, TEXT("111111111111%d\n222222222222222222222%d\n333333333333333333333%d\n444444444444444444444%d\n555555555555555555555555\n666666666666666666666666\n777777777777777777777777\n888888888888888888888888\n999999999999999999999999\n1010 10 10 10 10 10 10 \n11 11 11 11 11 11 xx:%d´Î\n12 12 12 12 12 12 yy:%d´Î ²âÊÔÈý:lpRectÊÇÍâ¿ò£¬lpClipRectÊÇÍâ¿ò ÈÎÒâ¼ü²âÊÔ¹ö¶¯Ð§¹û  zz:%d´Î"),index,index, index,index, ++xx,++yy,++zz),

       &rectScroll,DT_NOCLIP);

 

     EndPaint(hwnd,&ps);

     return 0;

 

  case WM_DESTROY:

     PostQuitMessage(0);

     DeleteObject (hFont);

     return 0;

   }

 

   return DefWindowProc(hwnd,message,wParam, lParam) ;

}

 

 

程序运行如下图:

 

代码分析:

 

   关键代码如下:

  case WM_KEYUP:

 

     //ScrollWindow (hwnd, 0, -cyText, NULL, NULL) ;//1

 

     //ScrollWindow (hwnd, 0, -cyText, &rectScroll ,0) ;//2

 

     //ScrollWindow (hwnd, 0, -cyText, &rectScroll,&clipRectScroll) ;//3

 

     ScrollWindow (hwnd,0, -cyText, NULL,&clipRectScroll) ;//4

 

这里一共做了四中情况讨论,我分别按照自己的实验结果给出相关的解释和说明:

主要介绍 最后两个参数  其他参数不做说明,请查阅msdn或者baidu

 

 

条件一:

 

ScrollWindow (hwnd, 0, -cyText, NULL, NULL) ;//1

这个似乎没有什么好说的,大多数运行都是传空  这样的话会滚动整个hwnd客户区,对的,他不会滚动标题栏和菜单 以及状态栏,只会滚动改窗口的客户区,至于怎么找到一个overlapped窗口的客户区,那就是window内部的事情了,到此为止,不在深入。

 

值得说明的是:滚动窗口会收到一个WM_PAINT消息,但是并不会重新绘制一次,从运行结果可以看出来并没有更新程序中onpaint的index变量,但是确实是进入onpaint了,在此,给出一种猜测的实现方式,此方式也适用于后续机种情况:

Scrollwindow的实现逻辑是:现将要滚动的区域保存成一幅内存位图(或者干脆创建内存兼容dc),然后滚动当前窗口到指定的位置,下来再将滚动后新生成的区域(也就是滚出来的区域)发送一个onpaint消息,脏矩形为新生成的区域。

 

条件二:

ScrollWindow (hwnd,0, -cyText, &rectScroll,0) ;//2

 

这里有了rectscroll矩形参数,msdn上解释如下:

lpRect

[in] Pointerto the RECT structure specifying the portion of the client area to be scrolled.If this parameter is NULL, the entire client area is scrolled.

 

大致含义就是指定客户区中将被滚动的区域。

 

带上这个参数之后,就可以看到:只有外面那个大框框里面的东西被滚动了,并且滚动后会超出该框框区域,滚动步骤是:保存内存位图,滚动之,然后向新滚出来的区域发送onpaint消息,脏矩形为该新滚出来的矩形。

 

条件三:

ScrollWindow (hwnd,0, -cyText, &rectScroll,&clipRectScroll) ;//3

 

这里增加了两个参数,即剪裁矩形

lpClipRect

[in] Pointerto the RECT structure containing the coordinates of the clippingrectangle. Only device bits within the clipping rectangle are affected. Bitsscrolled from the outside of the rectangle to the inside are painted; bitsscrolled from the inside of the rectangle to the outside are not painted.

 

这里的剪裁矩形应该和windows onpaint的里面的剪裁矩形和raw区域含义相同,具体请查阅相关图形书籍,在此不详述。大体含义就是  只会更新剪裁区域里面的内容。

 

但是注意:这个和条件二的不同之处在于:条件二会滚动出这个矩形边界,但是条件三不会!!! 这是因为设置了剪裁矩形以后,onpaint更新的区域就是脏矩形和剪裁矩形的交集了,所以还是更新新滚出来的区域,并且滚动后不会超出小矩形边界!!

 

条件四:

ScrollWindow (hwnd,0, -cyText, NULL,&clipRectScroll) ;//4

 

理解了上面几个老大难后,理解4就容易的多了!

 

只设置了剪裁矩形,所以只会在那个小框框里面更新内容!

 

 

最后在做点说明:这个实例中的剪裁矩形和第三个参数的lprect是包含关系,lprect包含了剪裁矩形(大家可以试验一下当剪裁矩形和lprect矩形只相交了一点的情况),最后更新的是剪裁区域里面的内容!那么大家会问:既然只更新剪裁区域里面的内容,为何还要lprect这个外围矩形呢?是不是这个参数就没有用了呢?

 

其实不是,滚动会滚动lprect里面的内容,但是更新只更新剪裁区域里面的内容,这样的话,就给大家提供了方便,可以用两个矩形来控制要滚动的区域!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值