//这是我初次编写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_MINIMIZEBOX和WS_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.wParam; //如果得到一个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,cxClient,cyChar,cyClient,iMaxWidth; int i,x,y,iPaintBeg,iPaintEnd,iVertPos,iHorzPos; TCHAR szBuffer[10]; TEXTMETRIC tm; SCROLLINFO si; 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); iMaxWidth=40*cxChar +22*cxCaps;//设置水平位置最大值(可是为啥一个*40,一个*22呢?) // 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 高字节用于客户区的垂直大小 cxClient=LOWORD(lParam); // 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; //设置范围和页面 si.nMin=0; si.nMax=2+iMaxWidth/cxChar; //设置水平位置最大值,用到了上面的iMaxWidth si.nPage=cxClient/cxChar; SetScrollInfo(hwnd,SB_HORZ,&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))//wParam的低字节指出了鼠标对滚动条进行的操作,高字节是附加参数(SB_THUMBTRACK和SB_THUMBPOSITION对应着) { 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; } 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_HSCROLL: //水平滚动条消息 si.cbSize=sizeof(si); si.fMask=SIF_ALL; GetScrollInfo(hwnd,SB_HORZ,&si); iHorzPos=si.nPos; switch(LOWORD(wParam))//wParam的低字节指出了鼠标对滚动条进行的操作,高字节是附加参数(SB_THUMBTRACK和SB_THUMBPOSITION对应着) { case SB_LINERIGHT: si.nPos+=1; break; case SB_LINELEFT: si.nPos-=1; break; case SB_PAGELEFT: //不知道咋回事的,这个消息(和下一个消息)一直响应不了,也不知道为啥 si.nPos-=si.nPage; break; case SB_PAGERIGHT: si.nPos+=si.nPage; break; case SB_THUMBTRACK: //释放滚动条/按下滚动条 si.nPos=si.nTrackPos; //高字节附加参数,此时指出位置变化为释放后的/按下滚动条 break; default: break; } si.fMask=SIF_POS; SetScrollInfo(hwnd,SB_HORZ,&si,TRUE); GetScrollInfo(hwnd,SB_HORZ,&si); if(si.nPos !=iHorzPos) { ScrollWindow(hwnd,cxChar*(iHorzPos-si.nPos),0,NULL,NULL); UpdateWindow(hwnd); } return 0; case WM_PAINT: //此消息也不是从消息队列中获得的,也是widows发送的 hdc=BeginPaint(hwnd,&ps); //返回的是一个"设备描述表句柄" si.cbSize=sizeof(si); si.fMask=SIF_POS; GetScrollInfo(hwnd,SB_VERT,&si); iVertPos=si.nPos; GetScrollInfo(hwnd,SB_HORZ,&si); iHorzPos=si.nPos; iPaintBeg=max(0,iVertPos+ps.rcPaint.top/cyChar); iPaintEnd=min(NUMLINES-1,iVertPos+ps.rcPaint.bottom/cyChar); 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+32*cxCaps,y,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szLabel)); //显示第一列 SetTextAlign(hdc,TA_RIGHT|TA_TOP); //设置为对齐方式(右上对齐) TextOut(hdc,x+22*cxCaps+150*cxChar,y,szBuffer,wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].ilndex)));//显示第三列 SetTextAlign(hdc,TA_LEFT|TA_TOP); //设置为对齐方式(重新设置为普通方式对齐) } 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_CREATE和WM_PAINT //都是不进队列的,直接由windows发送,不管我们的事
本文介绍了一个包含滚动条的Windows窗口程序实现案例。通过详细解析代码,展示了如何利用Windows API创建窗口、处理滚动条消息及绘制文本等内容。适用于初学者了解Windows编程的基础知识。

被折叠的 条评论
为什么被折叠?



