精华内容
下载资源
问答
  • Windows滚动条

    千次阅读 2015-12-24 12:05:27
    前面的窗口滚动条只能出现在父窗口的固定地方,而滚动条控件能出现在父窗口的任何地方。创建窗口滚动条控件:使用预定义的滚动条类(scrollbar),和两种滚动条样式SBS_VERT和SBS_HORZ。 例如:case WM_CREATE: ...

    前面的窗口滚动条只能出现在父窗口的固定地方,而滚动条控件能出现在父窗口的任何地方。

    创建窗口滚动条控件:使用预定义的滚动条类(scrollbar),和两种滚动条样式SBS_VERT和SBS_HORZ。
    例如:

    case WM_CREATE:
    
            hWndScroll = CreateWindow(L"scrollbar", L"", WS_CHILD | WS_VISIBLE | SBS_VERT, 100, 100, 50, 200, hwnd, nullptr, hInst, 0);
            return 0;

    这个滚动条的大小由50 200控制,出现的位置由100 100控制.
    滚动条控件的尺寸不是固定的,而是可以任意的
    如图:

    滚动条控件不发送WM_COMMAND消息,而直接发送WM_VSCROLL和WM_HSCROLL消息,而区分窗口滚动条和滚动条控件 的参数是lParam,如果lParam==0就是窗口滚动条,如果等于滚动条窗口句柄就是滚动条控件
    例如:

    case WM_VSCROLL:
    
            if (lParam == 0)
                MessageBox(nullptr,L"滑动了窗口滚动条",L"",0);
            else               
                MessageBox(nullptr, L"滑动了滚动条控件", L"", 0);
            break;

    如图:

    若想创建和窗口滚动条一样的尺寸,可以用如下两个函数获取滚动条大小

     //获取水平滚动条的高度
       GetSystemMetrics(SM_CYHSCROLL);
       //获取垂直滚动条的宽度
       GetSystemMetrics(SM_CXVSCROLL);

    例如:

    case WM_CREATE:
    
            hWndScroll = CreateWindow(L"scrollbar", L"", WS_CHILD | WS_VISIBLE | SBS_VERT, 100, 100
                , GetSystemMetrics(SM_CXVSCROLL), 200, hwnd, (HMENU)1, hInst, 0);
            return 0;

    如图:

    可以用与窗口滚动条同样的函数来设置滚动条控件的范围和位置,区别是SB_VERT、SB_HORZ改为SB_CTL
    例如:

    case WM_CREATE:
    
            hWndScroll = CreateWindow(L"scrollbar", L"", WS_CHILD|WS_VISIBLE|SBS_VERT,100,100,GetSystemMetrics(SM_CXVSCROLL), 200, hwnd, (HMENU)1, hInst, 0);
            //设置范围
            SetScrollRange(hWndScroll, SB_CTL, 0, 200, TRUE);
            //设置滑块初始位置
            SetScrollPos(hWndScroll, SB_CTL, ipos, TRUE);
            break;
    case WM_VSCROLL:
    
            switch (LOWORD(wParam))
            {
            case SB_LINEUP:
                ipos -= 1;
                break;
            case SB_LINEDOWN:
                ipos += 1;
                break;
            //case SB_THUMBPOSITION:
            case SB_THUMBTRACK:
                ipos = HIWORD(wParam);
            default:
                break;
            }
            SetScrollPos(hWndScroll, SB_CTL, ipos, TRUE);
            break;
    
    

    控件的句柄一定要是静态或者全局变量,否则以创建窗口后控件句柄就又被初始化了。

    展开全文
  • windows滚动条

    千次阅读 2012-03-28 17:40:45
    今天自己写了《windows程序设计》184页的用键盘控制滚动条显示程序,对滚动条显示有点感悟,留个纪念! 代码如下: #include #include #include "SYSMETS.h" LRESULT CALLBACK WndProc(HWND hwnd,UINT ...

    今天自己写了《windows程序设计》184页的用键盘控制滚动条显示程序,对滚动条显示有点感悟,留个纪念!

    代码如下:

    #include <Windows.h>
    #include <math.h>
    #include "SYSMETS.h"
    
    LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam);
    
    int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
    {
    	static TCHAR szAppName[]=TEXT("First Program");
    	MSG msg;
    	HWND hwnd;
    	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(hwnd,TEXT("Error exists!"),TEXT("Error!"),MB_ICONERROR);
    		return 0;
    	}
    
    	hwnd=CreateWindow(szAppName,TEXT("Hello World!"),WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_VSCROLL,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
    		CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
    
    	ShowWindow(hwnd,iCmdShow);
    	UpdateWindow(hwnd);
    
    	while (GetMessage(&msg,hwnd,0,0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    
    	return msg.wParam;
    }
    
    LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
    {
    	static int cxChar,cyChar,cxCaps,cxClient,cyClient;
    	int iVertPos,x,y,i,iPaintBeg,iPaintEnd;
    	TCHAR szBuffer[20];
    	HDC hdc;
    	PAINTSTRUCT ps;
    	TEXTMETRIC tm;
    	SCROLLINFO si;
    
    	switch(message)
    	{
    	case WM_CREATE:
    		hdc=GetDC(hwnd);
    
    		GetTextMetrics(hdc,&tm);
    		cxChar=tm.tmAveCharWidth;
    		cyChar=tm.tmHeight+tm.tmExternalLeading;
    		cxCaps=(tm.tmPitchAndFamily&1?3:2)*cxChar/2;
    		ReleaseDC(hwnd,hdc);
    		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);
    		return 0;
    
    	case WM_VSCROLL:
    		si.cbSize=sizeof(si);
    		si.fMask=SIF_ALL;
    		GetScrollInfo(hwnd,SB_VERT,&si);
    		iVertPos=si.nPos;
    
    		switch(LOWORD(wParam))
    		{
    		case SB_TOP:
    			si.nPos=si.nMin;
    			break;
    
    		case SB_BOTTOM:
    			si.nPos=si.nMax;
    			break;
    
    		case SB_PAGEUP:
    			si.nPos-=si.nPage;
    			break;
    
    		case SB_PAGEDOWN:
    			si.nPos+=si.nPage;
    			break;
    
    		case SB_LINEUP:
    			si.nPos-=1;
    			break;
    
    		case SB_LINEDOWN:
    			si.nPos+=1;
    			break;
    
    		case SB_THUMBTRACK:
    			si.nPos=si.nTrackPos;
    			break;
    
    		default:
    			break;
    		}
    		si.cbSize=sizeof(si);
    		si.fMask=SIF_POS;
    		SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
    		GetScrollInfo(hwnd,SB_VERT,&si);
    		if (si.nPos!=iVertPos)
    		{
    			ScrollWindow(hwnd,0,cyChar*(iVertPos-si.nPos),NULL,NULL);
    			UpdateWindow(hwnd);
    		}
    		return 0;
    
    	case WM_KEYDOWN:
    		switch(wParam)
    		{
    		case VK_UP:
    			SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0);
    			break;
    
    		case VK_DOWN:
    			SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0);
    			break;
    
    		case VK_PRIOR:
    			SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0);
    			break;
    
    		case VK_NEXT:
    			SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0);
    			break;
    
    		default:
    			break;
    		}
    		return 0; 
         //关键代码
    	case WM_PAINT:
    		si.cbSize=sizeof(si);
    		si.fMask=SIF_ALL;
    		GetScrollInfo(hwnd,SB_VERT,&si);
    		iVertPos=si.nPos;
    	   
    		hdc=BeginPaint(hwnd,&ps);
    		iPaintBeg=max(0,si.nPos+ps.rcPaint.top/cyChar);
    		iPaintEnd=min(si.nMax,si.nPos+ps.rcPaint.bottom/cyChar);
    
    		for (i=iPaintBeg;i<=iPaintEnd;i++)
    		{
    			y=cyChar*(i-iVertPos);
    
    			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_TOP|TA_RIGHT);
    			TextOut(hdc,60*cxCaps,y,szBuffer,wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].Index)));
    			SetTextAlign(hdc,TA_LEFT|TA_TOP);
    		}
    		EndPaint(hwnd,&ps);
    		return 0;
    
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    	}
    
    	return DefWindowProc(hwnd,message,wParam,lParam);
    }
    

    原来我老是有个疑问:

    1、iPaintBeg=max(0,si.nPos+ps.rcPaint.top/cyChar);
          iPaintEnd=min(si.nMax,si.nPos+ps.rcPaint.bottom/cyChar);

          这两句是干嘛用的?

    2、为什么是for (i=iPaintBeg;i<=iPaintEnd;i++)这样循环?

    3、y=cyChar*(i-iVertPos);

         为什么是i-iVertPos?


    今天调试了一下,颇有感悟!

    调试时滚动条下拉了一行!


    首先给出调试时一些参数,是我写的一张图:



    得出了一些结论:

    1、下拉滚动条时,只更新时新出现的客户区,这个矩形的具体参数存数在ps.rcPaint中。

    更新起点iPaintBeg是需更新矩形的顶部所在的行数,iPaintEnd是底部所在的行数。即图中新出现一行的顶部和底部。

    2、for循环就是输出这些新出现的文本

    3、i-iVerPos就是以新客户区的顶部为起点更新客户区

    展开全文
  • Windows滚动条

    千次阅读 2010-09-25 12:06:00
    //这是我初次编写windows应用程序(窗口),按理说是按书本上的抄录下来的,呵呵 //下面我把代码详细解释一下   /**********************一些字符前缀解释**********************************...

    //这是我初次编写windows应用程序(窗口),按理说是按书本上的抄录下来的,呵呵

    //下面我把代码详细解释一下

     

    /**********************一些字符前缀解释****************************************************/

    /*cs_:class(类风格选项)WM_:widows message(窗口消息)CW_:creat widows(绘制窗口)

    DT_:draw text(绘制文本选项)

    RECT:rectangle(巨型)instance:实例 h:handle(句柄,行为,把手) vertical:垂直

    horizontal:水平的

    */

     

    //此程序中在窗口中添加了滚动条内容

    #include <windows.h>

    #include "SYSMETS.h"

     

    LRESULT CALLBACK WndProc(

      HWND hwnd,              // handle to window

      UINT Msg,               // message

      WPARAM wParam,          // first message parameter

      LPARAM lParam           // second message parameter

    );

     

    int WINAPI WinMain(

      HINSTANCE hInstance,      // handle to current instance

      HINSTANCE hPrevInstance,  // handle to previous instance

      LPSTR lpCmdLine,          // command line

      int iCmdShow              // show state

    )

    {

          static TCHAR szAppName[]=TEXT("SysMets");

          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_ERROR);  //窗口左上角是一个叉的图标

          wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);  //光标选项(也就是鼠标)

          wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);  //客户区背景

          wndclass.lpszMenuName=NULL;  //vc中,有菜单,这个程序,没有菜单,所以为NULL

          wndclass.lpszClassName=szAppName;   //这个类的名字

     

          if(!RegisterClass(&wndclass))   //注册窗口类

          {

               MessageBox(NULL,TEXT("This program requires Windows NT!"),

                     szAppName,MB_ICONERROR);

               return 0;

          }

     

          HWND hwnd;  //定义一个窗口句柄,开始创建窗口

          hwnd=CreateWindow(                     //创建窗口

            szAppName,  // registered class name

            TEXT("The Hello Program"), // window name

          /*********************WS_OVERLAPPEDWINDOW 重叠式窗口****************************************************/

            //创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOXWS_MAXIMIZEBOX

            /*WS_OVERLAPPEDWINDOW*/WS_MINIMIZEBOX|WS_OVERLAPPED|WS_SYSMENU|WS_THICKFRAME|WS_MAXIMIZEBOX|WS_VSCROLL|WS_HSCROLL,//增加垂直滚动条和水平滚动条  

            CW_USEDEFAULT,                // horizontal position of window

            CW_USEDEFAULT,                // vertical position of window

            CW_USEDEFAULT,           // window width

            CW_USEDEFAULT,          // window height

            NULL,      // handle to parent or owner window

            NULL,          // menu handle or child identifier

            hInstance,  // handle to application instance

            NULL       // window-creation data

          );

     

          ShowWindow(hwnd,iCmdShow);    //显示窗口

          UpdateWindow(hwnd);           //更新窗口

          while(GetMessage(&msg,NULL,0,0)) //消息循环(这一步是从消息队列中得到消息)  

          {

               TranslateMessage(&msg);  //消息转换

               DispatchMessage(&msg);  //消息映射(如果在MFC中,这是一个非常难的难点)

          }

          return msg.lParam;  //如果得到一个WM_QUIT消息,退出while()循环,程序返回结束

    }

     

    //窗口过程函数

    LRESULT CALLBACK WndProc(   

      HWND hwnd,              // handle to window

      UINT msg,               // message

      WPARAM wParam,          // first message parameter

      LPARAM lParam           // second message parameter

    )

    {

          static int cxChar,cxCaps,cyChar,cyClient,iVscrollPos;

          int i,y;

          TCHAR szBuffer[10];

          TEXTMETRIC tm;

     

          HDC hdc;

          PAINTSTRUCT ps;

    //   RECT rect;

          switch(msg)

          {

     

               case WM_CREATE:  //创建窗口时由windows发送给窗口过程的,此时消息并没有进入消息队列

                     //   PlaySound(TEXT("hello,war"),NULL,SND_FILENAME|SND_ASYNC);

                     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);   //设置垂直滚动条的范围(自我感觉一下两句没有用处)

               //   SetScrollPos(hwnd,SB_VERT,iVscrollPos,TRUE);   //设置垂直滚动条的位置

                     return 0;

     

               case WM_SIZE:  //窗口大小改变时,产生的消息(当然,窗口第一次显示时,也是要产生这个消息的,接下来必然跟着WM_PAINT消息)

                     cyClient=HIWORD(lParam);  //lParam 低字节用于客户区的垂直大小

                     break;

     

               case WM_VSCROLL: //滚动条消息

                     switch(LOWORD(wParam))//wParam的低字节指出了鼠标对滚动条进行的操作

                     {

                     case SB_LINEUP:

                          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_THUMBTRACK/*SB_THUMBPOSITION*/:   //释放滚动条/按下滚动条

                          iVscrollPos=HIWORD(wParam);    //高字节附加参数,此时指出位置变化为释放后的/按下滚动条

                          break;

                     default:

                          break;

                     }

                     iVscrollPos=max(0,min(iVscrollPos,NUMLINES-1));  //使滚动条为位置不至于超出范围

                     if(iVscrollPos !=GetScrollPos(hwnd,SB_VERT))  

                     {

                          SetScrollPos(hwnd,SB_VERT,iVscrollPos,TRUE);   //重新设置滚动条位置

                          InvalidateRect(hwnd,NULL,TRUE);  //是客户区无效

                     //   UpdateWindow(hwnd);

                     }

                     return 0;

               case WM_PAINT: //此消息也不是从消息队列中获得的,也是widows发送的

                     hdc=BeginPaint(hwnd,&ps);  //返回的是一个“设备描述表句柄”

                     for(i=0;i<NUMLINES;i++)

                     {

                           y=cyChar*(i-iVscrollPos);

                          //y=cyChar*i;

                          TextOut(hdc,0,y,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));  //显示第一列

     

                          TextOut(hdc,22*cxChar,y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szLabel));   //显示第一列

                         

                          SetTextAlign(hdc,TA_RIGHT|TA_TOP); //设置为对齐方式(右上对齐)

     

    TextOut(hdc,22*cxChar+40*cxChar,y,szBuffer,wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].ilndex)));//显示第三列

     

                          SetTextAlign(hdc,TA_LEFT|TA_TOP);  //设置为对齐方式(重新设置为普通方式对齐)

                     }

               /*   GetClientRect(hwnd,&rect);  //通过这个函数可以获得变化后的窗口大小(我也不知道怎么实现的)

                     DrawText(

                       hdc,          // handle to DC

                       TEXT("Hello,Windows xp!"), // text to draw

                       -1,       // text length

                       &rect,    // formatting dimensions

                       DT_SINGLELINE|DT_CENTER|DT_VCENTER     // text-drawing options

                          );*/

                     EndPaint(hwnd,&ps);

                     return 0;

               case WM_DESTROY:

                     PostQuitMessage(0);

                     return 0;

          }

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

    }

    /*分析WM_PAINT消息:如果用户最终单击了关闭按钮,DefWindowProc处理键盘和鼠标输入,检测到close选项后,

    给窗口过程发送一个WM_SYSCOMMAND消息,WndProc将这个消息传给DefWindowProc,此函数给窗口过程发送一个WM_CLOSE消息

    来响应之,DestroyWindow 导致Windows给窗口过程发送一个WM_DESTROY消息。WndProc再调用PostQuitMessage,将一个

     

    WM_QUIT

    消息放入消息队列中,以此来响应此消息,这个消息导致WinMain中的消息循环终止,循环结束。*/

     

    //消息分为进队消息和不进队消息,从上面可以看出,在窗口没有创建以前,WM_CREATEWM_PAINT

    //都是不进队列的,直接由windows发送,不管我们的事

    展开全文
  • Windows程序设计--设置滚动条详解一

    千次阅读 2015-12-11 16:18:02
    先讲怎么用普通的方法设置滚动条。重点是设置滚动条而不是文本输出,所以示例程序的文本很简洁。说到设置滚动条我们就会想到三点: 1.用鼠标拖动滑块使客户区内容重绘 2.用键盘控制滑块移动 3.用鼠标滚轮控制滑块...

    先讲怎么用普通的方法设置滚动条。重点是设置滚动条而不是文本输出,所以示例程序的文本很简洁。

    说到设置滚动条我们就会想到三点:
    1.用鼠标拖动滑块使客户区内容重绘
    2.用键盘控制滑块移动
    3.用鼠标滚轮控制滑块移动

    那么我们就把这三个功能都给用上

    用到的函数有以下几个:

    //设置滚动条范围
    //返回TRUE表示成功,FALSE表示失败
    BOOL SetScrollRange( 
      HWND hWnd, //窗口句柄
      int nBar,  //滚动条类型
      int nMinPos, //滚动条的最小位置
      int nMaxPos, //滚动条的最大位置
      BOOL bRedraw //重绘标志
    ); 
    //滚动条位置
    //0表示失败,返回先前位置的值表示成功
    int SetScrollPos( 
      HWND hWnd, //窗口句柄
      int nBar, //滚动条类型
      int nPos, //滚动条新位置
      BOOL bRedraw // 重绘标志
    ); 
    //向窗口过程发送消息              
    LRESULT SendMessage(
      HWND hWnd,   //接收消息的窗口句柄
      UINT Msg,    //发送的消息
      WPARAM wParam, //附加消息
      LPARAM lParam  //附加消息
    ); 
    
    //该函数查询或设置系统级参数。该函数也可以在设置参数中更新用户配置文件。          
    BOOL SystemParametersInfo( 
      UINT uiAction,  // 该参数指定要查询或设置的系统级参数,MSDN有详细介绍
      UINT uiParam,  //与查询或设置的系统参数有关。
      PVOID pvParam, //与查询或设置的系统参数有关
      UINT fWinIni  //如果设置系统参数,则它用来指定是否更新用户配置文件(Profile)
    );

    知道并懂得怎么用这些函数后就可以开始设置我们的滚动条了。一般滚动条分为水平滚动条和垂直滚动条。所以一般我们有一下几个步骤来设置滚动条:
    1.向需要设置滚动条的窗口添加滚动条风格(WS_HSCROLL|WS_VSCROLL)这个是最主要的,因为你不添加这个风格无论你在窗口过程写多少代码都是无用功。
    2.在WM_CREATE消息中获取当前字体大小。

    GetTextMetrics(hdc, &tm);
    cxChar = tm.tmAveCharWidth;
    cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
    cyChar = tm.tmHeight + tm.tmExternalLeading;

    3.在WM_SIZE消息中获取客户区宽度和高度:

    cxClient=LOWORD(lParam);//宽度
    cyClient=HIWORD(lParam);//高度

    4.在WM_消息中设置滚动条范围和初始位置
    SetScrollRange
    SetScrollPos
    5.在WM_VSCROLL和WM_HSCROLL消息中设置新的滑块位置
    6.在WM_KETDOWN消息中利用SendMessage发送消息给WM_VSCROLL和WM_HSCROLL以设置新的滑块位置
    7.滚轮滑动利用SendMessage发送消息给WM_VSCROLL和WM_HSCROLL以设置新的滑块位置
    8.在WM_PAINT消息中显示滚动滑块后的内容
    基本就以上8点就可以设置滚动条了。细节更改可以自己研究.

    设置滚动条代码如下:

    
    #include <windows.h>
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    //全局变量存储错误信息
    DWORD dwError = 0;
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT("Scroll");
        HWND         hwnd=nullptr;
        MSG          msg = {0};
        WNDCLASS     wndclass = {0};
        //创建窗口类
        wndclass.style = CS_HREDRAW | CS_VREDRAW;
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
        wndclass.hCursor = LoadCursor(nullptr, IDC_ARROW);
        wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndclass.lpszMenuName = nullptr;
        wndclass.lpszClassName = szAppName;
        //注册窗口类
        if (!RegisterClass(&wndclass))
        {
            MessageBox(nullptr, TEXT("This program requires Windows NT!"),
                szAppName, MB_ICONERROR);
            return 0;
        }
        //创建窗口
        hwnd = CreateWindow(szAppName, TEXT("ScrollDemo"),
            WS_OVERLAPPEDWINDOW|WS_HSCROLL|WS_VSCROLL,//添加滚动条风格
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            nullptr, nullptr, hInstance, nullptr);
        if (!hwnd)
        { 
            dwError = GetLastError();
            return 0;
        }
        //显示窗口
        ShowWindow(hwnd, iCmdShow);
        //更新窗口
        UpdateWindow(hwnd);
        //获取队列中的消息
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    }
    
    
    
    //窗口过程函数
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        //字体的宽度,高度,cxCaps是宽字符的宽度
        static int  cxChar = 0, cxCaps = 0, cyChar = 0;
        //滚动条的垂直位置和水平位置
        static int iVertPos = 0, iHorzPos = 0;
        //获取当前客户区可容纳的行数和列数
        static int cxColumn = 0, cyLine = 0;
        //客户区宽度和高度
        static int cxClient = 0, cyClient = 0;
        //鼠标滑动信息
        static int  iDeltaPerLine = 0, iAccumDelta = 0;
        ULONG       ulScrollLines = 0;
        int i = 0, temp = 0, ix = 0, iy = 0;
        //设备环境句柄
        HDC         hdc = nullptr;
        //绘图信息结构
        PAINTSTRUCT ps = { 0 };
        //字体信息结构
        TEXTMETRIC  tm = { 0 };
    
        switch (message)
        {
        case WM_CREATE:
            hdc = GetDC(hwnd);
            //获取字体信息,一般系统默认
            GetTextMetrics(hdc, &tm);
            //字符宽度
            cxChar = tm.tmAveCharWidth;
            //判断是否是宽字符,宽字符就是1.5cxChar
            cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
            //字符高度
            cyChar = tm.tmHeight + tm.tmExternalLeading;
    
            ReleaseDC(hwnd, hdc);
        case WM_SETTINGCHANGE:
            //SPI_GETWHEELSCROLLLINES:用于Windows NT 4.0及以后版本、
            //Windows 98。当前轨迹球转动时,获取滚动的行数。参数pvParam
            //必须指向UINT类型变量以接收行数。缺省值是3。
            if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0))
            {
                dwError = GetLastError();
                break;
            }
    
            // 增量数值用WHEEL_DELTA来标识,它等于120
    
            if (ulScrollLines)//每滚动一行的增量是40
                iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
            else
                iDeltaPerLine = 0;
    
            return 0;
    
        case WM_SIZE:
            //获取客户区宽度和高度,每当你改变窗口大小的时候它
            //都会发生改变。
            cxClient = LOWORD(lParam);
            cyClient = HIWORD(lParam);
            //获取当前客户区可容纳的列数
            cxColumn = cxClient / cxChar;
            //获取当前客户区可容纳的行数
            cyLine = cyClient / cyChar;
    
            //设置垂直滚动条范围
            if (!SetScrollRange(hwnd, SB_VERT, 0, cyClient / cyChar, FALSE))
            {
                dwError = GetLastError();
                break;
            }
            //设置垂直滚动条初始位置
            SetScrollPos(hwnd, SB_VERT, iVertPos, TRUE);
    
            //设置水平滚动条范围 
            if (!SetScrollRange(hwnd, SB_HORZ, 0, cxClient / cxChar, TRUE))
            {
                dwError = GetLastError();
                break;
            }
            //设置垂直滚动条初始位置   
            SetScrollPos(hwnd, SB_HORZ, iHorzPos, TRUE);
    
            return 0;
    
          //垂直滚动条消息
        case WM_VSCROLL:
    
            //记录未改变时的滑块位置
            temp = iVertPos;
            //接收到用户拖动滑块消息
            switch (LOWORD(wParam))
            {
                //向上移动一个单位
            case SB_LINEUP:
                iVertPos -= 1;
                break;
                //想下移动一个单位
            case SB_LINEDOWN:
                iVertPos += 1;
                break;
                //翻上一页
            case SB_PAGEUP:
                iVertPos -= cyClient / cyChar;
                break;
                //翻下一页
            case SB_PAGEDOWN:
                iVertPos += cyClient / cyChar;
                break;
            case SB_TOP:
                iVertPos = 0;
                break;
            case SB_BOTTOM:
                iVertPos = cyClient / cyChar;
                break;
            case SB_THUMBTRACK:
                iVertPos = HIWORD(wParam);
                break;
            default:
                break;
            }
            //防止范围超出
            iVertPos = max(0, min(iVertPos, cyClient / cyChar));
            //当滑块改变的时候重新显示它
            if (temp != iVertPos)
            {
                //设置新的滑块位置
                SetScrollPos(hwnd, SB_VERT, iVertPos, TRUE);
                //使客户区无效,以便重绘它
                InvalidateRect(hwnd, nullptr, TRUE);
            }
    
    
            return 0;
            //水平滚动条消息
        case WM_HSCROLL:
    
            //记录未改变时的滑块位置
            temp = iHorzPos;
            //接收到用户拖动滑块消息
            switch (LOWORD(wParam))
            {
                //向左移动一个单位
            case SB_LINELEFT:
                iHorzPos -= 1;
                break;
                //想下移动一个单位
            case SB_LINERIGHT:
                iHorzPos += 1;
                break;
                //翻上一页
            case SB_PAGELEFT:
                iHorzPos -= cyClient / cyChar;
                break;
                //翻下一页
            case SB_PAGERIGHT:
                iHorzPos += cyClient / cyChar;
                break;
            case SB_THUMBTRACK:
                iHorzPos = HIWORD(wParam);
                break;
            default:
                break;
            }
            //防止范围超出
            iHorzPos = max(0, min(iHorzPos, cxClient / cxChar));
            //当滑块改变的时候重新显示它
            if (temp != iHorzPos)
            { 
               //设置新的滑块位置
                SetScrollPos(hwnd, SB_HORZ, iHorzPos, TRUE);
                //使客户区无效,以便于重绘
                InvalidateRect(hwnd, nullptr, TRUE);
            }
    
            return 0;
    
            //键盘消息
        case WM_KEYDOWN:
    
            //如果有按下方向键
            switch (LOWORD(wParam))
            {
                //如果按下方向键上
            case VK_UP:
                //想窗口过程发送消息
                SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
                break;
            case VK_DOWN:
                SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
                break;
            case VK_LEFT:
                SendMessage(hwnd, WM_HSCROLL, SB_LINELEFT, 0);
                break;
            case VK_RIGHT:
                SendMessage(hwnd, WM_HSCROLL, SB_LINERIGHT, 0);
                break;
                //PageUp
            case VK_PRIOR:
                SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);
                break;
                //PageDown
            case VK_NEXT:
                SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
                //Bottom
            case VK_END:
                SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, 0);
                break;
            case VK_HOME:
                SendMessage(hwnd, WM_VSCROLL, SB_TOP, 0);
                break;
            default:
                break;
            }
            return 0;
    
            //鼠标滚轮消息
        case WM_MOUSEWHEEL:
            //如果增量等于0就是没有滚动就退出
            if (iDeltaPerLine == 0)
                break;
    
            iAccumDelta += (short)HIWORD(wParam);     // 120 or -120
    
            while (iAccumDelta >= iDeltaPerLine)
            {
                SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
                iAccumDelta -= iDeltaPerLine;
            }
    
            while (iAccumDelta <= -iDeltaPerLine)
            {
                SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
                iAccumDelta += iDeltaPerLine;
            }
    
            return 0;
            //重绘
        case WM_PAINT:
    
            hdc = BeginPaint(hwnd, &ps);
    
            for (;i < cyLine;i++)
            {
                //当滑块位置改变时,输出的起始位置也随之改变
                //其原理就是把不需要输出的输出到屏幕外面
                ix = cxChar*(1 - iHorzPos);
                iy = cyChar * (i - iVertPos);
                TextOutW(hdc, ix, iy, L"一二三四五六", wcslen(L"一二三四五六"));
            }
    
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    代码中已经有很详细的注释了,所以这里大概再理清一下代码就行了。
    1.
    当我们创建窗口的时候会先触发WM_CREATE消息,这时,字体大小信息被获取到了,因为没有这个字体大小的信息,你根本不懂一个客户区可以容纳的行数和列数。
    2.
    接着会触发WM_SIZE消息,我们的客户区大小也能获取到了,然后就可以设置滚动条的范围和初始位置了。
    3.
    将滚动条初始化后就会触发WM_PAINT消息,文本和滚动条就会在窗口显示了。但是WM_HSCROLL和WM_VSCROLL这两个消息还没被触发,因为你并没有移动滑块。
    4.
    当你移动滑块后就会触发对应的水平或垂直滚动条消息,接着滑块的位置就会在里面被改变。
    5.最后就会被重绘在客户区中。

    键盘消息和鼠标滚轮消息对滑块的改变是通过SendMessage函数发送对应的消息到滚动条消息中,这样就可以达到键盘鼠标移动滑块的效果了。

    滚动条消息如下:

    #define SB_LINEUP       0
    
    #define SB_LINELEFT           0
    
    #define SB_LINEDOWN           1
    
    #define SB_LINERIGHT          1
    
    #define SB_PAGEUP         2
    
    #define SB_PAGELEFT           2
    
    #define SB_PAGEDOWN           3
    
    #define SB_PAGERIGHT          3
    
    #define SB_THUMBPOSITION   4
    
    #define SB_THUMBTRACK         5
    
    #define SB_TOP                6
    
    #define SB_LEFT           6
    
    #define SB_BOTTOM        7
    
    #define SB_RIGHT          7
    
    #define SB_ENDSCROLL          8

    其中的SB_THUMBTRACK 和SB_THUMBPOSITION只能处理一个,前者是设置滑块及时显示,后者是设置滑块被释放后显示.

    WM_VSCROLL和WM_HSCROLL中的wParam和lParam参数:

    wParam消息参数被分为一个低字组和一个高字组。wParam的低字组是一个数值,它指出了鼠标对滚动条进行的操作。

    而一般lParam在控件窗口中才有意义,所以这里不必管它.

    关于虚拟键消息可以百度。这里不详细讲。滚动条的设置还可以利用一个滚动条信息结构和两个函数。这种方法是比较常用的,下次会详细讲解它。

    展开全文
  • 用以下一个结构和三个函数就能设置滚动条了 1.滚动条信息结构//SetScrollInfo函数设置这个结构的信息 //GetScrollInfo函数返回这个结构的信息 typedef struct tagSCROLLINFO { UINT cbSize; //存储这个结构的大小...
  • Windows编程之滚动条

    千次阅读 2018-11-13 08:14:22
    Windows编程之滚动条
  • 改变windows系统自带滚动条样式

    千次阅读 2018-09-20 10:07:31
    改变windows系统自带滚动条的样式,对chrome兼容很不错但是不兼容windows请酌情使用 ::-webkit-scrollbar { width: 8px; height: 8px; background:#b9b9b9; } ::-webkit-scrollbar-button { display: ...
  • Windows对话框和滚动条

    千次阅读 2010-01-11 23:32:00
    Windows对话框和滚动条cheungmine 2010-1 尽管在Windows平台上编程多年,对滚动条的理解还是很肤浅。尤其给对话框添加滚动条。参考下面的文章: http://www.codeproject.com/KB/dialog/scroll_dialog.aspx ...
  • Windows编程之滚动条滚动条消息

    千次阅读 2013-09-23 12:19:40
    在用鼠标单击滚动条或者拖动卷动方块时,Windows给窗口消息处理程序发送WM_VSCROLL(供上下移动)和WM_HSCROLL(供左右移动)消息。在滚动条上的每个鼠标动作都至少产生两个消息,一条在按下鼠标按钮时产生,一条在...
  • html页面滚动条设置

    千次阅读 2012-09-05 11:28:53
    作者:pichcar   ...页面滚动条颜色设置隐藏技巧说明-网页特效观止-网页特效代码...1.overflow内容溢出时的设置(设定被设定对象是否显示滚动条) overflow-x水平方向内容溢出时的设置 overflow-y垂直方向内
  • 如题,请问windows滚动条是如何运作的? 我只能推测出 最大滚动距离=视窗高度-滚动条长度 但滚动条的长度又是从何而来? 视窗高度/内容高度 ?? 是不是还有系数? 是否要去掉按钮高度?
  • css实现滚动条兼容mac和windows

    千次阅读 2019-05-13 14:50:01
    要做到同时兼容windows和Mac,那么可以自定义滚动条,做法很简单,在全局的css样式中加入下面代码即可: //自动移滚动条样式 ::-webkit-scrollbar{ width: 5px; height: 5px; } ::-webkit-scrollbar-thumb{ ...
  • Windows API学习之滚动条系列函数

    千次阅读 2011-02-17 18:17:00
    Windows API学习之滚动条系列函数。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 67,302
精华内容 26,920
关键字:

windows滚动条设置