您的位置:首页 > 其它

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

2012-08-25 12:22 405 查看
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();

}

即可。

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



注: 上面的修改会导致对话框刷新出现问题。所以,部分时候,我们需要自行调用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) 。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: