VS2015 VS2017 MFC 动态布局的改进

先提上代码,然后再说怎么回事


// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#pragma once


#include <vector>
using namespace std;

/// <summary>
/// Vertical and horizontal ratios define move direction of a child control when a hosting window is being resized.
/// </summary>
struct MyDynamicLayoutMoveSettings
{
	MyDynamicLayoutMoveSettings()
	{
		m_nXRatio = 0;
		m_nYRatio = 0;
	}

	BOOL IsHorizontal() const { return m_nXRatio > 0; }
	BOOL IsVertical() const { return m_nYRatio > 0; }
	BOOL IsNone() const { return !IsHorizontal() && !IsVertical(); }

	/// <summary>
	/// Defines (in percents) how far a child control is moved horizontally when size of host has been changed.
	/// For example, m_nXRatio is 50%. If size of host is changed by 20 pixels, the child is moved horizontally by 10 pixels from its current position.
	/// </summary>
	int m_nXRatio;

	/// <summary>
	/// Defines (in percents) how far a child control is moved vertically when size of host has been changed.
	/// For example, m_nYRatio is 50%. If size of host is changed by 20 pixels, the child is moved vertically by 10 pixels from its current position.
	/// </summary>
	int m_nYRatio;
};

/// <summary>
/// Vertical and horizontal ratios define how to resize a child control when a hosting window is being resized.
/// </summary>
struct MyDynamicLayoutSettings
{
	MyDynamicLayoutSettings()
	{
		m_nXRatio = 0;
		m_nYRatio = 0;
	}

	BOOL IsHorizontal() const { return m_nXRatio > 0; }
	BOOL IsVertical() const { return m_nYRatio > 0; }
	BOOL IsNone() const { return !IsHorizontal() && !IsVertical(); }

	/// <summary>
	/// Defines (in percents) how a child control is resized horizontally when size of host has been changed.
	/// For example, m_nXRatio is 50%. If the size of host is changed by 20 pixels, the child is resized by 10 pixels.
	/// </summary>
	int m_nXRatio;

	/// <summary>
	/// Defines (in percents) how a child control is resized vertically when size of host has been changed.
	/// For example, m_nYRatio is 50%. If the size of host is changed by 20 pixels, the child is resized by 10 pixels.
	/// </summary>
	int m_nYRatio;
};


/////////////////////////////////////////////////////////////////////////////
// AFX_DYNAMIC_LAYOUT_ITEM

struct MYDYNAMIC_LAYOUT_ITEM
{
	struct Point
	{
		Point()
			: x(0.0)
			, y(0.0)
		{
		}

		double x;
		double y;
	};

	MYDYNAMIC_LAYOUT_ITEM(HWND hWnd,
		const MyDynamicLayoutMoveSettings& moveSettings,
		const MyDynamicLayoutSettings& sizeSettings)
		: m_hWnd(hWnd)
		, m_moveSettings(moveSettings)
		, m_sizeSettings(sizeSettings)
	{
	}

	HWND m_hWnd;
	Point m_ptInit;
	Point m_szInit;
	MyDynamicLayoutMoveSettings m_moveSettings;
	MyDynamicLayoutSettings m_sizeSettings;
};

#ifndef RT_DIALOG_LAYOUT
#define RT_DIALOG_LAYOUT	_T("AFX_DIALOG_LAYOUT")
#endif
/////////////////////////////////////////////////////////////////////////////
// MyDynamicLayout

/// <summary>
/// Dynamic layout performs automatic reposition of controls hosted in a window.
/// </summary>
class MyDynamicLayout
{
public:
	
	// Construction:
public:
	MyDynamicLayout();
	virtual ~MyDynamicLayout();

	// Operations:
public:
	/// <summary>
	/// Stores and validates the host window.</summary>
	/// <returns> TRUE if creation succeeded; otherwise FALSE.</returns>
	/// <param name="pHostWnd"> A pointer to a host window.</param>
	BOOL Create(CWnd* pHostWnd);

	/// <summary>
	/// This method recalculates positions and sizes of child controls that have been added to layout using AddItem. 
	/// Called by the framework when the hosting window is being resized.</summary>
	void Adjust();

	// Behavior settings:

	/// <summary>
	/// No move when a hosting window is being resized.</summary>
	/// <returns> Behavior settings define move direction.</returns>
	static MyDynamicLayoutMoveSettings MoveNone();

	/// <summary>
	/// A child control is moved horizontally only when a hosting window is being resized.</summary>
	/// <returns> Behavior settings define move direction.</returns>
	/// <param name="nRatio"> Defines (in percents) how far a child control is moved horizontally when size of host has been changed.</param>
	static MyDynamicLayoutMoveSettings MoveHorizontal(int nRatio);

	/// <summary>
	/// A child control is moved vertically only when a hosting window is being resized.</summary>
	/// <returns> Behavior settings define move direction.</returns>
	/// <param name="nRatio"> Defines (in percents) how far a child control is moved vertically when size of host has been changed.</param>
	static MyDynamicLayoutMoveSettings MoveVertical(int nRatio);

	/// <summary>
	/// A child control is moved horizontally and vertically when a hosting window is being resized.</summary>
	/// <returns> Behavior settings define move direction.</returns>
	/// <param name="nXRatio"> Defines (in percents) how far a child control is moved horizontally when size of host has been changed.</param>
	/// <param name="nYRatio"> Defines (in percents) how far a child control is moved vertically when size of host has been changed.</param>
	static MyDynamicLayoutMoveSettings MoveHorizontalAndVertical(int nXRatio, int nYRatio);

	/// <summary>
	/// No resize when a hosting window is being resized.</summary>
	/// <returns> Behavior settings define resize method.</returns>
	static MyDynamicLayoutSettings SizeNone();

	/// <summary>
	/// X dimension of a child window is changed when a hosting window is being resized.</summary>
	/// <returns> Behavior settings define resize method.</returns>
	/// <param name="nRatio"> Defines (in percents) how a child control is resized horizontally when size of host has been changed.</param>
	static MyDynamicLayoutSettings SizeHorizontal(int nRatio);

	/// <summary>
	/// Y dimension of a child window is changed when a hosting window is being resized.</summary>
	/// <returns> Behavior settings define resize method.</returns>
	/// <param name="nRatio"> Defines (in percents) how a child control is resized vertically when size of host has been changed.</param>
	static MyDynamicLayoutSettings SizeVertical(int nRatio);

	/// <summary>
	/// Width and height of a child window are changed when a hosting window is being resized.</summary>
	/// <returns> Behavior settings define resize method.</returns>
	/// <param name="nXRatio"> Defines (in percents) how a child control is resized horizontally when size of host has been changed.</param>
	/// <param name="nYRatio"> Defines (in percents) how a child control is resized vertically when size of host has been changed.</param>
	static MyDynamicLayoutSettings SizeHorizontalAndVertical(int nXRatio, int nYRatio);

	/// <summary>
	/// Adds a child control to dynamic layout.</summary>
	/// <remarks> The position and size of a child control is changed dynamically when a hosting window is being resized.</remarks>
	/// <returns> TRUE if succeeded; otherwise FALSE.</returns>
	/// <param name="nID"> Child control ID.</param>
	/// <param name="moveSettings"> Reposition behavior settings contain vertical and horizontal ratios. Specifies how to adjust position of a control.</param>
	/// <param name="sizeSettings"> Resizing behavior settings contain vertical and horizontal distribution ratios. Specifies how to adjust position of a control.</param>
	BOOL AddItem(UINT nID, MyDynamicLayoutMoveSettings moveSettings, MyDynamicLayoutSettings sizeSettings);

	/// <summary>
	/// Adds a child control to dynamic layout.</summary>
	/// <remarks> The position and size of a child control is changed dynamically when a hosting window is being resized.</remarks>
	/// <returns> TRUE if succeeded; otherwise FALSE.</returns>
	/// <param name="hwnd"> Handle of a child control.</param>
	/// <param name="moveSettings"> Reposition behavior settings contain vertical and horizontal ratios. Specifies how to adjust position of a control.</param>
	/// <param name="sizeSettings"> Resizing behavior settings contain vertical and horizontal distribution ratios. Specifies how to adjust position of a control.</param>
	BOOL AddItem(HWND hwnd, MyDynamicLayoutMoveSettings moveSettings, MyDynamicLayoutSettings sizeSettings);

	/// <summary>
	/// Checks if a child control was added to dynamic layout.</summary>
	/// <remarks></remarks>
	/// <returns> TRUE if layout already has this item; otherwise FALSE.</returns>
	/// <param name="hwnd"> Handle of a child control.</param>
	BOOL HasItem(HWND hwnd) { return FindItem(hwnd) != NULL; }

	/// <summary>
	/// Checks if a dynamic layout is empty.</summary>
	/// <remarks></remarks>
	/// <returns> TRUE if layout is empty; otherwise FALSE.</returns>
	BOOL IsEmpty() const { return m_listWnd.IsEmpty(); }

	/// <summary>
	/// This method returns client area of host window.</summary>
	/// <param name="rect"> When the function returns this parameter contains bounding rectangle of layout area..</param>
	void GetHostWndRect(CRect& rect) const;

	/// <summary>
	/// This method reads the dynamic layout from AFX_DIALOG_LAYOUT resource and then applies the layout to the host window.</summary>
	/// <returns> TRUE if resource is loaded and applied to the host window; otherwise FALSE.</returns>
	/// <param name="pHostWnd"> A pointer to the host window.</param>
	/// <param name="lpResource"> A pointer to the buffer containing AFX_DIALOG_LAYOUT resource.</param>
	/// <param name="dwSize"> Size of buffer in bytes.</param>
	static BOOL LoadResource(CWnd* pHostWnd, MyDynamicLayout* pDynamicLayout, LPVOID lpResource, DWORD dwSize);

public:
	MYDYNAMIC_LAYOUT_ITEM * FindItem(HWND hWnd);
	BOOL PrepareItem(MYDYNAMIC_LAYOUT_ITEM& item) const;
protected:
	void CorrectItem(MYDYNAMIC_LAYOUT_ITEM& item) const;
	UINT AdjustItemRect(MYDYNAMIC_LAYOUT_ITEM& item, CRect& rectItem) const;

	CRect GetItemRect(MYDYNAMIC_LAYOUT_ITEM& item) const;

	// Attributes:
public:
	/// <summary>
	/// This method returns a pointer to a host window. By default all child control positions recalculated relatively to this window.</summary>
	/// <returns> 
	/// A pointer to a host window.</returns>
	CWnd* GetHostWnd() { return m_pHostWnd; }

	/// <summary>
	/// This method returns minimal size of layout area. If a host window is resized beyond this area, the layout is not calculated.
	/// For dialog templates the initial minimal size is set to client rectangle.</summary>
	/// <returns> 
	/// Minimal size of layout area.</returns>
	CSize GetMinSize() const { return m_MinSize; }

	/// <summary>
	/// This function sets minimal size of layout area. If a host window is resized beyond this area, the layout is not calculated.</summary>
	/// <param name="size">Specifies the minimal size of layout area.</param>
	void SetMinSize(const CSize& size) { m_MinSize = size; }

private:
	CWnd * m_pHostWnd;
	CSize m_MinSize;
	CList<MYDYNAMIC_LAYOUT_ITEM*, MYDYNAMIC_LAYOUT_ITEM*> m_listWnd;

};

/////////////////////////////////////////////////////////////////////////////
// MyCDynamicLayoutData

/// <summary>
/// A helper class to store layout data. It's used while loading dynamic layout from resource and applying it to a host window.
/// </summary>
class MyCDynamicLayoutData
{
public:
	/// <summary>
	/// A helper class to store layout data of one child control.
	/// </summary>
	struct Item
	{
		MyDynamicLayoutMoveSettings m_moveSettings;
		MyDynamicLayoutSettings m_sizeSettings;
	};

public:
	/// <summary>
	/// Remove layout data that's stored in this helper class.</summary>
	void CleanUp();

	/// <summary>
	/// This method reads the dynamic layout data from AFX_DIALOG_LAYOUT resource.</summary>
	/// <returns> TRUE if resource is loaded; otherwise FALSE.</returns>
	/// <param name="lpResource"> A pointer to the buffer containing AFX_DIALOG_LAYOUT resource.</param>
	/// <param name="dwSize"> Size of buffer in bytes.</param>
	BOOL ReadResource(LPVOID lpResource, UINT nSize);

	/// <summary>
	/// This method enables the dynamic layout to a host window.</summary>
	/// <returns> TRUE if succeeds; otherwise FALSE.</returns>
	/// <param name="pHostWnd"> A pointer to the host window.</param>
	/// <param name="bUpdate"> Use TRUE to update positions and sizes of child controls.</param>
	BOOL ApplyLayoutDataTo(CWnd* pHostWnd, MyDynamicLayout* pLayout, BOOL bUpdate);

protected:
	CList<Item, Item&> m_listCtrls;
};
BOOL MyLoadDynamicLayoutResource(CWnd* thiz, MyDynamicLayout* pDynamicLayout, LPCTSTR lpszResourceName);

//cpp

#include "stdafx.h"

#include "Myafxlayout.h"
 



/////////////////////////////////////////////////////////////////////////////
// MyDynamicLayout



MyDynamicLayout::MyDynamicLayout()
	: m_pHostWnd(NULL)
	, m_MinSize(0, 0)
{
}

MyDynamicLayout::~MyDynamicLayout()
{
	while (!m_listWnd.IsEmpty())
	{
		delete m_listWnd.RemoveHead();
	}
}

BOOL MyDynamicLayout::Create(CWnd* pHostWnd)
{
	if (pHostWnd->GetSafeHwnd() == NULL)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	m_pHostWnd = pHostWnd;
	return TRUE;
}

void MyDynamicLayout::Adjust()
{
	const int nCount = (int)m_listWnd.GetCount();
	if (nCount == 0)
	{
		return;
	}

	HDWP hDWP = ::BeginDeferWindowPos(nCount);

	for (POSITION pos = m_listWnd.GetHeadPosition(); pos != NULL;)
	{
		MYDYNAMIC_LAYOUT_ITEM* pItem = m_listWnd.GetNext(pos);
		HWND hwnd = pItem->m_hWnd;

		if (::IsWindow(hwnd))
		{
			CRect rectItem;
			UINT uiFlags = AdjustItemRect(*pItem, rectItem);

			if ((uiFlags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE))
			{
				::DeferWindowPos(hDWP, hwnd, HWND_TOP, rectItem.left, rectItem.top,
					rectItem.Width(), rectItem.Height(),
					uiFlags | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOACTIVATE | SWP_NOCOPYBITS);
			}
		}
	}

	::EndDeferWindowPos(hDWP);
}

MyDynamicLayoutMoveSettings MyDynamicLayout::MoveNone()
{
	return MyDynamicLayoutMoveSettings();
}

MyDynamicLayoutMoveSettings MyDynamicLayout::MoveHorizontal(int nRatio)
{
	MyDynamicLayoutMoveSettings settings;
	settings.m_nXRatio = nRatio;

	return settings;
}

MyDynamicLayoutMoveSettings MyDynamicLayout::MoveVertical(int nRatio)
{
	MyDynamicLayoutMoveSettings settings;
	settings.m_nYRatio = nRatio;

	return settings;
}

MyDynamicLayoutMoveSettings MyDynamicLayout::MoveHorizontalAndVertical(int nXRatio, int nYRatio)
{
	MyDynamicLayoutMoveSettings settings;

	settings.m_nXRatio = nXRatio;
	settings.m_nYRatio = nYRatio;

	return settings;
}

MyDynamicLayoutSettings MyDynamicLayout::SizeNone()
{
	return MyDynamicLayoutSettings();
}

MyDynamicLayoutSettings MyDynamicLayout::SizeHorizontal(int nRatio)
{
	MyDynamicLayoutSettings settings;
	settings.m_nXRatio = nRatio;

	return settings;
}

MyDynamicLayoutSettings MyDynamicLayout::SizeVertical(int nRatio)
{
	MyDynamicLayoutSettings settings;
	settings.m_nYRatio = nRatio;

	return settings;
}

MyDynamicLayoutSettings MyDynamicLayout::SizeHorizontalAndVertical(int nXRatio, int nYRatio)
{
	MyDynamicLayoutSettings settings;

	settings.m_nXRatio = nXRatio;
	settings.m_nYRatio = nYRatio;

	return settings;
}

BOOL MyDynamicLayout::AddItem(UINT nID, MyDynamicLayoutMoveSettings moveSettings, MyDynamicLayoutSettings sizeSettings)
{
	if (m_pHostWnd->GetSafeHwnd() == NULL)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	return AddItem(m_pHostWnd->GetDlgItem(nID)->GetSafeHwnd(), moveSettings, sizeSettings);
}

BOOL MyDynamicLayout::AddItem(HWND hWnd, MyDynamicLayoutMoveSettings moveSettings, MyDynamicLayoutSettings sizeSettings)
{
	if (hWnd == NULL || !::IsWindow(hWnd) || !::IsChild(m_pHostWnd->GetSafeHwnd(), hWnd))
	{
		ASSERT(FALSE);
		return FALSE;
	}

	MYDYNAMIC_LAYOUT_ITEM* pItem = FindItem(hWnd);
	if (pItem != NULL)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	CFormView* pFormView = DYNAMIC_DOWNCAST(CFormView, m_pHostWnd);
	if (pFormView != NULL)
	{
		ASSERT_VALID(pFormView);

		if (pFormView->IsInitDlgCompleted())
		{
			TRACE0("MyDynamicLayout::AddAnchor failed! Please call this method inside WM_INITDIALOG message handler in your CFormView-derived class.\n");
			ASSERT(FALSE);
		}
	}

	pItem = new MYDYNAMIC_LAYOUT_ITEM(hWnd, moveSettings, sizeSettings);

	CorrectItem(*pItem);

	if (PrepareItem(*pItem))
	{
		m_listWnd.AddTail(pItem);
	}

	return TRUE;
}

MYDYNAMIC_LAYOUT_ITEM* MyDynamicLayout::FindItem(HWND hWnd)
{
	for (POSITION pos = m_listWnd.GetHeadPosition(); pos != NULL;)
	{
		MYDYNAMIC_LAYOUT_ITEM* pItem = m_listWnd.GetNext(pos);
		if (pItem->m_hWnd == hWnd)
		{
			return pItem;
		}
	}

	return NULL;
}

void MyDynamicLayout::CorrectItem(MYDYNAMIC_LAYOUT_ITEM& item) const
{
	CString strName;
	::GetClassName(item.m_hWnd, strName.GetBufferSetLength(1024), 1024);
	strName.ReleaseBuffer();

	if (strName.CompareNoCase(WC_COMBOBOX) == 0 || strName.CompareNoCase(WC_COMBOBOXEX) == 0)
	{
		DWORD dwStyle = ::GetWindowLong(item.m_hWnd, GWL_STYLE);

		if (item.m_sizeSettings.IsVertical() && (dwStyle & CBS_SIMPLE) == 0)
		{
			item.m_sizeSettings.m_nYRatio = 0;
		}
	}
}

CRect MyDynamicLayout::GetItemRect(MYDYNAMIC_LAYOUT_ITEM& item) const
{
	CRect rectChild(0, 0, 0, 0);

	if (m_pHostWnd == NULL)
	{
		ASSERT(FALSE);
		return NULL;
	}

	::GetWindowRect(item.m_hWnd, rectChild);
	m_pHostWnd->ScreenToClient(rectChild);

	return rectChild;
}

BOOL MyDynamicLayout::PrepareItem(MYDYNAMIC_LAYOUT_ITEM& item) const
{
	CRect rectHost;
	GetHostWndRect(rectHost);

	if (rectHost.IsRectNull())
	{
		ASSERT(FALSE);
		return FALSE;
	}

	CRect rectChild = GetItemRect(item);

	const double deltaX = 0.01 * rectHost.Width();
	const double deltaY = 0.01 * rectHost.Height();

	item.m_ptInit.x = (double)rectChild.left;
	item.m_ptInit.y = (double)rectChild.top;

	if (item.m_moveSettings.IsHorizontal())
	{
		item.m_ptInit.x -= deltaX * item.m_moveSettings.m_nXRatio;
	}

	if (item.m_moveSettings.IsVertical())
	{
		item.m_ptInit.y -= deltaY * item.m_moveSettings.m_nYRatio;
	}

	item.m_szInit.x = (double)rectChild.Width();
	item.m_szInit.y = (double)rectChild.Height();

	if (item.m_sizeSettings.IsHorizontal())
	{
		item.m_szInit.x -= deltaX * item.m_sizeSettings.m_nXRatio;
	}

	if (item.m_sizeSettings.IsVertical())
	{
		item.m_szInit.y -= deltaY * item.m_sizeSettings.m_nYRatio;
	}

	return TRUE;
}

UINT MyDynamicLayout::AdjustItemRect(MYDYNAMIC_LAYOUT_ITEM& item, CRect& rectItem) const
{
	rectItem.SetRectEmpty();

	CRect rectHost;
	GetHostWndRect(rectHost);

	if (rectHost.IsRectNull())
	{
		return SWP_NOMOVE | SWP_NOSIZE;
	}

	UINT uiFlags = 0;
	const double deltaX = 0.01 * rectHost.Width();
	const double deltaY = 0.01 * rectHost.Height();

	MYDYNAMIC_LAYOUT_ITEM::Point point(item.m_ptInit);
	MYDYNAMIC_LAYOUT_ITEM::Point size(item.m_szInit);

	if (item.m_moveSettings.IsHorizontal())
	{
		point.x += deltaX * item.m_moveSettings.m_nXRatio;
	}

	if (item.m_moveSettings.IsVertical())
	{
		point.y += deltaY * item.m_moveSettings.m_nYRatio;
	}

	if (item.m_sizeSettings.IsHorizontal())
	{
		size.x += deltaX * item.m_sizeSettings.m_nXRatio;
	}

	if (item.m_sizeSettings.IsVertical())
	{
		size.y += deltaY * item.m_sizeSettings.m_nYRatio;
	}

	rectItem.left = (long)point.x + rectHost.left;
	rectItem.top = (long)point.y + rectHost.top;
	rectItem.right = rectItem.left + (long)size.x;
	rectItem.bottom = rectItem.top + (long)size.y;

	if (rectItem.left == (item.m_ptInit.x + rectHost.left) && rectItem.top == (item.m_ptInit.y + rectHost.top))
	{
		uiFlags |= SWP_NOMOVE;
	}

	if (rectItem.Width() == item.m_szInit.x && rectItem.Height() == item.m_szInit.y)
	{
		uiFlags |= SWP_NOSIZE;
	}

	return uiFlags;
}

/////////////////////////////////////////////////////////////////////////////
// MyCDynamicLayoutData

void MyCDynamicLayoutData::CleanUp()
{
	m_listCtrls.RemoveAll();
}

inline int AfxClamp(WORD wValue, int nMin = 0, int nMax = 100)
{
	int value = (SHORT)wValue;

#if _DEBUG
	if (value < nMin || value > nMax)
	{
		TRACE(_T("Data is out of bounds.\n"));
	}
#endif

	return value < nMin ? nMin : (value > nMax ? nMax : value);
}

BOOL MyCDynamicLayoutData::ReadResource(LPVOID lpResource, UINT nSize)
{
	if (lpResource == NULL || nSize == 0)
	{
		return FALSE;
	}

	ASSERT(AfxIsValidAddress(lpResource, nSize, FALSE));

	CleanUp();

	const BYTE* const pBuf = (BYTE*)lpResource;
	const WORD* const pwEnd = (WORD*)(pBuf + nSize);
	const WORD* pw = (WORD*)pBuf;

	// header
	WORD wVersion = *pw++;

	if (wVersion == 0)
	{
		// data
		while (pw + 4 <= pwEnd)
		{
			Item itemData;

			itemData.m_moveSettings.m_nXRatio = AfxClamp(*pw++);
			itemData.m_moveSettings.m_nYRatio = AfxClamp(*pw++);
			itemData.m_sizeSettings.m_nXRatio = AfxClamp(*pw++);
			itemData.m_sizeSettings.m_nYRatio = AfxClamp(*pw++);

			m_listCtrls.AddTail(itemData);
		}

		return m_listCtrls.GetCount() > 0;
	}

	return FALSE;
}

BOOL MyCDynamicLayoutData::ApplyLayoutDataTo(CWnd* pHostWnd, MyDynamicLayout* pLayout, BOOL bUpdate)
{
	if (pHostWnd->GetSafeHwnd() == NULL || m_listCtrls.IsEmpty())
	{
		return FALSE;
	}

	ATLASSERT(pHostWnd);

	 

	if (pLayout == NULL)
	{
		return FALSE;
	}

	ATLASSERT(pLayout);

	if (!pLayout->Create(pHostWnd))
	{
		return FALSE;
	}

	int nCount = 0;
	CWnd* pChild = pHostWnd->GetWindow(GW_CHILD);
	POSITION pos = m_listCtrls.GetHeadPosition();
	while (pChild != NULL && pos != NULL)
	{
		const Item& item = m_listCtrls.GetNext(pos);

		if (!item.m_moveSettings.IsNone() || !item.m_sizeSettings.IsNone())
		{
			pLayout->AddItem(pChild->GetSafeHwnd(), item.m_moveSettings, item.m_sizeSettings);
			nCount++;
		}

		pChild = pChild->GetNextWindow();
	}

	if (bUpdate)
	{
		pLayout->Adjust();
	}

	return TRUE;
}

void MyDynamicLayout::GetHostWndRect(CRect& rect) const
{
	rect.SetRectEmpty();

	if (m_pHostWnd->GetSafeHwnd() != NULL)
	{
		m_pHostWnd->GetClientRect(rect);

#if defined(_AFXDLL) || !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
		if (DYNAMIC_DOWNCAST(CMFCPropertyPage, m_pHostWnd) != NULL)
		{
			CMFCPropertySheet* pParent = DYNAMIC_DOWNCAST(CMFCPropertySheet, m_pHostWnd->GetParent());
			if (pParent != NULL)
			{
				int nNavigatorWidth = pParent->GetNavBarWidth();
				int nHeaderHeight = pParent->GetHeaderHeight();

				if (nHeaderHeight > 0)
				{
					rect.top += nHeaderHeight;

					if (pParent->GetLook() != CMFCPropertySheet::PropSheetLook_Tabs)
					{
						rect.bottom -= nHeaderHeight;
					}
				}

				rect.left += nNavigatorWidth;
			}

			rect.OffsetRect(-rect.TopLeft());
		}
		else
#endif
			if (DYNAMIC_DOWNCAST(CFormView, m_pHostWnd) != NULL)
			{
				CPoint ptScroll(((CFormView*)m_pHostWnd)->GetScrollPos(SB_HORZ), ((CFormView*)m_pHostWnd)->GetScrollPos(SB_VERT));

				rect.InflateRect(0, 0, ptScroll.x, ptScroll.y);
				rect.OffsetRect(-ptScroll.x, -ptScroll.y);
			}

		rect.right = rect.left + max(m_MinSize.cx, rect.Width());
		rect.bottom = rect.top + max(m_MinSize.cy, rect.Height());
	}
}

/////////////////////////////////////////////////////////////////////////////
// MyDynamicLayout - loading RT_DIALOG_LAYOUT resource

BOOL MyDynamicLayout::LoadResource(CWnd* pHostWnd, MyDynamicLayout* pDynamicLayout, LPVOID lpResource, DWORD dwSize)
{
	if (pHostWnd->GetSafeHwnd() == NULL || !::IsWindow(pHostWnd->GetSafeHwnd()) || lpResource == NULL)
	{
		return FALSE;
	}

	MyCDynamicLayoutData layoutData;
	BOOL bResult = layoutData.ReadResource(lpResource, (UINT)dwSize);
	layoutData.ApplyLayoutDataTo(pHostWnd,pDynamicLayout, FALSE);

	return bResult;
}

void MyInitDynamicLayout(CWnd* thiz, MyDynamicLayout* pDynamicLayout)
{
	if(pDynamicLayout != NULL)
	{
		ATLASSERT(pDynamicLayout);
		CDialog* pDialog = DYNAMIC_DOWNCAST(CDialog, thiz);
		CPropertySheet* pPropSheet = DYNAMIC_DOWNCAST(CPropertySheet, thiz);
		const BOOL bIsChild = (thiz->GetStyle() & WS_CHILD) == WS_CHILD;

		if(!bIsChild && (pDialog != NULL || pPropSheet != NULL))
		{
			CRect rect;
			thiz->GetClientRect(&rect);
			thiz->ModifyStyle(DS_MODALFRAME, WS_POPUP | WS_THICKFRAME);
			::AdjustWindowRectEx(&rect, thiz->GetStyle(), ::IsMenu(thiz->GetMenu()->GetSafeHmenu()), thiz->GetExStyle());
			thiz->SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(), SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
		}

		if(pPropSheet == NULL && DYNAMIC_DOWNCAST(CPropertyPage, thiz) == NULL)
		{
			CRect rect;
			thiz->GetClientRect(rect);
			pDynamicLayout->SetMinSize(rect.Size());
		}
	}
}

BOOL MyLoadDynamicLayoutResource(CWnd* thiz , MyDynamicLayout* pDynamicLayout, LPCTSTR lpszResourceName)
{
	if(!thiz || thiz->GetSafeHwnd() == NULL || !::IsWindow(thiz->GetSafeHwnd()) ||
	        lpszResourceName == NULL)
	{
		return FALSE;
	}

	// find resource handle
	DWORD dwSize = 0;
	LPVOID lpResource = NULL;
	HGLOBAL hResource = NULL;

	if(lpszResourceName != NULL)
	{
		HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_DIALOG_LAYOUT);
		HRSRC hDlgLayout = ::FindResource(hInst, lpszResourceName, RT_DIALOG_LAYOUT);

		if(hDlgLayout != NULL)
		{
			// load it
			dwSize = SizeofResource(hInst, hDlgLayout);
			hResource = LoadResource(hInst, hDlgLayout);

			if(hResource == NULL)
				return FALSE;

			// lock it
			lpResource = LockResource(hResource);
			ASSERT(lpResource != NULL);
		}
	}

	// Use lpResource
	BOOL bResult = MyDynamicLayout::LoadResource(thiz, pDynamicLayout,lpResource, dwSize);

	// cleanup
	if(lpResource != NULL && hResource != NULL)
	{
		UnlockResource(hResource);
		FreeResource(hResource);
	}

	if(bResult)
	{
		MyInitDynamicLayout(thiz, pDynamicLayout);
	}

	return bResult;
}

对话框中添加

MyDynamicLayout * m_pMydynamicLayout = 0;

BOOL x::OnInitDialog()
{
CDialogEx::OnInitDialog();
EnableDynamicLayout(FALSE);
m_pMydynamicLayout = new(nothrow) MyDynamicLayout();


if(m_pMydynamicLayout)
{
MyLoadDynamicLayoutResource(this, m_pMydynamicLayout, MAKEINTRESOURCE(IDD_EXTSPLIT_DIALOG));

}

。。。

}

void x::OnSize(UINT nType, int cx, int cy)
{
if(m_pMydynamicLayout)
{
m_pMydynamicLayout->Adjust();
}
}

void x::OnGetMinMaxInfo(MINMAXINFO * lpMMI)
{
if(lpMMI && m_pMydynamicLayout)
{
CSize szMin = m_pMydynamicLayout->GetMinSize();
RECT rcWindow;
RECT rcClient;
::GetWindowRect(m_hWnd, &rcWindow);
::GetClientRect(m_hWnd, &rcClient);
lpMMI->ptMinTrackSize.x = szMin.cx + _WIDTH(rcWindow) - _WIDTH(rcClient);
lpMMI->ptMinTrackSize.y = szMin.cy + _HEIGHT(rcWindow) - _HEIGHT(rcClient);
}
}

void x::Spliter_OnChange(SplitStickObj * pCtrl, BOOL bHOrV, int LTnewHorW, int RBnewHorW, BOOL bScrollAtEndBefore)
{
//重新设置布局参数
if(m_pMydynamicLayout && m_pListLines && m_pListValues)
{
MYDYNAMIC_LAYOUT_ITEM* pItem = m_pMydynamicLayout->FindItem(m_pListLines->m_hWnd);


if(pItem)
{
m_pMydynamicLayout->PrepareItem(*pItem);
}


pItem = m_pMydynamicLayout->FindItem(m_pListValues->m_hWnd);


if(pItem)
{
m_pMydynamicLayout->PrepareItem(*pItem);
}


pItem = m_pMydynamicLayout->FindItem(m_pStaticSplit.m_hWnd);


if(pItem)
{
m_pMydynamicLayout->PrepareItem(*pItem);
}
}
}

这个修改在于允许在使用分割器控件等可调整原始布局比例的情况下重新更新布局,而mFC自带的布局管理器对FindItem PrePareItem等函数是非public

同时对话框通过GETMINMAXINFO也可以获取布局管理器的最小矩形,限制窗口调整时的最小大小






猜你喜欢

转载自blog.csdn.net/lif12345/article/details/79468688