透明字体,改变时发生文本重叠,解决办法是刷新窗体局部区域,该区域是文本或者按钮等控件的区域
Win32 API中使用InvalidateRect函数使指定区域失效,意味着要刷新该区域,再用UpdateWindow函数强迫窗体立即刷新
以100x30大小的静态文本控件为例,如何获得文本控件的区域?

GetClientRect和GetWindowRect两个函数可以获取控件区域
GetClientRect
检索窗口工作区的坐标。 客户端坐标指定工作区的左上角和右下角。 由于客户端坐标相对于窗口工作区的左上角,左上角的坐标 (0,0) 。
getWindowRect
检索指定窗口的边界矩形的尺寸。 尺寸以相对于屏幕左上角的屏幕坐标提供。
两个函数得到尺寸信息储存在RECT结构体中
RECT结构体
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT, *NPRECT, *LPRECT;
left
指定矩形左上角的 x 坐标。
top
指定矩形左上角的 y 坐标。
right
指定矩形右下角的 x 坐标。
bottom
指定矩形右下角的 y 坐标。
使用GetClientRect获取到的只是控件的尺寸,它的左上角坐标永远是(0,0),而右下角坐标为(100,30),如果使用此区域刷新窗体,那么会刷新父窗体上(0,0,100,30)的区域,显然是不能刷新到控件的位置
而使用GetWindowRect得到的是控件区域相对于屏幕的位置(700,300,100,30),使用此区域刷新父窗体也是错误的区域
有两个函数:ClientToScreen函数和ScreenToClient 函数
ClientToScreen 函数将指定点的工作区坐标转换为屏幕坐标。
ScreenToClient 函数将屏幕上指定点的屏幕坐标转换为工作区坐标。
通过ScreenToClient可以将屏幕位置上的点转换为相对于客户区位置的点,首先通过GetWindowRect函数获取控件区域左上角相对屏幕坐标,之后转化为相对于客户区的坐标就可以直到控件在客户区的位置。
RECT rc;
//获取控件在屏幕中位置
GetWindowRect(GetDlgItem(hWnd,controlID),&rc);
//将左上坐标转化成点
POINT p;
p.x = rc.left;
p.y = rc.top;
//将点坐标在屏幕位置转化成在客户区位置
ScreenToClient(hWnd,&p);
而控件的宽度可以通过GetClientRect函数获取,RECT的right - left和bottom - top就是控件的宽和高,
因此控件相对于客户区的区域就可以确定了
左上角:(p.x,p.y)
右下角(左上角坐标加控件的宽和高):(p.x + rc.right - rc.left,p.y + rc.bottom - rc.top)
之后在父窗体中刷新此区域就可以刷新到控件的实际位置
rc.right = p.x + rc.right - rc.left;
rc.left = p.x;
rc.bottom = p.y + rc.bottom - rc.top;
rc.top = p.y;
实际代码
void refresh_control(HWND hWnd,unsigned int controlID){
RECT rc;
//获取控件在屏幕中位置
GetWindowRect(GetDlgItem(hWnd,controlID),&rc);
//将左上坐标转化成点
POINT p;
p.x = rc.left;
p.y = rc.top;
//将点坐标在屏幕位置转化成在客户区位置
ScreenToClient(hWnd,&p);
//获取控件长宽
GetClientRect(GetDlgItem(hWnd,controlID),&rc);
//获取控件区域在客户区的相对位置
rc.right = p.x + rc.right - rc.left;
rc.left = p.x;
rc.bottom = p.y + rc.bottom - rc.top;
rc.top = p.y;
//刷新客户区控件位置
InvalidateRect(hWnd,&rc,true);
UpdateWindow(hWnd);
}