编程技术分享
分享一些我自己开发过程中的笔记
1,当下列情况发生时windows会发送WM_PAINT消息:
在使用者移动视窗或显示视窗时,视窗中先前被隐藏的区域重新可见。
使用者改变视窗的大小(如果视窗类别样式有著CS_HREDRAW和CS_VREDRAW位元旗标的设定)。
程式使用ScrollWindow或ScrollDC函式滚动显示区域的一部分。
程式使用InvalidateRect或InvalidateRgn函式刻意产生WM_PAINT讯息。
当对话框或者信息框被关闭
菜单被关闭
显示工具提示信息
2,下面的情况下不会发送WM_PAINT消息,windows会自动保存
鼠标箭头穿过显示区域
图标拖过显示区域
3,windows为每个程序保存一个绘图资讯结构,且windows不可能发送两个WM_PAINT结构
4,InvalidateRect可以让整个显示区域无效,GetUpdateRect可以获取无效举行的坐标,呼叫BeginPaint后,整个显示区域变为有效,ValidateRect可以让任意举行区域变为有效
5,TextOut (hdc, x, y, psText, iLength) ;
6,取得DC的第一种方法:
在回调函数中定义
PAINTSTRUCT ps ;
在处理WM_PAINT时先调用BeginPaint
他的第一个参数是窗口句柄,第二个是一个PAINTSTRUCT结构地址,返回值是HDC hdc ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
处理代码;
EndPaint (hwnd, &ps) ;
break;
7,若不调用BeginPaint和EndPaint而直接return,windows会不断地发送WM_PAINT消息
8,PAINTSTRUCT的钱三个成员变量是有用的,第一个是hdc,第二个表示背景是否被擦除,如果被擦除则为FALSE否则为TRUE,第三个是rcPaint无效举行。
9,如果想在需要更新的举行外绘图,做以下呼叫
InvalidateRect (hwnd, NULL, TRUE) ;
10,获取dc的第二种方法
要得到视窗显示区域的装置内容代号,可以呼叫GetDC来取得代号,在使用完後呼叫ReleaseDC:
hdc = GetDC (hwnd) ;
处理代码
ReleaseDC (hwnd, hdc) ;
必须成对出现
11,如果想使整个屏幕变为有效,则需要呼叫
ValidateRect (hwnd, NULL) ;
12,使用GetWindowDC可以获取整个窗口的设备描述表句柄,需要处理飞显示区域重绘(WM_NCPAINT)消息。
13,TEXTMETRIC结构用来描述字体资讯
要使用GetTextMetrics函式,需要先定义一个结构变数(通常称为tm):
TEXTMETRIC tm ;
在需要确定文字大小时,先取得装置内容代号,再呼叫GetTextMetrics:
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
ReleaseDC (hwnd, hdc) ;
14,TEXTMETRIC的重要成员
LONG tmHeight; //字符高度 TEXTMETRIC结构字段的图示[1]
LONG tmAscent; //字符上部高度(基线以上)
LONG tmDescent; //字符下部高度(基线以下)
LONG tmInternalLeading, //由tmHeight定义的字符高度的顶部空间数目
LONG tmExternalLeading, //夹在两行之间的空间数目
LONG tmAveCharWidth, //平均字符宽度
LONG tmMaxCharWidth, //最宽字符的宽度
由于windows启动后,字体就不会再更改了,所以建议在WM_CREATE中调用GetTextMetric函数。
14,应该先保存字元宽度和字元高度,通常在囘調函數中使用
static int cxChar, cyChar ;
case WM_CREATE:
hdc = GetDC (hwnd) ;
GetTextMetrics (hdc, &tm) ;
cxChar = tm.tmAveCharWidth ;
cyChar = tm.tmHeight + tm.tmExternalLeading ;
ReleaseDC (hwnd, hdc) ;
15,格式化字符序列
int iLength ;
TCHAR szBuffer [40] ;
其他行程式
iLength = wsprintf (szBuffer, TEXT ("The sum of %i and %i is %i"),
iA, iB, iA + iB) ;
TextOut (hdc, x, y, szBuffer, iLength) ;
16,对於可变宽度字体,TEXTMETRIC结构中的tmPitchAndFamily栏位的低位元为1,对於固定宽度字体,该值为0。
17,SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
之後,传给後续TextOut函式的座标将指定字串的右上角,而不是左上角。
18,可以用GetClientRect函數獲取到視窗的大小,但是效率並不高,我們可以處理WM_SIZE(窗口大小被改變)消息,該消息的LPARAM低字組鐘存放寬度,高字節存放高度。
首先定義兩個靜態變量保存其大小
static int cxClient, cyClient ;
處理WM_SIZE消息的方法如下:
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
用如下公式可以計算出在顯示區域顯示的總行數
cyClient / cyChar
用如下公式計算一橫排能顯示的字符數
cxClient / cxChar
19,只需要在CreateWindow的第三個參數增加關鍵字SW_VSCROLL就可以增加垂直滾動條;增加SW_HSCROLL就可以獲得平行滾動條
20,SetScrollRange (hwnd, iBar, iMin, iMax, bRedraw) ;
用來設置捲動列的數值
参数iBar为SB_VERT或者SB_HORZ,iMin和iMax分别是范围的最小值和最大值。如果想要Windows根据新范围重画卷动列,则设置bRedraw为TRUE(如果在呼叫SetScrollRange後,呼叫了影响卷动列位置的其他函式,则应该将bRedraw设定为FALSE以避免过多的重画)。
21,可以使用SetScrollPos設置滾動條的位置
SetScrollPos (hwnd, iBar, iPos, bRedraw) ;
22,如果需要使用滾動條,程序員需要做以下工作
初始化卷动列的范围和位置
处理视窗讯息处理程式的卷动列讯息
更新卷动列内卷动方块的位置
更改显示区域的内容以回应对卷动列的更改
23,在用滑鼠单击卷动列或者拖动卷动方块时,Windows给视窗讯息处理程式发送WM_VSCROLL(供上下移动)和WM_HSCROLL(供左右移动)讯息。
25,在wParam的低字组是SB_THUMBTRACK时,wParam的高字组是使用者在拖动卷动方块时的目前位置。该位置位於卷动列范围的最小值和最大值之间。
在wParam的低字组是SB_THUMBPOSITION时,wParam的高字组是使用者释放滑鼠键後卷动方块的最终位置。对於其他的卷动列操作,wParam的高字组应该被忽略。
26,如果您希望立即更新无效区域,可以在呼叫InvalidateRect之後呼叫UpdateWindow:
UpdateWindow (hwnd) ;
27,SetScrollInfo (hwnd, iBar, &si, bRedraw) ;
GetScrollInfo (hwnd, iBar, &si) ;
其中第三個參數通常定義為
SCROLLINFO si ;
使用之前需要:
si.cbSize = sizeof (si) ;
或
si.cbSize = sizeof (SCROLLINFO) ;
顯示圖像
1,第三種獲得DC的方法
hdc = CreateDC (pszDriver, pszDevice, pszOutput, pData) ;
其他行程式
DeleteDC (hdc) ;
2,hdc = CreateIC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;
不能寫入,只能獲取信息
3,可以用以下方法獲得顯示器或打印機的信息
iValue = GetDeviceCaps (hdc, iIndex) ;
4,Windows应用程式可以使用SM_CXSCREEN和SM_CYSCREEN参数从GetSystemMetrics得到图素尺寸。
5,如果使用如下的方式建立視窗,則dc不會改變
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC ;
6,idSaved = SaveDC (hdc) ;
现在,可以改变一些属性,在想要回到呼叫SaveDC前存在的装置内容时,呼叫:
RestoreDC (hdc, idSaved) ;
7,GetPixel函式传回指定座标处的图素颜色:
crColor = GetPixel (hdc, x, y) ;
SetPixel函式在指定的x和y座标以特定的颜色设定图素:
SetPixel (hdc, x, y, crColor) ;
8,画一条直线,必须呼叫两个函式。第一个函式指定了线的开始点,第二个函式指定了线的终点:
MoveToEx (hdc, xBeg, yBeg, NULL) ;
LineTo (hdc, xEnd, yEnd) ;
9,目前位置就是開始點,如果想獲得,通過以下函數
POINT pt;
GetCurrentPositionEx (hdc, &pt) ;
10,如果想把一個數組中的座標繪製成一條線,可以用
Polyline (hdc, apt, 5) ;
11,PolylineTo使用目前位置作为开始点,并将目前位置设定为最後一根线的终点。
MoveToEx (hdc, apt[0].x, apt[0].y, NULL) ;
PolylineTo (hdc, apt + 1, 4) ;
12,使用下面的函数画一个矩形
Rectangle (hdc, xLeft, yTop, xRight, yBottom) ;
其中(xLeft, yTop)是矩形的左上角,(xRight, yBottom)是矩形的右下角。
13,使用下面的函数画一个椭圆
Ellipse (hdc, xLeft, yTop, xRight, yBottom) ;
14使用下面的函数画圆角矩形
RoundRect ( hdc, xLeft, yTop, xRight, yBottom, xCornerEllipse, yCornerEllipse) ;
如果xCornerEllipse等於xLeft与xRight的差,且yCornerEllipse等於yTop与yBottom的差,那么RoundRect函式将画出一个椭圆。
通常使用以下方法计算矩形的弧度
xCornerEllipse = (xRight - xLeft) / 4 ;
yCornerEllipse = (yBottom- yTop) / 4 ;
15,下面依次为画椭圆线、椭圆的一部分(弓形)、扇形
Arc (hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd) ;
Chord (hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd) ;
Pie (hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd) ;
16,如果想画一条贝塞尔曲线可以调用下面的函数
POINT apt[4];
PolyBezier (hdc, apt, iCount) ;
或
PolyBezierTo (hdc, apt, iCount) ;
iCount参数等於1加上您所绘制的这些首尾相接曲线条数的三倍。
17,可以使用以下方法定义一个画笔的句柄
HPEN hPen ;
hPen = GetStockObject (WHITE_PEN) ;
就获得了一个白色的画笔。
使用
SelectObject (hdc, hPen) ;
可以将画笔选中设备上下文
SelectObject返回之前画笔的句柄
18,可以使用以下函数建立一个逻辑画笔:
hPen = CreatePen (iPenStyle, iWidth, crColor) ;
19,如果想使用CreatePenIndirect应该先建立一个LOGPEN的结构
LOGPEN logpen ;
他有三个成员变量,就是CreatePen的三个参数
hPen = CreatePenIndirect (&logpen) ;
注意:必须在使用完画笔后,调用DeleteObject删除画笔
19,如果想获得某个画笔的信息可以调用
GetObject (hPen, sizeof (LOGPEN), (LPVOID) &logpen) ;
如果需要目前正在使用的画笔的句柄,可以调用
hPen = GetCurrentObject (hdc, OBJ_PEN) ;
20,您可以通过如下呼叫来改变Windows用来填入空隙的背景色:
SetBkColor (hdc, crColor) ;
通过将背景模式转换为TRANSPARENT,可以阻止Windows填入空隙:
SetBkMode (hdc, TRANSPARENT) ;
21,可以通过以下呼叫在装置内容中设定新的绘图模式:
SetROP2 (hdc, iDrawMode) ;
23,选择画刷的步骤如下
1,建立画刷句柄
HBRUSH hBrush ;
2,呼叫GetStockObject得到一个现有的画刷句柄
hBrush = GetStockObject (GRAY_BRUSH) ;
3,呼叫SelectObject选入设备上下文
SelectObject (hdc, hBrush) ;
如果您想画一个没有边界框的图形
,可以将NULL_PEN选进装置内容:
如果您想画出图形的边界框,但不填入内部,则将NULL_BRUSH选进装置内容:
24,画多边形
Polygon (hdc, apt, iCount) ;
绘制多个多边形
PolyPolygon (hdc, apt, aiCounts, iPolyCount) ;
使用下面的函数设置多边形的填入方式
SetPolyFillMode (hdc, iMode) ;
25,可以使用下面五个函数建立逻辑画刷
hBrush = CreateSolidBrush (crColor) ;
hBrush = CreateHatchBrush (iHatchStyle, crColor) ;
hBrush = CreateBrushIndirect (&logbrush) ;
26,可以用下面的方法设置映射方式:
SetMapMode (hdc, iMapMode) ;
可以通过
iMapMode = GetMapMode (hdc) ;
获得当前的映射方式
27,下面的函数可以将装置点转换为逻辑点
DPtoLP (hdc, pPoints, iNumber) ;
下面的函式将逻辑点转换为装置点:
LPtoDP (hdc, pPoints, iNumber) ;
例如,假设显示区域为cxClient个图素宽和cyClient个图素高。如果想将逻辑点(0,0)定义为显示区域的中心,可进行如下呼叫:
SetViewportOrgEx (hdc, cxClient / 2, cyClient / 2, NULL) ;
SetViewportOrgEx的参数总是使用装置单位。现在,逻辑点(0,0)将映射为装置点(cxClient/2,cyClient/2),
用下面的SetWindowOrgEx叙述可以获得与上面使用SetViewportOrgEx同样的效果:
SetWindowOrgEx (hdc, -cxClient / 2, -cyClient / 2, NULL) ;
28,您可以使用下面两个函式取得目前视埠和视窗的原点:
GetViewportOrgEx (hdc, &pt) ;
GetWindowOrgEx (hdc, &pt) ;
其中pt是POINT结构。由GetViewportOrgEx传回的值是装置座标,而由GetWindowOrgEx传回的值是逻辑座标。
29,ract有四个成员left、top、right和bottom
可以通过呼叫下面的函数来方便的设置RECT的值
SetRect (&rect, xLeft, yTop, xRight, yBottom) ;
将矩形沿x轴和y轴移动几个单元:
OffsetRect (&rect, x, y) ;
增减矩形的尺寸:
InflateRect (&rect, x, y) ;
矩形各成员设定为0:
SetRectEmpty (&rect) ;
将矩形复制给另一个矩形:
CopyRect (&DestRect, &SrcRect) ;
取得两个矩形的交集:
IntersectRect (&DestRect, &SrcRect1, &SrcRect2) ;
取得两个矩形的并集:
UnionRect (&DestRect, &SrcRect1, &SrcRect2) ;
确定矩形是否为空:
bEmpty = IsRectEmpty (&rect) ;
确定点是否在矩形内:
bInRect = PtInRect (&rect, point) ;
30,PeekMessage (&msg, NULL, 0, 0, PM_REMOVE) ;
31,剪裁区域
hRgn = CreateRectRgn (xLeft, yTop, xRight, yBottom) ;
或
hRgn = CreateRectRgnIndirect (&rect) ;
也可以弄一个椭圆的剪裁区域
hRgn = CreateEllipticRgn (xLeft, yTop, xRight, yBottom) ;
或
hRgn = CreateEllipticRgnIndirect (&rect) ;
使用CreateRoundRectRgn建立圆角矩形剪裁区域
建立多边形剪裁区域
hRgn = CreatePolygonRgn (&point, iCount, iPolyFillMode) ;
iRgnType = CombineRgn (hDestRgn, hSrcRgn1, hSrcRgn2, iCombine) ;
这一函式将两个剪裁区域(hSrcRgn1和hSrcRgn2)组合起来并用代号hDestRgn指向组合成的剪裁区域。这三个剪裁区域代号都必须是有效的,
32,通过GetUpdateRect可以知道失效举行的坐标
位图
1,创建位图的方法基本都会返回一个HBITMAP句柄,betmap和画笔画刷一样需要删除和选择
创建位图的第一个方法
HBITMAP CreateBitmap( int nWidth, int nHeight, UINT cPlanes, UINT cBitsPerPel, CONST VOID *lpvBits );
cPlanes:指明色彩平面数。
cBitsPerPel:指明每个像素的颜色用多少位来表示,它和上一个参数可以通过GetDeviceCaps函数用PLANES 和BITSPIXEL标识符来获得。
lpvBits:指向DDB像素位数组的指针,该数组的每行为偶数字节,记录位图像素的色彩信息。单色位图的每个像素仅需一位,这里不做详述。
第二种方法:
HBITMAP CreateBitmapIndirect(CONST BITMAP *lpbm );
lpbm:指向BITMAP结构的指针,该结构记录了已创建的DDB位图的全部主要信息,它的域与CreateBitmap函数的参数对应,如下所示。
第三种
HBITMAP CreateCompatibleBitmap( HDC hdc, int nWidth, int nHeight ) ;
hdc:不仅是指显示设备描述表,还可以是内存设备描述表,这在下一小节的实例程序screensnap中,将看到这个函数的用法。
nWidth:指位图的宽度。
nHeight:指位图的高度。
3,创建内存描述表很容易,只要根据某个实际设备的设备描述表句柄使用CreateCompatibleDC函数即可完成。例如:
hdcMem = CreateCompatibleDC(hdc);
网站备案号: 京ICP备19050865号