代码改变世界

WM_PAINT

2016-05-26 21:03  sylar_liang  阅读(561)  评论(0编辑  收藏  举报

WM_PAINT:

BeginPaint(hWnd, &ps);

其中: ps 为 

typedef struct tagPAINTSTRUCT

{

  HDC hdc; //设备环境句柄

  BOOL fErase; 

  RECT rcPaint;

  ...

}

主要是前3个参数设置。

bErase大多数情况下被设置为FALSE(默认),意味着Windows在先前的BeginPaint函数中已经擦除了无效区域的背景。

如果想在窗口过程中自定义背景擦除方式,必须自己处理WM_ERASEBKGND消息。

 

InvalidRect函数使一个矩形无效,最后一个参数传FALSE将指定背景是否要被擦除。

FALSE: Windows不会擦除背景。

TRUE: 擦除。

 

调用BeginPaint函数后,PAINTSTRUCT的bErase值将是TRUE。

 

处理WM_PAINT消息时,在调用BeginPaint前调用

InvalidateRect(hWnd, NULL, TRUE);

这个调用将整个客户区无效化,并使其后调用的BeginPaint擦除原有的背景。

最后一个参数设为FALSE,BeginPaint函数将不会擦除背景。

 

GetDC获取的是整个客户区的设备环境句柄,BeginPaint获取的是无效区域的设备环境句柄。

GetDC不会将无效区域有效化,如需有效化整个客户区,ValidateRect(hWnd, NULL);

 

GetWindowDC获取的是整个窗口的设备环境句柄。如需修改窗口的标题栏输出,程序还需处理WM_NCPAINT(非客户区绘制)消息。

---

TextOut(hdc, x, y, psText, Length ); //x,y 在客户区的起始位置。距离左上角的坐标点。

 

文本背景色和窗口类中设定的背景色是不一样的。

 

传给函数的坐标一般称为 "逻辑坐标";

映射方式决定将GDI绘图函数中的逻辑坐标转换成显示器上的物理像素坐标。默认映射方式是MM_TEXT。

MM_TEXT模式下逻辑单位和物理单位都是像素点。

 

GetSystemMetrics函数来获取用户界面的尺寸。

GetTextMetrics获取字体尺寸。//定义变量 TEXTMETRIC tm;

typedef struct tagTEXTMETRIC

{

LONG tmHeight;

LONG tmAscent;

LONG tmDescent;

LONG tmInternalLeading;

LONG tmExternalLeading;

...

}

主要是这5个参数。

Leading(间距)是2行文字之间的空间。tmInternalLeading内部间距,通常用于显示重音符号。

tmExternalLeading不包含在tmHeight内,该字段指在两行文字之间留出的空间大小。

tmHeight = tmAscent + tmDescent;

系统字体的尺寸取决于Windows运行时的分辨率,有时还取决于用户选定的系统字号。

 

tmAscent 包括 tmInternalLeading;

Windows运行时,系统字体不会变化,应用程序只需调用一次GetTextMetrics,最好的时机是在窗口处理WM_CREATE。

定义2个变量来保存字符的平均宽度和总高度:

static int cxChar, cyChar; //变量名中的c 代表 count

示例代码:

GetTextMetrics(hdc, &tm);

cxChar = tm.tmAveCharWidth; //tmAveCharWidth是小写字符的加权平均宽度,tmMaxCharWidth是字体中最宽的字符的宽度。

cyChar = tm.tmHeight + tm.tmExternalLeading; //ExteralLeading 一般为0.

cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2; //大写字符的平均宽度。等宽字体中,cxCaps等于cxChar;变宽字体cxCaps是cxChar的1.5倍。tmPitchAndFamily字段的低位决定字体是否为等宽,1 变宽, 0 等宽。

通常需要显示的是格式化的数字和字符串。用 sprintf函数。

 

WM_SIZE 低位lParam客户区的宽度,wParam客户区的高度。

static int cxClient, cyClient;

cxClient = LWORD(lParam); //cxClient / cxChar 整行能显示的字数。

cyClient = HWORD(wParam); //cyClient 高度

 

滚动条: CreateWindow 第三个参数加上 WS_HSCROLL(水平滚动条) WS_VSCROLL(垂直滚动条)

SetScrollRange(hWnd, iBar, iMin, iMax, bRedraw); //bRedraw = FALSE,不重绘

//iMin~iMax滚动条范围(默认0-100)

//iBar 要么是 SB_VERT, SB_HORZ

如果在调用SetScrollRange函数之后还将调用其他函数来调整滚动条的显示时,最好将bRedraw设为FALSE避免过多的重绘。

SetScrollPos(hWnd, iBar, iPos, bRedraw); //设置滚动条位置。

消息有: SB_LINEDOWN, SB_LINEUP, SB_PAGEUP, SB_PAGEDOWN, SB_THUMBPOSITION

SB_THUMBTRACK消息,wParam的高位字是用户拖动滑块的当前位置。

SB_THUMBPOSITION消息,wParam的高位字是用户松开鼠标键时滑块的最终位置。 //这个比较好处理,直接调用SetScrollPos函数。

//部分示例代码

iVscrollPos = max(0, min(iVscrollPos, Max- 1)); //可以防止 iVscrollPos小于0的情况。

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

{

  SetScrollPos(hWnd, SB_VERT, iVscrollPos, TRUE); //bRedraw 为TRUE

  InvalidateRect(hWnd, NULL, TRUE); //使整个窗口无效。

}

如果想立刻更新无效区域,可以在调用InvalidateRect后调用UpdateWindow函数。-》发送WM_PAINT消息。

//新滚动条函数 SetScrollInfo GetScrollInfo

SetScrollInfo(hWnd, iBar, &si, bRedraw);

GetScrollInfo(hWnd, iBar, &si);

typedef struct tagSCROLLINFO

{

UINT cbSize; //设为sizeof(SCROLLINFO)

UINT fMask; //要设置或获取的值

int nMin;

int nMax;

UINT nPage; //页面大小

int nPos; //当前位置

int nTrackPos; //当前追踪位置

}SCROLLINFO

iBar:

1>SIF_RANGE 返回 nMin nMax范围

2>SIF_POS 当前位置。

3>SIF_ALL