刚才花了点时间,写了几个通用函数,实现对话框内控件的自动缩放.现在把源代码贴出来。
数据结构定义
1)定义链表结构来存放各子窗口的矩形
typedef struct tagRectLinkNode
{
HWND hChild;
RECT rect;
ListNode node; //这个用的是封装的链表结点结构
}WndRectLinkNode_T;
typedef struct tagRectLink
{
ListNode head; //头结点
sa_int node_cnt;//sa_int 类型, 即typedef 重定义的int类型
}RectLink_T;
2)定义自动缩放用到的数据结构.
这个结构在三个地方用到: WM_INITDIALOG 中生成它, WM_DESTROY响应中释放它,WM_SIZE响应中使用它
typedef struct tagResizeCtrlInfo
{
HWND hParent; //修改
sa_int initWidthParent;
sa_int initHeightParent;
sa_int widthParent;
sa_int heightParent;
RectLink_T tRectLink;
}ResizeCtrlInfo_T;
函数实现
SA_CreateResizeCtrlInfo
SA_CreateResizeCtrlInfo在WM_INITDIALOG 消息响应的最后调用,为什么要放到最后?因为有人会在WM_INITDIALOG消息响应中动态创建控件,或改变控件位置. 如果你没有这样做,那放在WM_INITDIALOG 消息响应的任何地方都所谓。注意保存这个函数返回的结构指针,并在适当的地方( 如响应WM_DESTROY时)调用我后面提供的函数释放它.
ResizeCtrlInfo_T* SA_CreateResizeCtrlInfo(HWND hWnd)
{
ResizeCtrlInfo_T* ptInfo = NULL;
RECT rect;
if(hWnd == NULL)
{
return NULL;
}
ptInfo = (ResizeCtrlInfo_T*)SA_MALLOC(sizeof(ResizeCtrlInfo_T));
INIT_LIST_HEAD(&(ptInfo->tRectLink.head)); //链表的初始化工作,你可以用你的链表替代
GetClientRect(hWnd,&rect);
ptInfo->widthParent = ptInfo->initWidthParent = SA_RECT_WIDTH(rect);
ptInfo->heightParent = ptInfo->initHeightParent = SA_RECT_HEIGHT(rect);
//枚举对话框内的所有子窗口,填充ResizeCtrlInfo_T结构
EnumChildWindows(hWnd,(WNDENUMPROC )SA_EnumResizeChildWndProc,(LPARAM)ptInfo);
return ptInfo;
}
SA_EnumResizeChildWndProc
static BOOL CALLBACK SA_EnumResizeChildWndProc(HWND hWnd,LPARAM lParam)
{
ResizeCtrlInfo_T* ptResizeInfo = (ResizeCtrlInfo_T*)lParam;
WndRectLinkNode_T *pRectNode=NULL;
RECT rect;
if(GetParent(hWnd)!=ptResizeInfo->hParent)
{
return TRUE; //只枚举子窗口,不枚举子窗口的晚辈了
}
GetWindowRect(hWnd,&rect);//得到屏幕坐标
//SA_ScreenRectToClient是我封装的将屏幕坐标转成窗口内的客户坐标
if(SA_ScreenRectToClient(GetParent(hWnd), &rect)
{
pRectNode = (WndRectLinkNode_T *)SA_MALLOC(sizeof(WndRectLinkNode_T));
pRectNode->hChild = hWnd;
CopyRect(&(pRectNode->rect),&rect);
List_InsertBefore(&(pRectNode->node),&(ptResizeInfo->tRectLink.head));//插入链表
(ptResizeInfo->tRectLink.node_cnt)++;
}
return TRUE;
}
SA_FreeResizeCtrlInfo 释放数据结构 ,传入指针的指针是为了将结构指针置NULL,避免调用者使用野指针
void SA_FreeResizeCtrlInfo(ResizeCtrlInfo_T** pptResizeCtrlInfo)
{
ListNode *p,*q;
WndRectLinkNode_T* pRectNode;
ResizeCtrlInfo_T *ptResizeCtrlInfo = NULL;
if(pptResizeCtrlInfo == NULL ||*pptResizeCtrlInfo ==NULL)
{
return;
}
ptResizeCtrlInfo = *pptResizeCtrlInfo;
List_ForEachSafe(p,q,&(ptResizeCtrlInfo->tRectLink.head))//链表遍历函数
{
pRectNode = List_Entry(p,WndRectLinkNode_T,node);//由链表结点得到数据结点
//把结点从链表中摘下来
List_Del(&pRectNode->node);
(ptResizeCtrlInfo->tRectLink.node_cnt)--;
//释放链表结点
SA_Safe_Free(pRectNode);
}
SA_Safe_Free(ptResizeCtrlInfo);
*pptResizeCtrlInfo = NULL;
}
SA_ResizeCtrl 在WM_SIZE中调用,widht/height是WM_SIZE消息 lParam传入的
void SA_ResizeCtrl(HWND hParent,ResizeCtrlInfo_T*ptResizeCtrlInfo,int width,int height)
{
ListNode *p;
WndRectLinkNode_T* pRectNode=NULL;
double width_scale=1;
double height_scale =1;
HDWP hdwp;
sa_int x;
sa_int y;
sa_int cx;
sa_int cy;
if(ptResizeCtrlInfo == NULL)
{
return;
}
if(width == 0 || height ==0)
{
ptResizeCtrlInfo->widthParent = width;
ptResizeCtrlInfo->heightParent = height;
return;
}
if(width == ptResizeCtrlInfo->widthParent &&
height == ptResizeCtrlInfo->heightParent)
{
return;
}
ptResizeCtrlInfo->widthParent = width;
ptResizeCtrlInfo->heightParent = height;
if(ptResizeCtrlInfo->initWidthParent == 0 ||
ptResizeCtrlInfo->initHeightParent ==0)
{
ptResizeCtrlInfo->initWidthParent = ptResizeCtrlInfo->widthParent;
ptResizeCtrlInfo->initHeightParent = ptResizeCtrlInfo->heightParent;
EnumChildWindows(hParent,(WNDENUMPROC )SA_EnumResizeChildWndProc,(LPARAM)ptResizeCtrlInfo);
return;
}
if(ptResizeCtrlInfo->tRectLink.node_cnt==0)
{
return;
}
width_scale = (double)width /(double)ptResizeCtrlInfo->initWidthParent;
height_scale = (double)height/(double)ptResizeCtrlInfo->initHeightParent;
hdwp = BeginDeferWindowPos (ptResizeCtrlInfo->tRectLink.node_cnt);
List_ForEach(p,&(ptResizeCtrlInfo->tRectLink.head)) //遍历链表
{
pRectNode = List_Entry(p,WndRectLinkNode_T,node);
x = (sa_int)(pRectNode->rect.left * width_scale);
y = (sa_int)(pRectNode->rect.top * height_scale);
cx = (sa_int)(SA_RECT_WIDTH(pRectNode->rect) * width_scale);
cy = (sa_int)(SA_RECT_HEIGHT(pRectNode->rect) * height_scale);
//DeferWindowPos(hdwp,pRectNode->hChild,HWND_TOP,x,y,cx,cy,SWP_NOZORDER);
if (hdwp)
{
hdwp =DeferWindowPos(hdwp,pRectNode->hChild,HWND_TOP,x,y,cx,cy,SWP_NOZORDER);
}
}
//EndDeferWindowPos(hdwp);
if (hdwp)
{
EndDeferWindowPos(hdwp);
}
}
就这么几个函数,是不是很简单?