在对话框里面加入工具条CMFCToolBar

VC 2010 + MFC : 在对话框里面加入工具条CMFCToolBar

By:章永辉

  

         VC 2010 + MFC 新库的资料很少,以下给出本人的实现方法。

  

      (1)古典的工具条

  

(a)对话框中加入CMFCToolBar的成员变量。
CMFCToolBar m_wndToolBar;

  

(b)创建工具条并显示之
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD   |   WS_VISIBLE   |   CBRS_TOP   |   CBRS_TOOLTIPS   |CBRS_FLYBY   |   CBRS_BORDER_BOTTOM) ||
  !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
  TRACE0("未能创建工具栏\n");
  return -1;      // 未能创建
}

m_wndToolBar.AdjustLayout();

这句" m_wndToolBar.AdjustLayout();"非常重要,否则,工具条将不显示。

  

至此,我们看到了XP风格的工具条,本人称之为古典的工具条,——相对Feature Pack界面库而言,这个XP风格的工具条确实是很古老的了。

  

         (2)Feature Pack风格的工具条

        通过前面的努力,我们看到了老土的工具条,虽然如此,我们还得继续努力,否则,这样的工具条和Ribbon界面不搭调,有还不如没有。

        所以,我继续跟踪,结果显示,是m_bIsDlgControl成员变量在作祟。但是这是保护类型的变量,没法直接修改的,所以,我继承之。

  

代码:

加上头文件包含。
#include "SegMFCToolBar.h"

  


CMFCToolBar m_wndToolBar;

改为:
CSegMFCToolBar m_wndToolBar;

  


m_wndToolBar.AdjustLayout();

前面加上:
m_wndToolBar.SetIsDlgControl(FALSE);

  

//SegMFCToolBar.h头文件

#pragma once


// CSegMFCToolBar

class CSegMFCToolBar : public CMFCToolBar
{
DECLARE_DYNAMIC(CSegMFCToolBar)

public:
CSegMFCToolBar();
virtual ~CSegMFCToolBar();

protected:
DECLARE_MESSAGE_MAP()

public:
void SetIsDlgControl(BOOL b)
{
  m_bIsDlgControl=b;
}
};


// SegMFCToolBar.cpp : 实现文件
//

#include "stdafx.h"
#include "AdServer.h"
#include "SegMFCToolBar.h"


// CSegMFCToolBar

IMPLEMENT_DYNAMIC(CSegMFCToolBar, CMFCToolBar)

CSegMFCToolBar::CSegMFCToolBar()
{

}

CSegMFCToolBar::~CSegMFCToolBar()
{
}


BEGIN_MESSAGE_MAP(CSegMFCToolBar, CMFCToolBar)
END_MESSAGE_MAP()

  

  

至此,完美解决。

  

20110902补充:

  

m_wndToolBar.AdjustLayout();

改为

m_wndToolBar.AdjustSizeImmediate();

  

否则,对话框的工具条大小会不正确的。 

  

20110903补充: 

          虽然如此,但是我们无法响应工具条的事件,也无法处理ON_UPDATE_COMMAND_UI。所以,我们需要加入以下两句代码:
m_wndToolBar.SetOwner(this);
m_wndToolBar.SetRouteCommandsViaFrame(FALSE);

  

              这样,还是不够的!我们还得处理一下WM_IDLEUPDATECMDUI消息。如下:

//消息处理函数的声明
afx_msg LRESULT OnIdleUpdateCmdUI(WPARAM wParam, LPARAM);

//消息映射
ON_MESSAGE(WM_IDLEUPDATECMDUI, &CSegMFCToolBar::OnIdleUpdateCmdUI)

//消息处理函数的实现
LRESULT CSegMFCToolBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM)
{
// the style must be visible and if it is docked
// the dockbar style must also be visible
if ((GetStyle() & WS_VISIBLE) &&
  (m_pParentDockBar == NULL || (m_pParentDockBar->GetStyle() & WS_VISIBLE)))
{
  CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
  if (pTarget == NULL)
   pTarget = AFXGetParentFrame(this);
  if (pTarget != NULL)
   OnUpdateCmdUI(pTarget, (BOOL)wParam);
}

return 0L;
}

效果图(背景透明的对话框专用工具条):

  

20110903补充(2):

再次发现问题,工具条的提示信息没有更新到状态栏! 为此,我们再次对MFC标准库进行手术。这次,我们需要重载ShowCommandMessageString虚函数。

函数声明:
void ShowCommandMessageString(UINT uiCmdId);
void SendMessageString(UINT uiTrackId);

函数实现: 

static inline BOOL __stdcall IsSystemCommand(UINT uiCmd)

{

    return(uiCmd >= 0xF000 && uiCmd < 0xF1F0);

}

void CSegMFCToolBar::ShowCommandMessageString(UINT uiCmdId)

{

    if (m_hookMouseHelp != NULL)

    {

        return;

    }

    if (uiCmdId == (UINT) -1 || uiCmdId == AFX_CUSTOMIZE_INTERNAL_ID)

    {

        SendMessageString(AFX_IDS_IDLEMESSAGE);

        return;

    }

    UINT uiTrackId = uiCmdId;

    if (IsSystemCommand(uiCmdId))

    {

        uiTrackId = ID_COMMAND_FROM_SC(uiCmdId);

        ASSERT(uiTrackId >= AFX_IDS_SCFIRST && uiTrackId < AFX_IDS_SCFIRST + 31);

    }

    else if (uiCmdId >= AFX_IDM_FIRST_MDICHILD)

    {

        // all MDI Child windows map to the same help id

        uiTrackId = AFX_IDS_MDICHILD;

    }

    SendMessageString(uiTrackId);

}

void CSegMFCToolBar::SendMessageString(UINT uiTrackId)

{

    CFrameWnd* pTarget=(CFrameWnd*)GetOwner();

    if (pTarget!=NULL && pTarget->IsFrameWnd())

    {

        pTarget->SendMessage(WM_SETMESSAGESTRING, (WPARAM) uiTrackId);

        return;

    }

    pTarget=(CFrameWnd*)AfxGetMainWnd();

    if (pTarget!=NULL && pTarget->IsFrameWnd())

    {

        pTarget->SendMessage(WM_SETMESSAGESTRING, (WPARAM) uiTrackId);

        return;

    }

}

20110924补充:

经测试发现,工具条上面并没有响应ON_UPDATE_COMMAND_UI,所以,我们还得加入代码。以下代码仅对模式对话框有效,非模式对话框,请自行作修改。

方法一:我们重载一下ContinueModal函数。


virtual BOOL ContinueModal();


BOOL CSegDialogEx::ContinueModal()
{
if (m_Toolbar!=NULL)
{
  if( m_Toolbar->IsWindowVisible() )
  {
   CFrameWnd* pParent = ( CFrameWnd* ) m_Toolbar->GetParent();
   if( pParent )
   {
    m_Toolbar->OnUpdateCmdUI( pParent, ( WPARAM ) TRUE );
   }
  }

  CMenu* pMainMenu = GetMenu();
  if (pMainMenu!=NULL)
  {
   CCmdUI cmdUI;
   for (INT n = 0; n < pMainMenu->GetMenuItemCount(); ++n)
   {
    CMenu* pSubMenu = pMainMenu->GetSubMenu(n);
    if (pSubMenu!=NULL)
    {
     cmdUI.m_nIndexMax = pSubMenu->GetMenuItemCount();
     for (UINT i = 0; i < cmdUI.m_nIndexMax;++i)
     {
      cmdUI.m_nIndex = i;
      cmdUI.m_nID = pSubMenu->GetMenuItemID(i);
      cmdUI.m_pMenu = pSubMenu;
      cmdUI.DoUpdate(this, FALSE);
     }
    }
   }
  }
}

return CDialogEx::ContinueModal();
}

即可。

工具条按钮无效时 ,灰色蒙板效果图:

VC 2010 + MFC : 在对话框里面加入工具条CMFCToolBar - Seg-Soft -

注: 上面的修改会导致对话框刷新出现问题。所以,部分时候,我们需要自行调用RedrawWindow来强制重绘其他控件。其实,也可以不加这个函数,而是,在需要的时候,调用一下工具条的OnUpdateCmdUI即可。

然而,对于动态调整大小的对话框,这个方法会导致严重的界面刷新问题。此方法不是很好。

方法二:
SendMessageToDescendants(WM_IDLEUPDATECMDUI,
  (WPARAM)TRUE, 0, TRUE, TRUE);

为了更省事儿,我这样:

BOOL CSegDialogEx::ContinueModal()
{
SendMessageToDescendants(WM_IDLEUPDATECMDUI,
  (WPARAM)TRUE, 0, TRUE, TRUE);

return CDialogEx::ContinueModal();
}

这样,即可不必使用m_Toolbar指针!但效果和方法(1)一样。然而,这里我们至少可以得出结论:

(a)我们可以手动调用:m_Toolbar->OnUpdateCmdUI( pParent, ( WPARAM ) TRUE );

(b)我们也可以手动调用:SendMessageToDescendants(WM_IDLEUPDATECMDUI,
  (WPARAM)TRUE, 0, TRUE, TRUE);

显然,(b)是最好的方法,因为通用性更好。

由于ContinueModal的调用太过频繁了,所以,在ContinueModal里面修改,就会导致CPU耗用较高、界面刷新不正确等问题,

于是,我目前的解决方法是:手动调用(a) 。


最后,附上源代码。

By:章永辉

你可能感兴趣的:(windows,command,null,mfc,工具,border)