CResizableFormView






3.50/5 (27投票s)
2000年11月29日

193209

2548
Paolo Messina 的 CResizableDialog 概念的扩展
引言
这个编程项目的灵感来源于:a) Paolo Messina 的 关于他的 CResizableDialog 代码的文章,以及 b) 我提到我已经调整了一个 CFormView
来在一个嵌入式属性表中使用 CResizablePage
。
在表单视图中使用 CResizablePage
与这个相比只是一个小的练习。我最终做出了一个 CResizableFormView
。这段代码完全基于 Paolo 的 CResizableDialog
代码。
如果您不想了解我是如何做的,请跳到本文底部,了解如何自己实现它。
概念
在我看来,如果对话框可以从这项技术中受益,那么表单视图也可以,因为毕竟,表单视图只不过是一个像对话框一样工作的视图。它甚至使用与对话框一样的资源模板。最初
最初的编码相当简单。我创建了一个名为CResizableFormView
的 CFormView 派生类。接下来,我复制了所有实用程序函数(不是由类向导提供的函数)。然后,我评估了 Paolo 代码使用的某些 Windows 消息的需求/可用性。我最终只需要处理 WM_SIZE
命令。最后,我决定最小/最大窗口大小代码不适用于表单视图,因此我删除了涉及 CResizableDialog
的这方面代码。实现
在使代码编译之后,我尝试基于我的新CResizableFormView
派生一个新类。经过一些实验,我发现我无法在 InitialUpdate
完成之前使用 AddAnchor
函数。如果我不遵循此规则,控件将无法正确调整大小。void CFormview2View::OnInitialUpdate() { CResizableFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); // put our code AFTER the stuff ClassWizard gave us. AddAnchor(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT); AddAnchor(IDC_GROUP1, TOP_LEFT, BOTTOM_LEFT); }
小问题
在玩弄调整大小一段时间后,我发现如果我将视图窗口缩小到小于原始对话框模板,则会发生一些与“锚定”控件相关的不良情况。- 列表框完全消失了,只有在我水平放大视图时才会部分出现。
- 围绕单选按钮的组合框会不断调整大小,直到什么都不剩(组合框)。
那时很明显,我必须包含一些代码来限制控件在达到(或小于)其原始大小后调整大小。我还假设我必须注意获取正确的原始大小,这意味着我必须在窗口第一次允许调整大小之前确定每个控件的大小。假设程序员可以选择做一些事情而不是使用对 MFC 的 ResizeParentToFit
的调用,我必须确保在创建视图后立即获取控件信息,但在其调整大小之前。我希望尽可能少地影响 Paolo 的原始代码,所以修复工作花了很长时间。
为了解决这个问题,我创建了一个 CTypedPtrArray
来保存一个新的结构。此结构包含每个“锚定”控件的原始大小和位置,以及其 HWND
和控件 ID。为了支持该结构,我还必须编写几个新函数。详细信息如下:
void CResizableFormView::AddResizedControls()
此函数负责确定指定控件的 HWND
和窗口大小/位置,以及存储其锚点位置。参数列表与原始 AddAnchor
函数相同。收集所有这些信息后,控件将添加到新的 CTypedPtrArray
中以安全保存。
void CResizableFormView::AnchorControls()
此函数实际上会为程序员在调用 AddResizedControls
函数时指定的每个控件调用 AddAnchor
。这在后面会很明显。
结果
为了实现大小/位置修复,在CResizableFormView
派生类中需要新的执行顺序。OnInitialUpdate
函数现在如下所示:void CFormview2View::OnInitialUpdate() { // jms - 11/28/00 - new code starts // We do this here because we need to get the *original* size of the // controls *before* the dialog is sized the first time. I don't know // what will happen if we do it after, but I didn't want to find out. // // Since we do this here, I decided to pass the parameters needed by // the AddAnchor() function to eliminate the need to call AddAnchor // from this function (after the view had been resized). AddResizedControl(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT); AddResizedControl(IDC_GROUP1, TOP_LEFT, BOTTOM_LEFT); // jms - 11/28/00 - new code stops CResizableFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); // Normally, we would put the calls to AddAnchor AFTER we call // ResizeParentToFit(). //AddAnchor(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT); //AddAnchor(IDC_GROUP1, TOP_LEFT, BOTTOM_LEFT); // jms - 11/28/00 - new code starts // Now anchor the controls we specified earlier in this function. We call // this function because it cycles thru the list of controls that are to // be resized. This prevents us from having to call AddAnchor (lots of // redundant typing at this point). AnchorControls(); }
但是,如果您希望视图不根据对话框模板调整自身大小呢?这很容易。只需计算表单视图的父窗口的大小,然后在退出 OnInitialUpdate
之前调用 MoveWindow
。这是一个例子:
void CFormview2View::OnInitialUpdate() { AddResizedControl(IDC_LIST1, TOP_LEFT, BOTTOM_RIGHT); AddResizedControl(IDC_GROUP1, TOP_LEFT, BOTTOM_LEFT); AddResizedControl(IDC_IPADDRESS1, BOTTOM_RIGHT); CResizableFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); // Here's where the difference lies. We don't want to call ResizeParentToFit() until // AFTER we calculate the true (initial) size of the parent frame. CRect rectFrame; CFrameWnd* pFrame = GetParentFrame(); ASSERT_VALID(pFrame); pFrame->GetWindowRect(rectFrame); CSize size = rectFrame.Size(); // Now, we can call ResizeParentToFit() and anchor the controls. ResizeParentToFit(FALSE); AnchorControls(); // Finally, we need to actually resize the frame to its original dimensions. This // allows the anchor code to work with its existing code. pFrame->MoveWindow(rectFrame, TRUE); }
最后的定论
要实现 CResizableFormView
,请执行以下步骤:
- 创建一个
CFormView
类及其对话框模板(如有必要)。 - 将您的
CFormView
派生类的基类更改为CResizableFormView
。 - 在派生表单视图的头文件中包含
#include "ResizableFormView.h"
。 - 如果该函数不存在,请使用类向导覆盖
OnInitialUpdate
函数。 - 为每个将要调整大小/重新定位的控件调用
AddResizedControls
。这必须在调用基类的OnInitialUpdate
**之前** 进行。 - 调用
AnchorControls
。这必须在调用ResizeParentToFit
**之后** 进行。