Painting和重绘
通过Post WM_PAINT消息通知WndProc,客户区的无效区域要重绘。
WM_PAINT消息
在以下情况下WndProc收到WM_PAINT
1.被遮挡的区域通过窗口移动又重现
2..resize
3. ScrollWindow或ScrollDC的调用,以scroll客户区
4. 程序调用了InvalidateRect或InvalidateRgn
有时,当客户区的某部分被暂时重写时,Windows也会试图保存之前的display以便restore。但不保证成功,所以有时Windows也会post WM_PAINT消息,有下列几种情况:
1.对话框,消息框在客户区的移动
2.menu拉动
3.tool tip显示
在下列情况,windows可以restore之前保存的display
1.mouse光标移动
2.icon拖曳入客户区
Valid和Invalid矩形区
每次只需更新一个小的区域,即有display更改的矩形区域,以提高绘制效率。当客户区有invalid区时,Windows就会将WM_PAINT消息放置到消息队列。
Wndows内部对每个窗口都维护了一个paint information structure,对于invalid区,包含了一个最小的能encompass invalid区的矩形,即”invalid矩形”。倘若在WndProc处理等待的WM_PAINT消息之前,又有新的invalid区产生,则Windows会计算对应的新的invalid矩形。
WndProc可以通过调用InvalidateRect函数,来使自己的客户区的一个矩形变成invalid矩形,倘若此时队列中有WM_PAINT,则合并生成新的invalid矩形,否则,则放置一个WM_PAINT到队列。
通过GetUpdateRect,我们可得到invalid矩形的坐标。而通过调用ValidateRect函数,可将任一矩形区设为valid,如果该函数将整个客户区都validate了,那么队列中的WM_PAINT将统统被移去。(有invalid矩形,才有重绘的必要)。
GDI介绍
GDI(Graphics Device Interface)。
设备上下文(DC)
DC是GDI内部维护的一个数据结构,它和一个特定的显示设备联系在一起。DC有一些graphics的属性值,诸如文字颜色,字体等等。用完DC后,要记得release。
获取DC句柄:法1
在处理WM_PAINT时用此法,涉及两个函数,BeginPaint和EndPaint。使用前者填充PAINTSTRUCT结构ps,并返回DC句柄,后者负责释放DC。
必须成对出现。另外,有一个很重要的clipping区的概念,windows只能在clipping区绘制,调用BeginPaint,将会把Update区设为clipping区,如果有标志要erase背景,则BeginPaint会将Update区的背景擦掉。BeginPaint还会把invalid区设为有效,不用担心,原来的invalid区信息已保存在DC和ps中。
Paint信息结构
fErase:是否要erase背景,如果之前调用了BeginPaint,则不需要,如果调用InvalidateRect,并将该函数的最后一个参数设为0,则引发的WM_PAINT处理时,fErase为真,需要erase invalid矩形的背景。
rcPaint: 客户区中的invalid 矩形,此为应该绘制之所。
获取DC句柄:法2
在WM_PAINT处理之外,用GetDC得到DC,最后用ReleaseDC释放。此法返回的DC的clipping区是整个客户区,即可以随便画。而且它不会validate任何区域,若想validate整个客户区,需调用
ValidateRect(hwnd,NULL)
TextOut:细说
TextOut(hdc,x,y,psTest,iLength);
系统字体
不同的字符宽度不一。
字符大小
系统字体的height和平均width。有用的函数:GetTextMetrics
Text Metrics:细节
LONG tmHeight ;
LONG tmAscent ;
LONG tmDescent ;
LONG tmInternalLeading ;
LONG tmExternalLeading ;
LONG tmAveCharWidth ;
LONG tmMaxCharWidth ;
格式化文本
sprintf,wsprintf,不好用printf了
putting it all together
例子程序:利用GetSystemMetrics获取各种属性,并打印在客户区。
/*-----------------------------------------------
SYSMETS.H -- System metrics display structure
-----------------------------------------------*/
#define NUMLINES ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))
struct
{
int iIndex;
TCHAR * szLabel;
TCHAR * szDesc;
}
sysmetrics[] = {
SM_CXSCREEN, TEXT ("SM_CXSCREEN"), TEXT ("Screen width in pixels"),
SM_CYSCREEN, TEXT ("SM_CYSCREEN"), TEXT ("Screen height in pixels"),
SM_CXVSCROLL, TEXT ("SM_CXVSCROLL"), TEXT ("Vertical scroll width"),
SM_CYHSCROLL, TEXT ("SM_CYHSCROLL"), TEXT ("Horizontal scroll height"),
SM_CYCAPTION, TEXT ("SM_CYCAPTION"), TEXT ("Caption bar height"),
SM_CXBORDER, TEXT ("SM_CXBORDER"), TEXT ("Window border width"),
SM_CYBORDER, TEXT ("SM_CYBORDER"), TEXT ("Window border height"),
SM_CXFIXEDFRAME, TEXT ("SM_CXFIXEDFRAME"), TEXT ("Dialog window frame width"),
SM_CYFIXEDFRAME, TEXT ("SM_CYFIXEDFRAME"), TEXT ("Dialog window frame height"),
SM_CYVTHUMB, TEXT ("SM_CYVTHUMB"), TEXT ("Vertical scroll thumb height"),
SM_CXHTHUMB, TEXT ("SM_CXHTHUMB"), TEXT ("Horizontal scroll thumb width"),
SM_CXICON, TEXT ("SM_CXICON"), TEXT ("Icon width"),
SM_CYICON, TEXT ("SM_CYICON"), TEXT ("Icon height"),
SM_CXCURSOR, TEXT ("SM_CXCURSOR"), TEXT ("Cursor width"),
SM_CYCURSOR, TEXT ("SM_CYCURSOR"), TEXT ("Cursor height"),
SM_CYMENU, TEXT ("SM_CYMENU"), TEXT ("Menu bar height"),
SM_CXFULLSCREEN, TEXT ("SM_CXFULLSCREEN"), TEXT ("Full screen client area width"),
SM_CYFULLSCREEN, TEXT ("SM_CYFULLSCREEN"), TEXT ("Full screen client area height"),
SM_CYKANJIWINDOW, TEXT ("SM_CYKANJIWINDOW"), TEXT ("Kanji window height"),
SM_MOUSEPRESENT, TEXT ("SM_MOUSEPRESENT"), TEXT ("Mouse present flag"),
SM_CYVSCROLL, TEXT ("SM_CYVSCROLL"), TEXT ("Vertical scroll arrow height"),
SM_CXHSCROLL, TEXT ("SM_CXHSCROLL"), TEXT ("Horizontal scroll arrow width"),
SM_DEBUG, TEXT ("SM_DEBUG"), TEXT ("Debug version flag"),
SM_SWAPBUTTON, TEXT ("SM_SWAPBUTTON"), TEXT ("Mouse buttons swapped flag"),
SM_CXMIN, TEXT ("SM_CXMIN"), TEXT ("Minimum window width"),
SM_CYMIN, TEXT ("SM_CYMIN"), TEXT ("Minimum window height"),
SM_CXSIZE, TEXT ("SM_CXSIZE"), TEXT ("Min/Max/Close button width"),
SM_CYSIZE, TEXT ("SM_CYSIZE"), TEXT ("Min/Max/Close button height"),
SM_CXSIZEFRAME, TEXT ("SM_CXSIZEFRAME"), TEXT ("Window sizing frame width"),
SM_CYSIZEFRAME, TEXT ("SM_CYSIZEFRAME"), TEXT ("Window sizing frame height"),
SM_CXMINTRACK, TEXT ("SM_CXMINTRACK"), TEXT ("Minimum window tracking width"),
SM_CYMINTRACK, TEXT ("SM_CYMINTRACK"), TEXT ("Minimum window tracking height"),
SM_CXDOUBLECLK, TEXT ("SM_CXDOUBLECLK"), TEXT ("Double click x tolerance"),
SM_CYDOUBLECLK, TEXT ("SM_CYDOUBLECLK"), TEXT ("Double click y tolerance"),
SM_CXICONSPACING, TEXT ("SM_CXICONSPACING"), TEXT ("Horizontal icon spacing"),
SM_CYICONSPACING, TEXT ("SM_CYICONSPACING"), TEXT ("Vertical icon spacing"),
SM_MENUDROPALIGNMENT, TEXT ("SM_MENUDROPALIGNMENT"),TEXT ("Left or right menu drop"),
SM_PENWINDOWS, TEXT ("SM_PENWINDOWS"), TEXT ("Pen extensions installed"),
SM_DBCSENABLED, TEXT ("SM_DBCSENABLED"), TEXT ("Double-Byte Char Set enabled"),
SM_CMOUSEBUTTONS, TEXT ("SM_CMOUSEBUTTONS"), TEXT ("Number of mouse buttons"),
SM_SECURE, TEXT ("SM_SECURE"), TEXT ("Security present flag"),
SM_CXEDGE, TEXT ("SM_CXEDGE"), TEXT ("3-D border width"),
SM_CYEDGE, TEXT ("SM_CYEDGE"), TEXT ("3-D border height"),
SM_CXMINSPACING, TEXT ("SM_CXMINSPACING"), TEXT ("Minimized window spacing width"),
SM_CYMINSPACING, TEXT ("SM_CYMINSPACING"), TEXT ("Minimized window spacing height"),
SM_CXSMICON, TEXT ("SM_CXSMICON"), TEXT ("Small icon width"),
SM_CYSMICON, TEXT ("SM_CYSMICON"), TEXT ("Small icon height"),
SM_CYSMCAPTION, TEXT ("SM_CYSMCAPTION"), TEXT ("Small caption height"),
SM_CXSMSIZE, TEXT ("SM_CXSMSIZE"), TEXT ("Small caption button width"),
SM_CYSMSIZE, TEXT ("SM_CYSMSIZE"), TEXT ("Small caption button height"),
SM_CXMENUSIZE, TEXT ("SM_CXMENUSIZE"), TEXT ("Menu bar button width"),
SM_CYMENUSIZE, TEXT ("SM_CYMENUSIZE"), TEXT ("Menu bar button height"),
SM_ARRANGE, TEXT ("SM_ARRANGE"), TEXT ("How minimized windows arranged"),
SM_CXMINIMIZED, TEXT ("SM_CXMINIMIZED"), TEXT ("Minimized window width"),
SM_CYMINIMIZED, TEXT ("SM_CYMINIMIZED"), TEXT ("Minimized window height"),
SM_CXMAXTRACK, TEXT ("SM_CXMAXTRACK"), TEXT ("Maximum draggable width"),
SM_CYMAXTRACK, TEXT ("SM_CYMAXTRACK"), TEXT ("Maximum draggable height"),
SM_CXMAXIMIZED, TEXT ("SM_CXMAXIMIZED"), TEXT ("Width of maximized window"),
SM_CYMAXIMIZED, TEXT ("SM_CYMAXIMIZED"), TEXT ("Height of maximized window"),
SM_NETWORK, TEXT ("SM_NETWORK"), TEXT ("Network present flag"),
SM_CLEANBOOT, TEXT ("SM_CLEANBOOT"), TEXT ("How system was booted"),
SM_CXDRAG, TEXT ("SM_CXDRAG"), TEXT ("Avoid drag x tolerance"),
SM_CYDRAG, TEXT ("SM_CYDRAG"), TEXT ("Avoid drag y tolerance"),
SM_SHOWSOUNDS, TEXT ("SM_SHOWSOUNDS"), TEXT ("Present sounds visually"),
SM_CXMENUCHECK, TEXT ("SM_CXMENUCHECK"), TEXT ("Menu check-mark width"),
SM_CYMENUCHECK, TEXT ("SM_CYMENUCHECK"), TEXT ("Menu check-mark height"),
SM_SLOWMACHINE, TEXT ("SM_SLOWMACHINE"), TEXT ("Slow processor flag"),
SM_MIDEASTENABLED, TEXT ("SM_MIDEASTENABLED"), TEXT ("Hebrew and Arabic enabled flag"),
SM_MOUSEWHEELPRESENT, TEXT ("SM_MOUSEWHEELPRESENT"),TEXT ("Mouse wheel present flag"),
SM_XVIRTUALSCREEN, TEXT ("SM_XVIRTUALSCREEN"), TEXT ("Virtual screen x origin"),
SM_YVIRTUALSCREEN, TEXT ("SM_YVIRTUALSCREEN"), TEXT ("Virtual screen y origin"),
SM_CXVIRTUALSCREEN, TEXT ("SM_CXVIRTUALSCREEN"),TEXT ("Virtual screen width"),
SM_CYVIRTUALSCREEN, TEXT ("SM_CYVIRTUALSCREEN"),TEXT ("Virtual screen height"),
SM_CMONITORS, TEXT ("SM_CMONITORS"), TEXT ("Number of monitors"),
SM_SAMEDISPLAYFORMAT, TEXT ("SM_SAMEDISPLAYFORMAT"),TEXT ("Same color format flag")
};//SYSMETS1.cpp
#include <Windows.h>
#include "SYSMETS.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
{
static TCHAR szAppName[] = TEXT("SysMets1");
HWND hwnd;
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_APPLICATION);
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("fail!"),szAppName,MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName,
TEXT("Get System Metrics No. 1"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
// return 0;
}
//WParam是int,LPARAM是long
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
static int cxChar,cxCaps,cyChar;
HDC hdc;
PAINTSTRUCT ps;
TCHAR szBuffer[10];
TEXTMETRIC tm;
switch(message)
{
case WM_CREATE:
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);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
for(int i =0;i < NUMLINES;i++)
{
TextOut(hdc,0,cyChar * i,sysmetrics[i].szLabel,lstrlen(sysmetrics[i].szLabel));
TextOut(hdc,22 * cxCaps,cyChar * i,sysmetrics[i].szDesc,lstrlen(sysmetrics[i].szDesc));
SetTextAlign(hdc,TA_RIGHT | TA_TOP);
int len = wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].iIndex));
TextOut(hdc, 22 * cxCaps + 40 * cxChar, cyChar * i,szBuffer,len);
SetTextAlign(hdc,TA_LEFT | TA_TOP);
}
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
SYSMETS2.cpp
#include <Windows.h>
#include "SYSMETS.h"
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow)
{
static TCHAR szAppName[] = TEXT("SysMets2");
HWND hwnd;
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_APPLICATION);
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL,TEXT("fail!"),szAppName,MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName,
TEXT("Get System Metrics No. 2"),
WS_OVERLAPPEDWINDOW | WS_VSCROLL,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
// return 0;
}
//WParam是int,LPARAM是long
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
static int cxChar,cxCaps,cyChar,cyClient,iVscrollPos;
HDC hdc;
PAINTSTRUCT ps;
TCHAR szBuffer[10];
TEXTMETRIC tm;
switch(message)
{
case WM_CREATE:
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:
cyClient = HIWORD(lParam);
return 0;
case WM_VSCROLL:
switch(LOWORD(wParam))
{
case SB_LINEUP:
iVscrollPos --;
break;
case SB_LINEDOWN:
iVscrollPos ++;
break;
case SB_PAGEUP:
iVscrollPos -= cyClient / cyChar;
break;
case SB_PAGEDOWN:
iVscrollPos += cyClient / cyChar;
break;
case 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);//马上绘制
}
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
for(int i =0;i < NUMLINES;i++)
{
int y = cyChar * (i - iVscrollPos);
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_RIGHT | TA_TOP);
int len = wsprintf(szBuffer,TEXT("%5d"),GetSystemMetrics(sysmetrics[i].iIndex));
TextOut(hdc, 22 * cxCaps + 40 * cxChar, y,szBuffer,len);
SetTextAlign(hdc,TA_LEFT | TA_TOP);
}
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}