【写在前面】

平常在编写界面程序时,使窗口中的控件随窗口大小改变而改变,只需调用WM_SIZE消息,在消息函数OnSize中进行处理,比如如下函数,就是使静态文本控件动态变化,但是这种方法计算繁琐不说,在改变控件位置时,此部分又需要从新计算,相当麻烦,下面我来介绍一下另一种方法。

if (GetDlgItem(IDC_STATIC2))
     {
         CRect rt;
         GetClientRect(rt);
         rt.top = rt.bottom - 123;
         rt.bottom -=105;
        float x = (float)(rt.Width()*1.0/m_rect.Width());
         rt.left += 10;
         rt.right = (LONG)(rt.left + 80*x);
         GetDlgItem(IDC_STATIC2)->MoveWindow(rt);
     }

【方法】注:此方法考验理解能力,目前我也只能理解很浅显的部分,大家可以在评论区交流,谈谈自己的理解,我会逐步更新博文。

1.将Resizer.h以及Resizer.cpp添加至工程中。

2.在对话框窗口的头文件(.h文件)中添加#include "Resizer.h"以及CResizer m_resizer;

3. 将以下代码段插入对话框窗口源文件(.cpp文件)的配置函数(OnInitDialog())中,更改方法是,将数组中IDC_STATIC1等控件的ID号改成自己的;IDC_MAIN是参考坐标,可以更换成自己需要的参考坐标控件ID,但是最好慎重。eTop等根据需要更改。

我来说一下数组中IDC_STATIC1控件,

第一行以IDC_MAIN为参考坐标,将控件的顶部(eTop)固定(eFixed);

第二行以IDC_MAIN为参考坐标,将控件的左部(eLeft)固定(eFixed);

第三行以IDC_MAIN为参考坐标,将控件的右部(eRight)等宽(eWidth);

第四行以IDC_MAIN为参考坐标,将控件的顶部(eTop)等高(eHeight);

这四句的作用是将控件IDC_STATIC控件大小不变,固定在控件初始位置上。

static CResizer::CBorderInfo s_bi[] = {{ IDC_STATIC1,{ CResizer::eFixed, IDC_MAIN, CResizer::eTop },  //1{ CResizer::eFixed, IDC_MAIN, CResizer::eLeft },  //2{ CResizer::eWidth, IDC_MAIN, CResizer::eRight }, //3{ CResizer::eHeight, IDC_MAIN, CResizer::eTop } }, //4{ IDC_STATIC2,{ CResizer::eFixed, IDC_MAIN, CResizer::eTop },{ CResizer::eFixed, IDC_MAIN, CResizer::eLeft },{ CResizer::eWidth, IDC_MAIN, CResizer::eRight },{ CResizer::eHeight, IDC_MAIN, CResizer::eTop } },{ IDC_STATIC3,{ CResizer::eFixed, IDC_MAIN, CResizer::eTop },{ CResizer::eFixed, IDC_MAIN, CResizer::eLeft },{ CResizer::eWidth, IDC_MAIN, CResizer::eRight },{ CResizer::eHeight, IDC_MAIN, CResizer::eTop } },};const int nSize = sizeof(s_bi) / sizeof(s_bi[0]);
//Second we initialize resizer with this array.
//At the same time it will store the original controls positions.
m_resizer.Init(m_hWnd, NULL, s_bi, nSize);

4.将m_resizer.Move();填写在OnSize()函数中

至此程序就编写完了,主要更改的就是配置函数中static CResizer::CBorderInfo s_bi[]数组。可以根据需要更改数组的参考坐标。

【写在最后】

在使用这个方法时,需要较强的空间想象力,程序源代码例程有详细的使用方法我会传到我的资源中https://download.csdn.net/download/lifuran156/10710303,里边有示例软件https://download.csdn.net/download/lifuran156/10710316,可以看一下。Resizer.h以及Resizer.cpp文件放在结尾,

//Resizer.cpp
/******************************************************************************\
$Copyright: (C)2001 Dmitry Kochin <dco@mail.ru>
$Workfile: Resizer.cpp $
\******************************************************************************/
// Resizer.cpp: implementation of the CResizer class.
//
//
// Class to correctly move child windows after parent was resized
// Created: 06/07/01 by dukei@#include "stdafx.h"
#include "Resizer.h"#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif//
// Construction/Destruction
//CResizer::CResizer()
{memset(&m_rcInitial, 0, sizeof(m_rcInitial));m_vInfo = NULL;m_vRectInfo = NULL;m_nSize = 0;m_nCachedSize = 0;
}CResizer::~CResizer()
{Clear();
}void CResizer::Clear()
{delete [] m_vInfo;delete [] m_vRectInfo;m_vInfo = NULL;m_vRectInfo = NULL;m_nSize = 0;m_nCachedSize = 0;
}bool CResizer::Init(HWND hWndParent, LPCRECT rcInitial, const CBorderInfo *pBorders, int nSize)
{Clear();m_vInfo = new CControlInfo[nSize];m_nSize = nSize;m_wndParent = hWndParent;if(rcInitial == NULL)::GetClientRect(m_wndParent, &m_rcInitial);else::CopyRect(&m_rcInitial, rcInitial);for(int i = 0; i < m_nSize; i++){CControlInfo &ci = m_vInfo[i];ci.pInfo = pBorders + i;GetDlgItemRect(ci.pInfo->nID, ci.rcInitial);#ifdef _DEBUG//Make some debug checking//Check that no controls have reserved IDs//IDC_MAIN == 0 isn't allowed for control identifiers!//Set another control ID with CWindow::SetDlgCtrlID() or ::SetWindowLong(m_hWnd, GWL_ID, nID)!_ASSERTE(ci.pInfo->nID != IDC_MAIN);//Check that this control ID is unique.//ALL control identifiers MUST BE UNIQUE!!!for(int j = 0; j < i; j++){const CControlInfo &ciPrevious = m_vInfo[j];_ASSERTE(ciPrevious.pInfo->nID != ci.pInfo->nID); //Duplicated control ID!!!//Control j in initialization array has the same id as control i.}
#endif}return true;
}void CResizer::Move() const
{if(m_vRectInfo == NULL && m_nSize > 0)m_vRectInfo = new CRectInfo[m_nSize];for(int i = 0; i < m_nSize; i++){//Move(i) should be called always for i=0 to m_nSize!!//It is required by its implementation!Move(i);}MoveAndHideOverlapped();
}void CResizer::Move(int nIndex) const
{const CControlInfo &ci = m_vInfo[nIndex];CRectInfo &ri = m_vRectInfo[nIndex];m_nCachedSize = nIndex + 1; //Now m_vRectInfo contains nIndex + 1 valid itemsri.nID = ci.pInfo->nID;RECT &rc = ri.rc;rc.left = GetCoordinate(eLeft, ci.rcInitial, ci.pInfo->left, rc);rc.top = GetCoordinate(eTop, ci.rcInitial, ci.pInfo->top, rc);rc.right = GetCoordinate(eRight, ci.rcInitial, ci.pInfo->right, rc);rc.bottom = GetCoordinate(eBottom, ci.rcInitial, ci.pInfo->bottom, rc);HWND pCtl = GetDlgItem(ci.pInfo->nID);LONG dwStyle = ::GetWindowLong(pCtl, GWL_STYLE);ri.bVisible = (::IsWindowVisible(pCtl) != FALSE && (dwStyle & WS_CLIPSIBLINGS) == 0);ri.bHide = false;
}int CResizer::GetCoordinate(ESize eType, const RECT &rcInitial, const CBorder &border, const RECT &rc) const
{int nOld = GetRectCoord(eType, rcInitial);switch(border.eType){case eFixed:{//Get initial relative window positionRECT rc;GetInitialDlgItemRect(border.nRelID, rc);int nRelOld = GetRectCoord(border.eRelType, rc);//Get current relative window positionint nRelNew = GetRelativeCoord(border);//Compute and return new positionreturn nOld - nRelOld + nRelNew;}case eProportional:{//Get initial relative window positionRECT rcOld;GetInitialDlgItemRect(border.nRelID, rcOld);int nOldSize = GetRectSize(eType, rcOld);int nOldBase = GetRectCoord(border.eRelType, rcOld);//Get current relative window positionRECT rcNew;GetCachedDlgItemRect(border.nRelID, rcNew);int nNewSize = GetRectSize(eType, rcNew);int nNewBase = GetRectCoord(border.eRelType, rcNew);//Compute and return new positionreturn nNewBase + (nOld - nOldBase) * nNewSize / (nOldSize <= 0 ? 1 : nOldSize);}case eWidth:return rc.left + rcInitial.right - rcInitial.left;case eHeight:return rc.top + rcInitial.bottom - rcInitial.top;}_ASSERTE(FALSE); //Wrong relation type is specified. Use items from EBorder enum.return 0;
}int CResizer::GetRectCoord(ESize eType, const RECT &rc)
{switch(eType){case eLeft:return rc.left;case eTop:return rc.top;case eRight:return rc.right;case eBottom:return rc.bottom;case eXCenter:return (rc.right + rc.left) / 2;case eYCenter:return (rc.bottom + rc.top) / 2;}_ASSERTE(FALSE); //Wrong side is specified. Use items from ESize enum.return 0;
}int CResizer::GetRectSize(ESize eType, const RECT &rc)
{switch(eType){case eLeft:case eRight:case eXCenter:return rc.right - rc.left;case eTop:case eBottom:case eYCenter:return rc.bottom - rc.top;}_ASSERTE(FALSE); // Wrong side is specified. Use items from ESize enum.return 0;
}int CResizer::GetRelativeCoord(const CBorder &border) const
{RECT rc;GetCachedDlgItemRect(border.nRelID, rc);return GetRectCoord(border.eRelType, rc);
}void CResizer::GetDlgItemRect(int nID, RECT &rc) const
{switch(nID){case IDC_MAIN:::GetClientRect(m_wndParent, &rc);break;default:HWND pCtl = GetDlgItem(nID);::GetWindowRect(pCtl, &rc);POINT pt1, pt2;pt1.x = rc.left, pt1.y = rc.top;pt2.x = rc.right, pt2.y = rc.bottom;::ScreenToClient(m_wndParent, &pt1);::ScreenToClient(m_wndParent, &pt2);rc.left = pt1.x, rc.top = pt1.y, rc.right = pt2.x, rc.bottom = pt2.y;break;}
}void CResizer::GetCachedDlgItemRect(int nID, RECT &rc) const
{switch(nID){case IDC_MAIN:GetDlgItemRect(nID, rc);break;default:int i = FindCached(nID);rc = m_vRectInfo[i].rc;break;}
}void CResizer::GetInitialDlgItemRect(int nID, RECT &rc) const
{switch(nID){case IDC_MAIN:rc = m_rcInitial;break;default://Get initial relative window positionint i = Find(nID);rc = m_vInfo[i].rcInitial;break;}
}int CResizer::Find(int nID) const
{for(int i = 0; i < m_nSize; i++){if(m_vInfo[i].pInfo->nID == nID)return i;}_ASSERTE(FALSE); //Possibly control id nID wasn't defined before it is used//as relative window. Read the TIP in the header file resizer.hreturn -1;
}int CResizer::FindCached(int nID) const
{for(int i = 0; i < m_nCachedSize; i++){if(m_vRectInfo[i].nID == nID)return i;}_ASSERTE(FALSE); //Possibly control id nID wasn't defined before it is used//as relative window. Read the TIP in the header file resizer.hreturn -1;
}void CResizer::MoveAndHideOverlapped() const
{_ASSERTE(m_nSize == m_nCachedSize);for(int i = 0; i < m_nSize; i++){CRectInfo &riSlave = m_vRectInfo[i];for(int j = 0; j < i; j++){const CRectInfo &riMaster = m_vRectInfo[j];//if senior window is visible and intersects with juniur, junior is to be hiddenif(riMaster.bVisible && riSlave.bVisible && !riSlave.bHide){RECT rc;::IntersectRect(&rc, &riMaster.rc, &riSlave.rc);riSlave.bHide = !::IsRectEmpty(&rc);}}//if the window doesn't intersect with seniors, it can be drawnHWND pCtl = GetDlgItem(riSlave.nID);
//        if(riSlave.bHide)
//            ::SetRectEmpty(&riSlave.rc);//SWP_NOCOPYBITS is obligatory, otherwise windows don't correctly redraw itselves::SetWindowPos(pCtl, NULL, riSlave.rc.left, riSlave.rc.top,riSlave.rc.right - riSlave.rc.left, riSlave.rc.bottom - riSlave.rc.top,SWP_NOCOPYBITS | SWP_NOZORDER);}
}
//Resizer.h
/******************************************************************************\
$Copyright: (C)2001 Dmitry Kochin <dco@mail.ru>
$Workfile: Resizer.h $
\******************************************************************************/// Resizer.h: interface for the CResizer class.
//
//
// Class to correctly move child windows after parent window was resized
// Created: 06/07/01 by dukei@
////An idea:
//
//Each child window side (left, top, right and bottom) is connected to a side of another window,
//so called relative window. It is tipically dialog window, that owns the child window.
//When dialog window is resized, child window sides are moved after the relative window,
//preserving the connections.
//
//Typical usage:
//
// 1. CResizer m_resizer is member variable;
//
// 2. Add the following code to OnInitDialog()
// (replacing control IDs to your specific ones).
// See array format description later in the comment
//
//  static CResizer::CBorderInfo s_bi[] = {
//    {IDC_CONTROL_ID,      {CResizer::eFixed, IDC_MAIN, CResizer::eLeft}, //Left side
//                          {CResizer::eFixed, IDC_MAIN, CResizer::eTop},  //Top side
//                          {CResizer::eFixed, IDC_MAIN, CResizer::eLeft}, //Right side
//                          {CResizer::eFixed, IDC_MAIN, CResizer::eTop}}, //Bottom side
//    {IDC_STATIC_ID,       {CResizer::eFixed, IDC_MAIN, CResizer::eLeft},
//                          {CResizer::eFixed, IDC_MAIN, CResizer::eTop},
//                          {CResizer::eFixed, IDC_MAIN, CResizer::eRight},
//                          {CResizer::eFixed, IDC_MAIN, CResizer::eTop}},
//  };
//  const nSize = sizeof(s_bi)/sizeof(s_bi[0]);
//  m_resizer.Init(m_hWnd, NULL, s_bi, nSize);
//
// 3. Add the following code to OnSize() handler
//
//  m_resizer.Move();
//
// 4. Everything should work now
//
// P.S. Data array format consists of one or more CBorderInfo structures, which contains
// moved control ID (first field) and four CBorder structures,
// for left, top, right and bottom sides of moved control accordingly.
//
// The main difficulty is to understand CBorder structure, which has the following format:
//
// {<how control side is connected to side of another window>, <another window id>,
//                  <side of another window, to which a control side is connected>}
//
//     CResizer::eFixed                                  CResizer::eLeft
//     CResizer::eProportional  IDC_MAIN                 CResizer::eTop
// or {CResizer::eWidth       , IDC_ANOTHER_CONTROL_ID , CResizer::eRight   }
//     CResizer::eHeight                                 CResizer::eBottom
//                                                       CResizer::eXCenter
//                                                       CResizer::eYCenter
//
// For example, {CResizer::eFixed, IDC_MAIN, CResizer::eLeft} means, that moved control side is
// on the fixed distance (CResizer::eFixed) from left side (CResizer::eLeft) of dialog window (IDC_MAIN)
//
// Another example: {CResizer::eProportional, IDC_CONTROL_ID, CResizer::eLeft} means, that
// moved control side preserves relation (proportionaly) (CResizer::eProportional)
// to the width (CResizer::eLeft or CResizer::eRight) of control IDC_CONTROL_ID.
//
// TIP: Resizer resizes controls in the order they are defined in the array, so
// <another window id> should always be defined (and, therefore, moved by the resizer) before
// it is used as relative window. Otherwise, resizer ASSERTs.#pragma once#define IDC_MAIN 0   //Parent dialog ID to be relative windowclass CResizer
{
public:enum EBorder{eFixed = 1,  //Given distance to specified window sideeProportional, //Coordinate is changed proportionally to width/height of specified windoweWidth,   //The width is preserved (relative window and window side are ignored)eHeight,  //The height is preserved (relative window and window side are ignored)};enum ESize{eLeft = 1,  //Relative to left sideeTop,       //TopeRight,     //RighteBottom,    //BottomeXCenter,   //The center of widtheYCenter    //The center of height};struct CBorder{EBorder eType;  //Type of relation to relative control sideint nRelID;     //Relative controlESize eRelType; //Side of relative control};struct CBorderInfo{int nID;         //Control IDCBorder left;CBorder top;CBorder right;CBorder bottom;};private:struct CControlInfo{RECT rcInitial; //initial control position;const CBorderInfo *pInfo;};struct CRectInfo{int nID;       //Control IDRECT rc;      //New control rectbool bVisible; //If control is visiblebool bHide;    //If control should be hidden because it overlaps senior control};HWND m_wndParent;RECT m_rcInitial; //Initial window client areatypedef CControlInfo *TInfo;typedef CRectInfo *TRectInfo;TInfo m_vInfo;int m_nSize; //Size of m_vInfo arraymutable TRectInfo m_vRectInfo;mutable int m_nCachedSize; //Size of m_vRectInfoprotected:HWND GetDlgItem(int nID) const{return ::GetDlgItem(m_wndParent, nID);}void GetDlgItemRect(int nID, RECT &rc) const;void GetCachedDlgItemRect(int nID, RECT &rc) const;void GetInitialDlgItemRect(int nID, RECT &rc) const;void Move(int nIndex) const;int GetCoordinate(ESize eType, const RECT &rcInitial, const CBorder &border, const RECT &rc) const;static int GetRectCoord(ESize eType, const RECT &rc);static int GetRectSize(ESize eType, const RECT &rc);int GetRelativeCoord(const CBorder &border) const;int Find(int nID) const;int FindCached(int nID) const;void MoveAndHideOverlapped() const;void Clear();public://Initializes resizerbool Init(HWND hWndParent, LPCRECT rcInitial, const CBorderInfo *pBorders, int nSize);//Performs moving of controlsvoid Move() const;//Just constructorCResizer();//Just destructor~CResizer();
};

MFC界面设计----改变界面大小使其中控件随其界面大小变化的方法相关推荐

  1. android水果界面设计,一套小清新的水果元素的APP界面设计欣赏

    这套小清新的而可爱风格的的APP名字叫:\"Fresh It Up\" – App Design 这套APP设计图来自国外设计网站behance. \"Fresh It ...

  2. C#中纯代码实现界面设计,不受VS中的拖拽图像界面限制

    第一步:需要了解的基本知识 NativeWindow:该类自动管理窗口类的创建和注册.当窗口与窗口句柄关联时,该窗口不适合进行垃圾收集.为了确保正确的垃圾回收,必须使用DestroyHandle手动销 ...

  3. python界面设计实例-Python GUI项目实战:主窗体的界面设计与实现

    一.基础 from tkinter import * from tkinter.ttk import * import os class MainWindow(Tk): def __init__(se ...

  4. MFC—界面设计(控件自适应,添加背景图,Static背景颜色设置)

    1.控件随着窗口自适应 首先在类视图里面添加OnSize()函数,然后添加一个ChangeSize()函数,头文件中添加如下 //控件自适应变量POINT old;CRect m_rect;void ...

  5. 第二章 VB的界面设计

    轉自:http://wwww.hyit.edu.cn/edu/vb/study/index.htm 第二章         VB的界面设计 2.1  VB用户界面设计基础 1. 概述 界面的设计有两步 ...

  6. Python-Tkinter图形化界面设计(详细教程 )

    原文链接:https://www.jianshu.com/p/91844c5bca78 声明:本篇文章为转载自https://www.jianshu.com/p/91844c5bca78,在原作者的基 ...

  7. 一个好的界面设计应该注意的 75 个原则

    一个好的界面设计应该拥有高转化率且方便用户使用,换句话说:既能达到商业目的又能满足方便易用的要求. 有一个设计咨询公司根据自己的客户案例,总结了 75 个经过实践证明的原则: 之前国内流传这篇文章的前 ...

  8. 一个好的界面设计应该注意的75个原则

    转载: http://www.xueui.cn/experience/app-experience/75-principles-of-excellent-interface-design.html 一 ...

  9. 关于游戏交互界面设计的几点思考

    接口数据流 玩家所体验的游戏世界其实是在他们的脑海中的,而玩家融入进游戏所通过的界面,就是交互界面.交互界面的设计目标就是让玩家「感到」他能够自如地控制自己的体验. 上图是一个简单的映射图,我修改了一 ...

最新文章

  1. 8086为什么不用c语言,现代汇编教材还是基于8086,对理解当今CPU(如i9)有帮助吗,还是教程太滞...
  2. 【C++】 64_C++中的异常处理 (上)
  3. 170万奖金扶持 华为云究竟在下一盘怎样的棋?
  4. android log丢失(一)使用logd丢失log原理
  5. HTML5 Web Worker
  6. 如何在Java中将数组转换为列表
  7. c# 正则表达式笔记
  8. POJ 2255/递归:前序中序求后序
  9. 正式举报林-裴 (1999) 论文涉嫌学术不端
  10. SysUtils.StrLCat
  11. asp.net mvc bundle中数组超出索引
  12. 【C++ 程序】 解线性方程组(Cramer法则)
  13. 基于片内Flash的提示音播放程序
  14. win7电脑屏幕亮度怎么调节
  15. LabVIEW编程技巧:手把手教你实现基于状态机的程序框架架构
  16. php滑动拼图验证,如何在PHP环境下实现滑动拼图验证
  17. 1.Android稳定性测试
  18. 杰理之设置恒流充电电流【篇】
  19. erp软件的主要功能
  20. 精尽Spring Boot源码分析 - 内嵌Tomcat容器的实现

热门文章

  1. 计算机应用对教学的影响,计算机应用教学存在的主要问题及对策
  2. 智慧城市挺进“绿色”时代
  3. lingo输出解的解释
  4. AutoCAD2012从入门到精通中文视频教程 第21课 偏移与镜像(个人收藏)
  5. Revit 中注释族的应用详解及公共族库工具
  6. 解决双系统出现的windows时间错误
  7. java堆栈、gc、dump文件在线分析
  8. 亚马逊 ec2 连接不上_在Amazon EC2上轻松进行蓝绿色部署
  9. Sqlite数据库管理工具
  10. Mysql快速备份_sql备份