好久没有学习Windows下的编程了, 因为我发现在学习Delphi时;看书的时候一会儿就涉及到windows编程的机制了。
因此在今天有时间的时候学习一下windows的编程。
#include <windows.h>
//#include "sysmets.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iShowCmd)
{
static TCHAR szAppName[]=TEXT("SysMets4");
static TCHAR szNeedNT[]=TEXT("You need winNT to run this program!");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndclass.hInstance=hInstance;
wndclass.lpfnWndProc=WndProc;
wndclass.lpszClassName=szAppName;
wndclass.lpszMenuName=NULL;
wndclass.style=CS_VREDRAW | CS_HREDRAW;
if(!RegisterClass(&wndclass))
{
MessageBox(NULL,szNeedNT,"Warning",MB_OK);
return 0;
}
hwnd=CreateWindow(wndclass.lpszClassName,
szAppName,
WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCROLL,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd,iShowCmd);
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 cxChar,
cxCaps,
cyChar,
cxClient,
cyClient,
iMaxWidth;
int i,
x,
y,
iVertPos,
iHorzPos,
iPaintBeg,
iPaintEnd;
SCROLLINFO si; //通过这个结构体来处理与滚动条相关的消息
/*
结构体的SCROLLINFO
typedef struct tagSCROLLINFO
{
UINT cbSize; //这个字段表示的是结构体变量的大小, 通常设定为cbsize=sizeof SCROLLINFO;
UINT fMask; //调用GetScrollInfo函数和SetScrollPosInfo函数时想要设定的值
int nMin; //V_Range或者R_Range的最小值
int nMax; //滚动范围的最大值
UINT nPage; // 页面的大小, 这个值一般是cyClient/cyChar的大小
int nPos; // 滚动条的当前位置
int nTrackPos; //
} SCROLLINFO, FAR *LPSCROLLINFO;
fMask指定使用结构中哪些成员,不指定的就不使用;可以是以下几个值的任意组合
SIF_ALL
SIF_DISABLENOSCROLL
SIF_PAGE
SIF_POS
SIF_RANGE
SIF_TRACKPOS
函数SetScrollInfo和GetScrollInfo的参数LPSCROLLINFO lpsi指向该结构。在程序中,可以定义如下的SCROLLINFO结构型态:
SCROLLINFO si ;
在调用SetScrollInfo或GetScrollInfo之前,必须将cbSize字段设定为结构的大小:
si.cbSize = sizeof (si) ;
或
si.cbSize = sizeof (SCROLLINFO) ;
把fMask字段设定为一个以上以SIF前缀开头的旗标,并且可以使用C的位操作OR运算子(|)组合这些旗标。
SetScrollInfo函数使用SIF_RANGE旗标时,必须把nMin和nMax字段设定为所需的卷动列范围。
GetScrollInfo函数使用SIF_RANGE旗标时,应把nMin和nMax字段设定为从函数传回的目前范围。
SIF_POS旗标也一样。当通过SetScrollInfo使用它时,必须把结构的nPos字段设定为所需的位置。
可以通过GetScrollInfo使用SIF_POS旗标来取得目前位置。
使用SIF_PAGE旗标能够取得页面大小。用SetScrollInfo函数把nPage设定为所需的页面大小。
GetScrollInfo使用SIF_PAGE旗标可以取得目前页面的大小。如果不想得到比例化的卷动列,就不要使用该旗标。
当处理带有SB_THUMBTRACK或SB_THUMBPOSITION通知码的WM_VSCROLL或WM_HSCROLL消息时,通过GetScrollInfo只使用SIF_TRACKPOS旗标。
从函数的传回中,SCROLLINFO结构的nTrackPos字段将指出目前的32位的卷动方块位置。
*/
//TCHAR szBuffer[10];
TEXTMETRIC tm;
switch(message)
{
case WM_CREATE:
hdc=GetDC(hwnd);
/*
tm结构体的定义:
*/
GetTextMetrics(hdc,&tm); //通过这个函数获取设备内容中关于字符系统信息
cxChar=tm.tmAveCharWidth; //表示字符的平均宽度
cyChar=tm.tmHeight+tm.tmExternalLeading; //字符的高度
cxCaps=(tm.tmPitchAndFamily & 1 ? 3:2)*cxChar /2;
ReleaseDC(hwnd,hdc);
iMaxWidth=40 * cxChar + 22 * cxCaps;
return 0;
case WM_SIZE:
/*
WM_SIZE消息:
The WM_SIZE message is sent to a window after its size has changed.
当窗口大小发生变化时发送给窗口的消息。
当窗口处理函数接收到WM_SIZE消息时, message会接收一个wm_size消息,而消息的附加消息
会保存在wParam中,其中wParam分为两段:
低字: 保存窗口大小改变后x方向客户区的大小
高字: 保存窗口大小改变后y方向客户区的大小
*/
cxClient=LOWORD(lParam);
cyClient=HIWORD(lParam);
si.cbSize=sizeof si;
//在函数中使用滚动条的滚动范围信息和页面大小信息,这个地方还需要进一步理解
si.fMask=SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = 100-1;
si.nPage = cyClient/cyChar;
SetScrollInfo(hwnd,SB_VERT,&si,TRUE); //SB_VERT:用于窗口中标准垂直滚动条,此处函数仅改变垂直方向的信息
si.cbSize=sizeof si;
si.fMask=SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax=2+iMaxWidth+cyChar;
si.nPage=cxClient/cxChar;
SetScrollInfo(hwnd,SB_HORZ,&si,TRUE); //SB_HORZ:用于窗口中水平滚动条,此处函数仅改变水平方向滚动条的信息
return 0;
case WM_VSCROLL:
/*
WM_VSCROLL:窗口的垂直滚动条消息。 当接收到这个消息时,wParam参数会附加消息码/通知码。
wParam附加通知码存在该参数的低字, 可以通过LOWORD获取这个通知码消息,并且在一个switch中进行
进行处理。
*/
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_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.nPos+si.nPage;
break;
case SB_THUMBTRACK:
si.nPos=si.nTrackPos;
break;
default:
break;
} //Scroll 附加消息处理
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:
/*
WM_HSCROLL:窗口的水平滚动条消息。 当接收到这个消息时,wParam参数会附加消息码/通知码。
wParam附加通知码存在该参数的低字, 可以通过LOWORD获取这个通知码消息,并且在一个switch中进行
进行处理。
*/
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_HORZ,&si);
iHorzPos=si.nPos;
switch(LOWORD(wParam))
{
case SB_LINELEFT:
si.nPos += -1;
break;
case SB_LINERIGHT:
si.nPos++;
break;
case SB_PAGELEFT:
si.nPos -=si.nPage;
break;
case SB_PAGERIGHT:
si.nPos +=si.nPos;
break;
case SB_THUMBPOSITION:
si.nPos=si.nTrackPos;
break;
default:
break;
} // scroll 附加消息处理
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);
}
return 0;
case WM_KEYDOWN:
/*
WM_KEYDOWN: 窗口的键盘消息
键盘消息分为:
WM_KEYDOWN WM_KEYUP
WM_SYSKEYDOWN WM_SYSKEYUP
这里处理的是非系统键按下消息。
因为键比较多,因此也需要一个消息的附加信息, 这个附加信息还是通过wParam参数进行传递
通常键盘消息的wParam附加信息,成为虚拟键码。 这个参数信息通常用VK_ 开头表示。
在键盘消息里面lParam参数也包含了丰富的信息,这些信息与lParam各个位的取值相关。
*/
switch(wParam)
{
case VK_HOME:
SendMessage(hwnd,WM_VSCROLL,SB_TOP,0);
break;
case VK_END:
SendMessage(hwnd,WM_VSCROLL,SB_BOTTOM,0);
break;
case VK_PRIOR:
SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0);
break;
case VK_NEXT:
SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0);
break;
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;
case VK_LWIN:
MessageBox(hwnd,"You have press left win key!","提示",MB_OK);
break;
} //keydown 消息处理
case WM_PAINT:
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(1000-1,iVertPos+ps.rcPaint.bottom/cyChar);
for(i=iPaintBeg;i<=iPaintEnd;i++)
{
x=cxChar* (1-iHorzPos);
y=cxChar*(1-iVertPos);
TextOut(hdc,x,y,"abc",strlen("abc"));
TextOut(hdc,x+22*cxCaps,y,"abcdefg",strlen("abcdefg"));
SetTextAlign(hdc,TA_RIGHT | TA_TOP);
}//for 循环
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
我发现在目前我学习过的windows编程知识里面,滚动条的处理和字符系统处理比较困难。
哈哈, 希望自己能够坚持下去, 在2009年的时候,就打算学习win的编程,结果没有坚持下去,
当时学习的东西又基本忘记了,
好在目前有博客园,在这里记录学习的点滴,促使我一直坚持学习............