1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > MFC对话框最大化/窗口化及控件自适应缩放以及嵌套窗口缩放

MFC对话框最大化/窗口化及控件自适应缩放以及嵌套窗口缩放

时间:2023-09-29 02:09:45

相关推荐

MFC对话框最大化/窗口化及控件自适应缩放以及嵌套窗口缩放

1. 实现方法(计算窗口放大/缩小比例,控件相应缩放并改变位置,但会存在一定问题)

先在窗口类的头文件中添加相应变量与函数(其中OnSize由类向导消息WM_SIZE生成):

// XXXDlg.h// 窗口放大所需变量private:BOOL m_IsInitialized;int m_nOldCx, m_nOldCy; // 变量需要在类的构造函数中初始化public:// 改变窗口大小void ReSize(int cx, int cy);afx_msg void OnSize(UINT nType, int cx, int cy);

实现文件中函数定义为如下:

// XXXDlg.cppBOOL CXXXDlg::OnInitDialog(){CDialogEx::OnInitDialog();// TODO: 在此添加额外的初始化// 窗口初始化大小保存// 保存窗口初始大小CRect m_windowedRect;GetClientRect(&m_windowedRect);m_nOldCx = m_windowedRect.Width();m_nOldCy = m_windowedRect.Height();// 初始化完毕flagm_IsInitialized = TRUE;return TRUE; // return TRUE unless you set the focus to a control// 异常: OCX 属性页应返回 FALSE}// 改变窗口大小void CXXXDlg::ReSize(int cx, int cy){//计算窗口比率float fspx = (float)cx / m_nOldCx;float fspy = (float)cy / m_nOldCy;CRect rect; //获取子窗口(控件)CWnd * pWnd = this->GetWindow(GW_CHILD);while(pWnd != NULL){pWnd->GetWindowRect(&rect);this->ScreenToClient(&rect);//重新计算控件位置和大小int nNewx = (int)(rect.left * fspx);int nNewy = (int)(rect.top * fspy);int nNewWidth = (int)(rect.Width() * fspx);int nNewHeight = (int)(rect.Height() * fspy);//调整控件pWnd->MoveWindow(nNewx, nNewy, nNewWidth, nNewHeight);//获取下一个子窗口(控件)pWnd = pWnd->GetWindow(GW_HWNDNEXT);}}void CXXXDlg::OnSize(UINT nType, int cx, int cy){CDialogEx::OnSize(nType, cx, cy);// TODO: 在此处添加消息处理程序代码if (m_IsInitialized && (nType==SIZE_RESTORED || nType==SIZE_MAXIMIZED)){ReSize(cx, cy);m_nOldCx = cx;m_nOldCy = cy;Invalidate();//更新窗口 }}

但是这种方法存在一个问题,在来回缩放多次后,由于double转int的精度丢失导致控件会逐渐变小直至消失,如下图:

窗口缩放前控件大小

多次缩放后控件变小

下面采用一种改进的方法来解决这个问题。

解决方案:在第一次放大和第一次缩小的时候分别使用两个vector容器来遍历记录所有控件的位置和大小信息,下面贴代码。

首先定义一个控件位置的结构体:

typedef struct ControlPos{int Top;int Left;int CtrlWidth;int CtrlHeight;} ControlPos;

然后在需要进行自适应缩放窗口的头文件中添加如下变量:

// XXXDlg.h#include <vector>// 窗口放大所需变量private:BOOL m_IsInitialized;int m_nOldCx, m_nOldCy;int m_maxedCx, m_maxedCy;bool m_IsMaxed;// 窗口化控件位置std::vector<ControlPos> m_vecWindowedControl;// 最大化时控件位置std::vector<ControlPos> m_vecMaxedControl;public:// 改变窗口大小void ReSize(int cx, int cy);afx_msg void OnSize(UINT nType, int cx, int cy);

相应的需要在构造函数中进行初始化:

// XXXDlg.cppCXXXDlg::CXXXDlg(CWnd* pParent /*=NULL*/): CDialogEx(CXXXDlg::IDD, pParent), m_nOldCx(0), m_nOldCy(0), m_IsInitialized(false), m_maxedCx(0), m_maxedCy(0), m_IsMaxed(false){}

然后下面是实现函数(OnSize函数是在类向导中的WM_SIZE消息添加的):

// XXXDlg.cpp// 改变窗口大小void CDownViewDlg::ReSize(int cx, int cy){//计算窗口比率float fspx = (float)cx / m_nOldCx;float fspy = (float)cy / m_nOldCy;CRect rect; //获取子窗口(控件)CWnd * pWnd = this->GetWindow(GW_CHILD);while(pWnd != NULL){pWnd->GetWindowRect(&rect);this->ScreenToClient(&rect);//重新计算控件位置和大小int nNewx = (int)(rect.left * fspx);int nNewy = (int)(rect.top * fspy);int nNewWidth = (int)(rect.Width() * fspx);int nNewHeight = (int)(rect.Height() * fspy);// 信息赋给结构体ControlPos windowedCtrl, maxedCtrl;windowedCtrl.Left = rect.left;windowedCtrl.Top = rect.top;windowedCtrl.CtrlWidth = rect.Width();windowedCtrl.CtrlHeight = rect.Height();maxedCtrl.Left = nNewx;maxedCtrl.Top = nNewy;maxedCtrl.CtrlWidth = nNewWidth;maxedCtrl.CtrlHeight = nNewHeight;// 位置信息加入新旧容器m_vecWindowedControl.push_back(windowedCtrl);m_vecMaxedControl.push_back(maxedCtrl);//调整控件pWnd->MoveWindow(nNewx, nNewy, nNewWidth, nNewHeight);//获取下一个子窗口(控件)pWnd = pWnd->GetWindow(GW_HWNDNEXT);}}void CDownViewDlg::OnSize(UINT nType, int cx, int cy){CDialogEx::OnSize(nType, cx, cy);// TODO: 在此处添加消息处理程序代码if (m_IsInitialized && (nType==SIZE_RESTORED || nType==SIZE_MAXIMIZED)){if (!m_IsMaxed){m_maxedCx = cx;m_maxedCy = cy;ReSize(cx, cy);Invalidate();//更新窗口 #ifdef _CAMclose_window(m_lowHWindowID);close_window(m_highHWindowID);OpenWindow();OnBnClickedResetlowimage();OnBnClickedResethighimage();#endifm_IsMaxed = true;}else{if (cx == m_maxedCx){CRect rect; int i = 0; //当做迭代器,把每个控件位置取出//获取子窗口(控件)CWnd * pWnd = this->GetWindow(GW_CHILD);while(pWnd != NULL){pWnd->GetWindowRect(&rect);this->ScreenToClient(&rect);//调整控件pWnd->MoveWindow(m_vecMaxedControl[i].Left, m_vecMaxedControl[i].Top, m_vecMaxedControl[i].CtrlWidth, m_vecMaxedControl[i].CtrlHeight);i+=1; // 迭代器后移//获取下一个子窗口(控件)pWnd = pWnd->GetWindow(GW_HWNDNEXT);}#ifdef _CAMclose_window(m_lowHWindowID);close_window(m_highHWindowID);OpenWindow();OnBnClickedResetlowimage();OnBnClickedResethighimage();#endif}else{CRect rect; int i = 0; //当做迭代器,把每个控件位置取出//获取子窗口(控件)CWnd * pWnd = this->GetWindow(GW_CHILD);while(pWnd != NULL){pWnd->GetWindowRect(&rect);this->ScreenToClient(&rect);//调整控件pWnd->MoveWindow(m_vecWindowedControl[i].Left, m_vecWindowedControl[i].Top, m_vecWindowedControl[i].CtrlWidth, m_vecWindowedControl[i].CtrlHeight);i+=1; // 迭代器后移//获取下一个子窗口(控件)pWnd = pWnd->GetWindow(GW_HWNDNEXT);}}}}}

这样在后续的放大/缩小中就不会因为精度的丢失而造成控件消失的情况了!

2. 升级版

最近在帮师兄做这个页面缩放的时候遇到了问题,由于师兄的页面是由一个主页面(主页面内只有Tab控件)加上两个选项卡页面构成的,所以在代码中先对主页面进行缩放,然后再对下属页面进行上述方法的缩放(下属页面会在主页面调用切换时自动调用OnSize函数进行缩放,具体可加断点查看),具体实现较为复杂,下面贴出代码供参考(还存在一个小BUG):

(这段代码仅供参考,因为有很多与缩放不相关的函数没有删掉)

// XXXDlg.cpp// 这个cpp是主页面(选项卡页面)的实现文件// 其余部分与上述方法都一样// 头文件定义private:// 对话框切换Tab控件CTabCtrl m_Tab;CRect m_old;bool m_isFirstOpen;bool m_isFirstMax;bool m_isFirstWindow;// 窗口化控件位置std::vector<ControlPos> m_vecWindowedControl;// 最大化时控件位置std::vector<ControlPos> m_vecMaxedControl;public:afx_msg void OnSize(UINT nType, int cx, int cy);void ReSize(UINT nType, int cx, int cy);// 构造函数CDropViewDlg::CDropViewDlg(CWnd* pParent /*=NULL*/): CDialogEx(CDropViewDlg::IDD, pParent), m_isFirstOpen(false), m_isFirstMax(false), m_isFirstWindow(false){}void CDropViewDlg::OnSize(UINT nType, int cx, int cy){CDialogEx::OnSize(nType, cx, cy);// TODO: 在此处添加消息处理程序代码if (nType == 1){return;}if (nType == 0)//第一次启动对话框时的大小变化不做处理 { if (!m_isFirstOpen){m_isFirstOpen = true;return;}else{if (!m_isFirstWindow){ReSize(nType, cx, cy);CRect TabRect;m_Tab.GetClientRect(&TabRect);TabRect.left+=1;TabRect.right-=1;TabRect.top+=25;TabRect.bottom-=1;m_DlgView.OnSize(nType,cx,cy);switch (m_Tab.GetCurSel()) { case 0: m_DlgView.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_SHOWWINDOW);m_DlgResult.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_HIDEWINDOW);break; case 1: m_DlgView.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_HIDEWINDOW);m_DlgResult.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_SHOWWINDOW);break; default: break; } CRect rect; m_DlgView.m_ListTrigger.GetClientRect(&rect); m_DlgView.m_ListTrigger.SetExtendedStyle(m_DlgView.m_ListTrigger.GetExtendedStyle() | LVS_EX_GRIDLINES |LVS_EX_FULLROWSELECT); m_DlgView.m_ListTrigger.InsertColumn(0, _T("参数"), LVCFMT_CENTER, rect.Width()/3, 0); m_DlgView.m_ListTrigger.InsertColumn(1, _T("采集1"), LVCFMT_CENTER, rect.Width()/3, 1); m_DlgView.m_ListTrigger.InsertColumn(2, _T("采集2"), LVCFMT_CENTER, rect.Width()/3, 2); Invalidate();//更新窗口 m_isFirstWindow = true;}else{CRect rect; int i = 0; //当做迭代器,把每个控件位置取出//获取子窗口(控件)CWnd * pWnd = this->GetWindow(GW_CHILD);while(pWnd != NULL){pWnd->GetWindowRect(&rect);this->ScreenToClient(&rect);//调整控件pWnd->MoveWindow(m_vecWindowedControl[i].Left,m_vecWindowedControl[i].Top, m_vecWindowedControl[i].CtrlWidth, m_vecWindowedControl[i].CtrlHeight);i+=1; // 迭代器后移//获取下一个子窗口(控件)pWnd = pWnd->GetWindow(GW_HWNDNEXT);}CRect TabRect;m_Tab.GetClientRect(&TabRect);TabRect.left+=1;TabRect.right-=1;TabRect.top+=25;TabRect.bottom-=1;//m_DlgView.OnSize(nType,cx,cy);//m_DlgResult.OnSize(nType,cx,cy);switch (m_Tab.GetCurSel()) { case 0: m_DlgView.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_SHOWWINDOW);m_DlgResult.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_HIDEWINDOW);break; case 1: m_DlgView.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_HIDEWINDOW);m_DlgResult.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_SHOWWINDOW);break; default: break; } //CRect rect; m_DlgView.m_ListTrigger.GetClientRect(&rect); m_DlgView.m_ListTrigger.SetExtendedStyle(m_DlgView.m_ListTrigger.GetExtendedStyle() | LVS_EX_GRIDLINES |LVS_EX_FULLROWSELECT); m_DlgView.m_ListTrigger.InsertColumn(0, _T("参数"), LVCFMT_CENTER, rect.Width()/3, 0); m_DlgView.m_ListTrigger.InsertColumn(1, _T("采集1"), LVCFMT_CENTER, rect.Width()/3, 1); m_DlgView.m_ListTrigger.InsertColumn(2, _T("采集2"), LVCFMT_CENTER, rect.Width()/3, 2); Invalidate();//更新窗口 }}// 缩小时候ntype==0,这里在第一次打开窗口时候也会进入,所以要放置一个变量判断是否第一次打开窗口} else { if (!m_isFirstMax){ReSize(nType, cx, cy);CRect TabRect;m_Tab.GetClientRect(&TabRect);TabRect.left+=1;TabRect.right-=1;TabRect.top+=25;TabRect.bottom-=1;//m_DlgView.OnSize(nType,cx,cy);switch (m_Tab.GetCurSel()) { case 0: m_DlgView.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_SHOWWINDOW);m_DlgResult.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_HIDEWINDOW);break; case 1: m_DlgView.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_HIDEWINDOW);m_DlgResult.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_SHOWWINDOW);break; default: break; } CRect rect; m_DlgView.m_ListTrigger.GetClientRect(&rect); m_DlgView.m_ListTrigger.SetExtendedStyle(m_DlgView.m_ListTrigger.GetExtendedStyle() | LVS_EX_GRIDLINES |LVS_EX_FULLROWSELECT); m_DlgView.m_ListTrigger.InsertColumn(0, _T("参数"), LVCFMT_CENTER, rect.Width()/3, 0); m_DlgView.m_ListTrigger.InsertColumn(1, _T("采集1"), LVCFMT_CENTER, rect.Width()/3, 1); m_DlgView.m_ListTrigger.InsertColumn(2, _T("采集2"), LVCFMT_CENTER, rect.Width()/3, 2); Invalidate();//更新窗口 m_isFirstMax = true;}else{CRect rect; int i = 0; //当做迭代器,把每个控件位置取出//获取子窗口(控件)CWnd * pWnd = this->GetWindow(GW_CHILD);while(pWnd != NULL){pWnd->GetWindowRect(&rect);this->ScreenToClient(&rect);//调整控件pWnd->MoveWindow(m_vecMaxedControl[i].Left, m_vecMaxedControl[i].Top, m_vecMaxedControl[i].CtrlWidth, m_vecMaxedControl[i].CtrlHeight);i+=1; // 迭代器后移//获取下一个子窗口(控件)pWnd = pWnd->GetWindow(GW_HWNDNEXT);}CRect TabRect;m_Tab.GetClientRect(&TabRect);TabRect.left+=1;TabRect.right-=1;TabRect.top+=25;TabRect.bottom-=1;//m_DlgView.OnSize(nType,cx,cy);//m_DlgResult.OnSize(nType,cx,cy);switch (m_Tab.GetCurSel()) { case 0: m_DlgView.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_SHOWWINDOW);m_DlgResult.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_HIDEWINDOW);break; case 1: m_DlgView.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_HIDEWINDOW);m_DlgResult.SetWindowPos(NULL,TabRect.left,TabRect.top,TabRect.Width(),TabRect.Height(),SWP_SHOWWINDOW);break; default: break; } //CRect rect; m_DlgView.m_ListTrigger.GetClientRect(&rect); m_DlgView.m_ListTrigger.SetExtendedStyle(m_DlgView.m_ListTrigger.GetExtendedStyle() | LVS_EX_GRIDLINES |LVS_EX_FULLROWSELECT); m_DlgView.m_ListTrigger.InsertColumn(0, _T("参数"), LVCFMT_CENTER, rect.Width()/3, 0); m_DlgView.m_ListTrigger.InsertColumn(1, _T("采集1"), LVCFMT_CENTER, rect.Width()/3, 1); m_DlgView.m_ListTrigger.InsertColumn(2, _T("采集2"), LVCFMT_CENTER, rect.Width()/3, 2); Invalidate();//更新窗口 }}}void CDropViewDlg::ReSize(UINT nType, int cx, int cy){float fspx = (float)cx / m_old.Width();float fspy = (float)cy / m_old.Height();CRect rect; //获取子窗口(控件)CWnd * pWnd = this->GetWindow(GW_CHILD);while(pWnd != NULL){pWnd->GetWindowRect(&rect);this->ScreenToClient(&rect);//重新计算控件位置和大小int nNewx = (int)(rect.left * fspx);int nNewy = (int)(rect.top * fspy);int nNewWidth = (int)(rect.Width() * fspx);int nNewHeight = (int)(rect.Height() * fspy);// 信息赋给结构体ControlPos windowedCtrl, maxedCtrl;windowedCtrl.Left = rect.left;windowedCtrl.Top = rect.top;windowedCtrl.CtrlWidth = rect.Width();windowedCtrl.CtrlHeight = rect.Height();maxedCtrl.Left = nNewx;maxedCtrl.Top = nNewy;maxedCtrl.CtrlWidth = nNewWidth;maxedCtrl.CtrlHeight = nNewHeight;// 位置信息加入新旧容器m_vecWindowedControl.push_back(windowedCtrl);m_vecMaxedControl.push_back(maxedCtrl);//调整控件pWnd->MoveWindow(nNewx, nNewy, nNewWidth, nNewHeight);//获取下一个子窗口(控件)pWnd = pWnd->GetWindow(GW_HWNDNEXT);}}

然后是剩下两个下属页面的缩放,与1中的实现相同,这个最主要的问题在于先缩放主页面,然后在主页面缩放的过程中会对下属页面进行缩放。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。