65.9K
CodeProject 正在变化。 阅读更多。
Home

关于 CMFCToolBar 的一些说明 – 停靠大按钮和 MDIClientArea 的使用

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (12投票s)

2013年7月4日

CPOL

4分钟阅读

viewsIcon

144793

downloadIcon

2023

将 CToolBar 更新到 MFC 功能包 (2008)

引言

本文讨论 CMFCToolBar 类,并记录了从 CToolBar 更改的许多细节,以及如何使 CMFCToolBar 按预期方式工作。

背景

CMFCToolBar 是 2008 年添加的 MFC 功能包的一部分,它取代了 CToolBar。本文使用了 Visual Studio 2012 Update 2。

通常,创建工具栏的代码位于 CMainFrame::OnCreate 方法中。下面展示了创建两个工具栏,以处理带有大按钮的工具栏和带有标准大小按钮的另一个工具栏。如果只使用标准大小的按钮,可以跳过处理 szImageszButton 的代码。 此代码对于正确显示大按钮是必要的。首先,声明 m_nToolBarm_nAnalysisToolCMFCToolBar

DWORD dwCtrlStyle = TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CBRS_SIZE_DYNAMIC;
DWORD dwStyle = AFX_DEFAULT_TOOLBAR_STYLE;
CMFCToolBarInfo tbi, tbiA;
const CRect r1(1, 1, 1, 1); 
if (!m_nToolBar.CreateEx(this, dwCtrlStyle, dwStyle, r1, IDR_MAINFRAME) ||
        !m_nToolBar.LoadToolBarEx(IDR_MAINFRAME, tbi, TRUE)
{
    return -1;      // fail to create
} 
// this permits large buttons (>16x15) to display correctly
CSize szImage, szButton;
szImage = m_nToolBar.GetImageSize();
szButton.cx = szImage.cx + 6; // button size must be at least image size + 6
szButton.cy = szImage.cy + 6;
m_nToolBar.SetMenuSizes(szButton, szImage);

if (!m_wndStatusBar.Create(this) || 
        !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))
{
    return -1;      // fail to create
}

// Adding Extra ToolBar
if (!m_nAnalysisTool.CreateEx( this, dwCtrlStyle, dwStyle, r1, IDR_ANALYSIS_TOOL) ||
        !m_nAnalysisTool.LoadToolBarEx(IDR_ANALYSIS_TOOL, tbiA, TRUE))
{
    return -1;      // fail to create
} 
szImage = m_nAnalysisTool.GetImageSize();
szButton.cx = szImage.cx + 6;
szButton.cy = szImage.cy + 6;
m_nAnalysisTool.SetMenuSizes(szButton, szImage);

dwStyle = CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC;
m_nToolBar.SetPaneStyle(m_nToolBar.GetPaneStyle() | dwStyle);
m_nAnalysisTool.SetPaneStyle(m_nToolBar.GetPaneStyle() | dwStyle); 
EnableDocking(CBRS_ALIGN_ANY);

请注意,如果 CMFCToolBarInfo 为空,则 LoadToolBarEx 会填充它,因此每个工具栏使用一个新的 CMFCToolBarInfo

CMFCToolBar 放置示例

在测试代码之前,请务必删除注册表项 *HKCU\Software\CompanyName\ProgramName\Workspace*,否则将使用上次的工具栏放置,如果您使用 WindowPlacement 加载注册表。

如果使用 CBRS_ALIGN_ANY,工具栏默认在顶部对齐。

现在,有三个例子说明工具栏的放置

示例 1

默认行为是工具栏堆叠在顶部。 这种外观并不总是令人满意。

图 1 默认停靠
m_nToolBar.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_nToolBar);

m_nAnalysisTool.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_nAnalysisTool);

示例 2

要使 CMFCToolBar 最初停靠在一侧,然后可以自由地停靠在任何一侧,首先仅通过 EnableDocking 强制所需的侧,然后调用 DockPane。这样可以正确放置工具栏。然后可以再次调用 EnableDocking 并允许更多侧有效。 图下方的三行显示了这一点。

图 2 停靠顶部和底部
m_nToolBar.EnableDocking(CBRS_ALIGN_ANY); 
DockPane(&m_nToolBar); 
m_nAnalysisTool.EnableDocking(CBRS_ALIGN_BOTTOM); 
DockPane(&m_nAnalysisTool);
m_nAnalysisTool.EnableDocking(CBRS_ALIGN_ANY);

示例 3

要在顶部的同一栏上强制并排停靠,首先停靠最右侧的窗格,然后将额外的窗格添加到其左侧。

图 3 并排停靠
m_nToolBar.EnableDocking(CBRS_ALIGN_ANY); 
m_nAnalysisTool.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_nAnalysisTool);  
m_dockManager.DockPaneLeftOf(&m_nToolBar, &m_nAnalysisTool);

编码说明

不要尝试使用 DockToFrameWindow(),此方法仅适用于 CDockablePane 类,而 CMFCToolBar 的层次结构中没有 CDockablePane。 当从 CMFCTooBar 类调用时,DockToFrameWindow() 方法除了返回 false 之外什么也不做。人们会认为 CMFCToolBar 类会继承自 CDockablePane 类,但事实并非如此。

CMFCToolBar 不负责自行切换。 如果你使用了 ID_VIEW_TOOLBARCToolBar 之前会负责切换。 要现在处理切换,需要在消息映射中进行以下添加。(这通常在 CMainFrame 类中完成。)

ON_COMMAND(ID_VIEW_TOOLBAR, OnViewControls)
ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, OnUpdateViewControls) 
ON_COMMAND(ID_VIEW_PLOTCONTROLS, OnViewAnalysisControls) 
ON_UPDATE_COMMAND_UI(ID_VIEW_PLOTCONTROLS, OnUpdateViewAnalysisControls)

然后添加方法。

// Toggle the ToolBar on and off.
void CMainFrame::OnViewControls() // Called when View->ToolBar menuitem is pressed.
{
  m_nToolOpen = !m_nToolOpen;
  ShowPane(&m_nToolBar, m_nToolOpen, FALSE, TRUE);
  // Force resize of toolbar when the larger toolbar is removed
  // (a problem if both toolbars are on the same line)   
  if (!m_nToolOpen) RecalcLayout();
  m_wndClientArea.Invalidate();  // force redraw to correct for image shifting
}

void CMainFrame::OnUpdateViewControls(CCmdUI* pCmdUI)
// Called when View is pressed or when View->ToolBar menuitem is displayed
{
    pCmdUI->SetCheck(m_nToolOpen);
}

// Toggle the Analysis ToolBar on and off. void CMainFrame::OnViewAnalysisControls()
// Called when View->Analysis ToolBar menuitem is pressed.
{
  m_nAnalysisToolOpen = !m_nAnalysisToolOpen;
  ShowPane(&m_nAnalysisTool, m_nAnalysisToolOpen , FALSE, TRUE);
  m_wndClientArea.Invalidate();  // force redraw to correct for image shifting
}

void CMainFrame::OnUpdateViewAnalysisControls(CCmdUI* pCmdUI)
// Called when View is pressed or when View->ToolBar menuitem is displayed
{
    pCmdUI->SetCheck(m_nAnalysisToolOpen);
}

CMFCToolBar 和在 MDIClientArea 上绘图

CMFCToolBar 和在 MDIClientArea 上绘图存在问题。 打开和关闭工具栏或移动停靠位置可能会导致 MDIClientArea 上的图像损坏。 CToolBar 类总是触发到 MDIClientOnDraw 消息。 对于 MFC 2008 功能包,无法进行子类化,因此无法覆盖 OnDraw 例程。

除非在 MDIClientArea 上绘图,否则上面的 OnView… 方法不需要 m_wndClientArea.Invalidate() 行。 在客户端区域中绘图时,当工具栏操作导致客户端区域更改大小时,需要这些行,因为调整大小会破坏你的图像。

包含 RecalcLayout() 调用是为了处理关闭具有较大按钮大小的工具栏并且两个工具栏位于同一行的情况;如果没有强制,工具栏的区域不会针对较小的按钮调整大小。 使用旧的 CToolBar 类会自动处理这些情况。

移动工具栏也可能会破坏你在客户端区域上的绘图。 我编写了一个小类 CMFCToolBarEx 来扩展 CMFCToolBar 并覆盖 OnAfterChangeParent()。 *CMFCToolBarEx.h* 中的代码是

#pragma once
 
// CMFCToolBarEx.h
 
class CMFCToolBarEx : public CMFCToolBar
{
    DECLARE_DYNAMIC(CMFCToolBarEx)
 
public:
    CMFCToolBarEx();
    virtual ~CMFCToolBarEx();
 
protected:
    DECLARE_MESSAGE_MAP()
public:
    virtual void OnAfterChangeParent(CWnd* pWndOldParent);
};

*CMFCToolBarEx.cpp* 中的代码是

// MFCToolBarEx.cpp : implementation file
//
 
#include "stdafx.h"
#include "MainFrm.h"
#include "MFCToolBarEx.h"
 
// CMFCToolBarEx
 
IMPLEMENT_DYNAMIC(CMFCToolBarEx, CMFCToolBar)
 
CMFCToolBarEx::CMFCToolBarEx()
{
}
 
CMFCToolBarEx::~CMFCToolBarEx()
{
}
 
BEGIN_MESSAGE_MAP(CMFCToolBarEx, CMFCToolBar)
END_MESSAGE_MAP()
 
// CMFCToolBarEx message handlers
 
 
// Overrides
 
void CMFCToolBarEx::OnAfterChangeParent(CWnd* pWndOldParent)
{
    CMainFrame* pFrame = (CMainFrame*) AfxGetMainWnd();
    if (pFrame)
    {
        CRect rect;
        pFrame->GetClientRect(rect);
        pFrame->InvalidateRect(rect);
    }
    CMFCToolBar::OnAfterChangeParent(pWndOldParent);
}

如果你有两组图像想要显示在工具栏上而不更改按钮的 ID,则以下代码将更改按钮上的图像。 IDR_ANANLYSIS_TOOLIDR_ANALYSIS_TOOL_RATE 是具有相同大小的工具栏。 工具栏仅在按钮上的图像上有所不同。

在 CMFCToolBar 上交换图像

如果你有两组图像想要显示在工具栏上而不更改按钮的 ID,则以下代码将更改按钮上的图像。 IDR_ANANLYSIS_TOOLIDR_ANALYSIS_TOOL_RATE 是具有相同大小的工具栏。 工具栏仅在按钮上的图像上有所不同。

void CMainFrame::SetAnalysisBar(void)
{
    BOOL b;
 
    m_nAnalysisTool.ResetAllImages();
    if (m_productionDataSet.m_PRODUCTION_MODE == 1)
        b = m_nAnalysisTool.LoadBitmap(IDR_ANALYSIS_TOOL);
    else
        b = m_nAnalysisTool.LoadBitmap(IDR_ANALYSIS_TOOL_RATE);
 
    if (b) m_nAnalysisTool.Invalidate();
}
© . All rights reserved.