SDK实现自动改变控件位置和大小的函数

时间:2022-08-21 03:47:28

刚才花了点时间,写了几个通用函数,实现对话框内控件的自动缩放.现在把源代码贴出来。

数据结构定义

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);
 }
}

 就这么几个函数,是不是很简单?