MFC 窗口大小变化控制类

效果如下图


参考及源码下载:https://www.codeproject.com/Articles/125068/MFC-C-Helper-Class-for-Window-Resizing#CreateFlowLayoutPanel

Introduction

In MFC, resizing or repositioning controls could be quite bothersome. If you are familiar with the .NET platform, things are much more simplified with the use of theAnchor and Dock properties of the Control class and design-time support for adding child controls to container controls. I tried to mimic some of these features of .NET, but the C++ way.

Background

There are other solutions available online (also on CodeProject.com) for this purpose. I think my solution stands out on its design, simplicity, and feature richness.

This solution allows you to do the following:

  • Anchor dialog controls
  • Create panels which contain other panels or UI controls
  • Restrict the size of dialog controls or panels by using minimum size and maximum size properties
  • Restrict the size of dialogs by using minimum size and maximum size properties
  • Create horizontal or vertical split containers
  • Freeze split containers so that users cannot use mouse to resize the panels
  • Set a panel of split containers to be fixed so that when the dialog resizes, the fixed panel will remain unchanged
  • Set the parent of dialog controls or panels (not related to Win32 SetParent API)
  • Show a resize grip on the lower right corner of the dialog using Visual Style (if the application supports it)
  • Show resize grips for splitter of split containers
  • Dock dialog control within its parent panel
  • Create flow layout panels

Let's take a brief look at how .NET does its resizing of child controls:

  • Anchor - It allows a child control to be anchored to the left, top, right, or bottom edge, or any combination of these four options.
  • Dock - It allows a child control to be docked to the left, top, right, and bottom edges.
  • Visual Studio Designer Support - If you place a frame control on a Windows Form and then drag a button control on top of the frame, the button becomes the actual child of the frame and grandchild of the Windows Form. But in the resource editor of MFC, if you place the frame on the dialog template and then drag a button on top of the frame control, the button is actually an immediate child of the dialog template and not the frame. This means if you move the frame, the button will not move.
  • SplitContainer - Creating splitter windows has never been this simple since the invention of this control. It has two panels which can host other controls inside.
  • FlowLayout - Represents a panel that dynamically lays out its contents horizontally or vertically.

So in .NET, all controls are children or grandchildren of the Form; this creates a hierarchical structure of controls. When a parent is resized or repositioned, all its children are resized or repositioned according to theirAnchor or Dock property settings.

In my solution, I create a hierarchical structure of rectangles (CRect) instead. I have implemented theAnchor, Panel, SplitContainer, Dock, andFlowLayout concepts.

There are several classes in this solution, but CWndResizer is the only class that a developer will work with.

Typically, you will design your dialog template in the Visual Studio Resource Editor, and then in the dialog class implementation, you will have a member variable like this:

private:
    CWndResizer m_resizer;

The samples included with this article uses the CDialog class to demonstrate many features of this class. But this class can be used with any class derived fromCWnd (CDialog, CPropertyPage, CPropertySheet,CFrmWnd, CFormView, etc.).

Before this class can do anything, you must call the Hook method like this:

BOOL CExample1Dlg::OnInitDialog()
{
  CDialog::OnInitDialog();
  BOOL bOk = m_resizer.Hook(this);
  ASSERT(bOk == TRUE);
}

In this article, I will refer to this window (that is passed to the Hook method) as "hooked-window".

By calling this method, it places a window procedure hook in the WndProc chain.

When you call the Hook method, it stores the client area of the hooked-window in a structure calledCPanel. A panel is mainly a rectangle area given in client coordinates of the hooked-window. A panel can have zero or more panels as children. During the creation of a panel, you assign a unique name for the panel. The name is used to refer to the panel or find a panel. The client area of the hooked-window is the root of the hierarchy, and it is named_root.

Each panel has the Anchor, MinSize, and MaxSize properties (along with some other properties). But you cannot directly set or get the properties of a panel; instead, you will use member methods of theCWndResizer class.

The idea is that when a CPanel is resized or repositioned, all its children are also resized and repositioned relatively.

Now, let's look at some code snippets.

The following code will anchor the OK and Cancel buttons of your dialog to the bottom-right corner:

BOOL CExample1Dlg::OnInitDialog()
{
  CDialog::OnInitDialog();
  BOOL bOk = m_resizer.Hook(this);
  ASSERT(bOk == TRUE);

  bOk = m_resizer.SetAnchor(IDOK, ANCHOR_RIGHT | ANCHOR_BOTTOM);
  ASSERT(bOk == TRUE);

  bOk = m_resizer.SetAnchor(IDCANCEL, ANCHOR_RIGHT | ANCHOR_BOTTOM);
  ASSERT(bOk == TRUE);
}

If you want to create a panel and set its Anchor property to ANCHOR_HORIZONTALLY, you will do this:

BOOL CExample1Dlg::OnInitDialog()
{
  CDialog::OnInitDialog();
  BOOL bOk = m_resizer.Hook(this);
  ASSERT(bOk == TRUE);
  CRect rc(40, 40, 240, 240);
  bOk = m_resizer.CreatePanel(_T("MyNewPanel"), &rc);

  bOk = m_resizer.SetAnchor(_T("MyNewPanel"), ANCHOR_HORIZONTALLY);
  ASSERT(bOk == TRUE);

  ASSERT(bOk == TRUE);
}

About Clipping (Important)

This solution cannot clip any part of a dialog control or any part of a panel. ACPanel object does not have any window (HWND) associated with it in general. If a child panel is larger than its parent panel, the child's area that is outside the parent will be visible since neither the parent panel nor the child panel is actually a window. To circumvent this issue, we should set a reasonable minimum size of the parent panel by calling theSetMinimumSize method so that the parent is never smaller than the child's minimum size. You should also consider setting the minimum size of the hooked-window as well such that it can contain all panels within its client area.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值