mfc控件位置随对话框窗口移动
ControlPos.h代码
//------------------------------------------------------------------------------ // ControlPos.h // // CControlPos // Position controls on a form's resize // // Copyright (c) 2000 Paul Wendt // // VERSION# DATE NAME DESCRIPTION OF CHANGE // -------- ---------- ---- --------------------- // 1.01 07/11/2000 PRW Original creation. // #ifndef CONTROLPOS_H_ #define CONTROLPOS_H_ //---------------------------------------------- // these #define's specify HOW the control // will move. they can be combined with the // bitwise or operator // #define CP_MOVE_HORIZONTAL 1 #define CP_MOVE_VERTICAL 2 #define CP_RESIZE_HORIZONTAL 4 #define CP_RESIZE_VERTICAL 8 #define CP_MOVE_HORIZONTAL_CENTER 16 #define CP_MOVE_VERTICAL_CENTER 32 class CControlPos { public: CControlPos(CWnd* pParent = NULL); virtual ~CControlPos(); public: void SetParent(CWnd* pParent); BOOL AddControl(CWnd* pControl, const DWORD& dwStyle = CP_MOVE_HORIZONTAL); BOOL AddControl(const UINT& unId, const DWORD& dwStyle = CP_MOVE_HORIZONTAL); BOOL RemoveControl(CWnd* pControl); BOOL RemoveControl(const UINT& unId); void ResetControls(void); virtual void MoveControls(void); //--------------------------------------------------- // most of the time, you don't want to move controls // if the user reduces window size [controls can // overlap and cause "issues"] // negative moves won't move controls when the parent // window is getting smaller than its original size // void SetNegativeMoves(const BOOL& fNegativeMoves = TRUE); BOOL GetNegativeMoves(void) const; protected: virtual void UpdateParentSize(void); private: CWnd* m_pParent; int m_nOldParentWidth; int m_nOldParentHeight; int m_nOriginalParentWidth; int m_nOriginalParentHeight; BOOL m_fNegativeMoves; CObArray m_awndControls; }; //---------------------------------------------------- // internal structure used to hold all information // about a CWnd* control // typedef struct tagCONTROLDATA { HWND hControl; // HWND's never change; some MFC functions return temporary CWnd *'s DWORD dwStyle; // check the #define's above } CONTROLDATA, *LPCONTROLDATA; #endif
ControlPos.cpp
//------------------------------------------------------------------------------ // ControlPos.cpp // // CControlPos // Position controls on a form's resize // // Copyright (c) 2000 Paul Wendt // // VERSION# DATE NAME DESCRIPTION OF CHANGE // -------- ---------- ---- --------------------- // 1.01 07/11/2000 PRW Original creation. // #include "StdAfx.h" #include "ControlPos.h" //------------------------------------------------------------------------------ // CControlPos::CControlPos // // default constructor // // Access: public // // Args: // CWnd* pParent = pointer to parent window // // Return: // none // CControlPos::CControlPos(CWnd* pParent /* = NULL */) { m_pParent = pParent; UpdateParentSize(); m_nOldParentHeight = 0; m_nOldParentWidth = 0; SetNegativeMoves(FALSE); ResetControls(); } //------------------------------------------------------------------------------ // CControlPos::~CControlPos // // default destructor -- It deletes all controls. // // Access: public // // Args: // none // // Return: // none // CControlPos::~CControlPos() { ResetControls(); } //------------------------------------------------------------------------------ // CControlPos::SetParent // // This sets the parent window. It should be called from a CWnd's // post-constructor function, like OnInitdialog or InitialUpdate. // // Access: public // // Args: // CWnd* pParent = parent window // // Return: // none // void CControlPos::SetParent(CWnd* pParent) { CRect rcParentOriginalSize; m_pParent = pParent; m_pParent->GetClientRect(rcParentOriginalSize); m_nOriginalParentWidth = rcParentOriginalSize.right; m_nOriginalParentHeight = rcParentOriginalSize.bottom; UpdateParentSize(); } //------------------------------------------------------------------------------ // CControlPos::AddControl // // This adds a control to the internal list of controls in CControlPos. // // Access: public // // Args: // CWnd* pControl = pointer to the control to be added // const DWORD& dwStyle = how the window should be moved -- see #define's // in the header file // // Return: // BOOL = TRUE if the control was added successfully, FALSE otherwise // BOOL CControlPos::AddControl(CWnd* pControl, const DWORD& dwStyle /* = CP_MOVE_HORIZONTAL */) { BOOL fReturnValue = TRUE; if (pControl && m_pParent) { LPCONTROLDATA pstControl = new CONTROLDATA; pstControl->hControl = pControl->GetSafeHwnd(); pstControl->dwStyle = dwStyle; m_awndControls.Add(((CObject*)pstControl)); } else { fReturnValue = FALSE; } return (fReturnValue); } //------------------------------------------------------------------------------ // CControlPos::AddControl // // This adds a control the internal list of controls in CControlPos. // // Access: public // // Args: // const UINT& unId = ID of the control to add // const DWORD& dwStyle = how the window should be moved -- see #define's // in the header file // // Return: // BOOL = TRUE if the control was added successfully, FALSE otherwise // BOOL CControlPos::AddControl(const UINT& unId, const DWORD& dwStyle /* = CP_MOVE_HORIZONTAL */) { CWnd* pControl; if (m_pParent) { pControl = m_pParent->GetDlgItem(unId); return (AddControl(pControl, dwStyle)); } else { return (FALSE); } } //------------------------------------------------------------------------------ // CControlPos::RemoveControl // // If a client ever wants to remove a control programmatically, this // function will do it. // // Access: public // // Args: // CWnd* pControl = pointer of the window who should be removed from // the internal control list [ie: will not be repositioned] // // Return: // BOOL = TRUE if the control was found [and deleted], FALSE otherwise // BOOL CControlPos::RemoveControl(CWnd* pControl) { BOOL fReturnValue = FALSE; for (int i = 0; i < m_awndControls.GetSize(); i++) { LPCONTROLDATA pstControl = ((LPCONTROLDATA)m_awndControls.GetAt(i)); if (pstControl->hControl == pControl->GetSafeHwnd()) { m_awndControls.RemoveAt(i); delete pstControl; fReturnValue = TRUE; break; } } return (fReturnValue); } //------------------------------------------------------------------------------ // CControlPos::RemoveControl // // If a client ever wants to remove a control programmatically, this // function will do it. // // Access: public // // Args: // const UINT& unId = ID of the control that should be removed from the // internal control list [ie: will not be repositioned] // // Return: // BOOL = TRUE if the control was found [and deleted], FALSE otherwise // BOOL CControlPos::RemoveControl(const UINT& unId) { CWnd* pControl; if (m_pParent) { pControl = m_pParent->GetDlgItem(unId); return (RemoveControl(pControl)); } else { return (FALSE); } } //------------------------------------------------------------------------------ // CControlPos::ResetControls // // This function removes all controls from the CControlPos object // // Access: public // // Args: // none // // Return: // none // void CControlPos::ResetControls(void) { while (m_awndControls.GetSize() > 0) { int nHighIdx = m_awndControls.GetUpperBound(); LPCONTROLDATA pstControl = ((LPCONTROLDATA)m_awndControls.GetAt(nHighIdx)); if (pstControl) { m_awndControls.RemoveAt(nHighIdx); delete pstControl; } } } //------------------------------------------------------------------------------ // CControlPos::MoveControls // // This function takes care of moving all controls that have been added to // the object [see AddControl]. This function should be called from the // WM_SIZE handler-function [typically OnSize]. // // Access: public // // Args: // none // // Return: // none // void CControlPos::MoveControls(void) { if (m_pParent) { //-------------------------------------------------------------------- // for each control that has been added to our object, we want to // check its style and move it based off of the parent control's // movements. // the thing to keep in mind is that when you resize a window, you // can resize by more than one pixel at a time. this is important // when, for example, you start with a width smaller than the // original width and you finish with a width larger than the // original width. you know that you want to move the control, but // by how much? that is why so many if's and calculations are made // for (int i = 0; i < m_awndControls.GetSize(); i++) { LPCONTROLDATA pstControl = ((LPCONTROLDATA)m_awndControls.GetAt(i)); CRect rcParentBounds; CRect rcBounds; CWnd* pControl = m_pParent->FromHandle(pstControl->hControl); pControl->GetWindowRect(rcBounds); m_pParent->GetClientRect(rcParentBounds); if ((pstControl->dwStyle & (CP_RESIZE_VERTICAL)) == (CP_RESIZE_VERTICAL)) { if (!m_fNegativeMoves) { if (rcParentBounds.bottom > m_nOriginalParentHeight) { if (m_nOriginalParentHeight <= m_nOldParentHeight) { rcBounds.bottom += rcParentBounds.bottom - m_nOldParentHeight; } else { rcBounds.bottom += rcParentBounds.bottom - m_nOriginalParentHeight; } } else { if (m_nOldParentHeight > m_nOriginalParentHeight) { rcBounds.bottom += m_nOriginalParentHeight - m_nOldParentHeight; } } } else { rcBounds.bottom += rcParentBounds.bottom - m_nOldParentHeight; } } if ((pstControl->dwStyle & (CP_RESIZE_HORIZONTAL)) == (CP_RESIZE_HORIZONTAL)) { if (!m_fNegativeMoves) { if (rcParentBounds.right > m_nOriginalParentWidth) { if (m_nOriginalParentWidth <= m_nOldParentWidth) { rcBounds.right += rcParentBounds.right - m_nOldParentWidth; } else { rcBounds.right += rcParentBounds.right - m_nOriginalParentWidth; } } else { if (m_nOldParentWidth > m_nOriginalParentWidth) { rcBounds.right += m_nOriginalParentWidth - m_nOldParentWidth; } } } else { rcBounds.right += rcParentBounds.right - m_nOldParentWidth; } } if ((pstControl->dwStyle & (CP_MOVE_VERTICAL)) == (CP_MOVE_VERTICAL)) { if (!m_fNegativeMoves) { if (rcParentBounds.bottom > m_nOriginalParentHeight) { if (m_nOriginalParentHeight <= m_nOldParentHeight) { rcBounds.bottom += rcParentBounds.bottom - m_nOldParentHeight; rcBounds.top += rcParentBounds.bottom - m_nOldParentHeight; } else { rcBounds.bottom += rcParentBounds.bottom - m_nOriginalParentHeight; rcBounds.top += rcParentBounds.bottom - m_nOriginalParentHeight; } } else { if (m_nOldParentHeight > m_nOriginalParentHeight) { rcBounds.bottom += m_nOriginalParentHeight - m_nOldParentHeight; rcBounds.top += m_nOriginalParentHeight - m_nOldParentHeight; } } } else { rcBounds.bottom += rcParentBounds.bottom - m_nOldParentHeight; rcBounds.top += rcParentBounds.bottom - m_nOldParentHeight; } } if ((pstControl->dwStyle & (CP_MOVE_HORIZONTAL)) == (CP_MOVE_HORIZONTAL)) { if (!m_fNegativeMoves) { if (rcParentBounds.right > m_nOriginalParentWidth) { if (m_nOriginalParentWidth <= m_nOldParentWidth) { rcBounds.right += rcParentBounds.right - m_nOldParentWidth; rcBounds.left += rcParentBounds.right - m_nOldParentWidth; } else { rcBounds.right += rcParentBounds.right - m_nOriginalParentWidth; rcBounds.left += rcParentBounds.right - m_nOriginalParentWidth; } } else { if (m_nOldParentWidth > m_nOriginalParentWidth) { rcBounds.right += m_nOriginalParentWidth - m_nOldParentWidth; rcBounds.left += m_nOriginalParentWidth - m_nOldParentWidth; } } } else { rcBounds.right += rcParentBounds.right - m_nOldParentWidth; rcBounds.left += rcParentBounds.right - m_nOldParentWidth; } } if ((pstControl->dwStyle & (CP_MOVE_HORIZONTAL_CENTER)) == (CP_MOVE_HORIZONTAL_CENTER)) { if (!m_fNegativeMoves) { if (rcParentBounds.right > m_nOriginalParentWidth) { if (m_nOriginalParentWidth <= m_nOldParentWidth) { rcBounds.right += (rcParentBounds.right - m_nOldParentWidth)/2; rcBounds.left += (rcParentBounds.right - m_nOldParentWidth)/2; } else { rcBounds.right += rcParentBounds.right - m_nOriginalParentWidth; rcBounds.left += rcParentBounds.right - m_nOriginalParentWidth; } } else { if (m_nOldParentWidth > m_nOriginalParentWidth) { rcBounds.right += m_nOriginalParentWidth - m_nOldParentWidth; rcBounds.left += m_nOriginalParentWidth - m_nOldParentWidth; } } } else { rcBounds.right += rcParentBounds.right - m_nOldParentWidth; rcBounds.left += rcParentBounds.right - m_nOldParentWidth; } } if ((pstControl->dwStyle & (CP_MOVE_VERTICAL_CENTER)) == (CP_MOVE_VERTICAL_CENTER)) { if (!m_fNegativeMoves) { if (rcParentBounds.bottom > m_nOriginalParentHeight) { if (m_nOriginalParentHeight <= m_nOldParentHeight) { rcBounds.bottom += (rcParentBounds.bottom - m_nOldParentHeight)/2; rcBounds.top += (rcParentBounds.bottom - m_nOldParentHeight)/2; } else { rcBounds.bottom += rcParentBounds.bottom - m_nOriginalParentHeight; rcBounds.top += rcParentBounds.bottom - m_nOriginalParentHeight; } } else { if (m_nOldParentHeight > m_nOriginalParentHeight) { rcBounds.bottom += m_nOriginalParentHeight - m_nOldParentHeight; rcBounds.top += m_nOriginalParentHeight - m_nOldParentHeight; } } } else { rcBounds.bottom += rcParentBounds.bottom - m_nOldParentHeight; rcBounds.top += rcParentBounds.bottom - m_nOldParentHeight; } } m_pParent->ScreenToClient(rcBounds); pControl->MoveWindow(rcBounds); } UpdateParentSize(); } } //------------------------------------------------------------------------------ // CControlPos::SetNegativeMoves // // This sets the NegativeMoves boolean parameter of the object. When the // parent window becomes smaller than it started, setting this to FALSE // will not allow controls to be moved; the parent size may change, but // it'll just force the controls to go off of the // This parameter defaults to FALSE on object creation. // // Access: public // // Args: // const BOOL& fNegativeMoves /* = TRUE */ = value to set // // Return: // none // void CControlPos::SetNegativeMoves(const BOOL& fNegativeMoves /* = TRUE */) { m_fNegativeMoves = fNegativeMoves; } //------------------------------------------------------------------------------ // CControlPos::GetNegativeMoves // // This function returns whether or not negative moves are enabled. // // Access: public // // Args: // none // // Return: // BOOL = TRUE if negative moves are enabled, FALSE otherwise // BOOL CControlPos::GetNegativeMoves(void) const { return (m_fNegativeMoves); } //------------------------------------------------------------------------------ // CControlPos::UpdateParentSize // // Since CControlPos keeps track of the parent's size, it gets updated // every time it tells us to size the controls. We keep track so we know // how much it changed from the last WM_SIZE message. // // Access: protected // // Args: // none // // Return: // none // void CControlPos::UpdateParentSize(void) { if (m_pParent) { CRect rcBounds; m_pParent->GetClientRect(rcBounds); m_nOldParentWidth = rcBounds.Width(); m_nOldParentHeight = rcBounds.Height(); } }
调用方法:
.h文件中添加
CControlPos m_ControlPos;
.cpp文件中添加
//OnCreate或OnInitDialog中添加
m_ControlPos.SetParent(this);
m_ControlPos.AddControl(GetDlgItem(控件ID), CP_MOVE_HORIZONTAL | CP_MOVE_VERTICAL); //随窗口变化移动
/* 参数例表
CP_MOVE_HORIZONTAL //随窗口水平移动
CP_MOVE_VERTICAL //随窗口垂直移动
CP_RESIZE_HORIZONTAL //随窗口水平变化而变化
CP_RESIZE_VERTICAL //随窗口垂直变化而变化
CP_MOVE_HORIZONTAL_CENTER //随窗口水平变化始终保存着居中比例
CP_MOVE_VERTICAL_CENTER //随窗口垂直变化始终保存着居中比例
*/
//添加WM_SIZE消息 OnSize中添加
m_ControlPos.MoveControls();