对话框中工具条的空闲处理

http://blog.csdn.net/wsjeep/archive/2007/12/24/1964939.aspx
   大多数基于MFC文档视结构的程序,CToolBar对象都位于CMainFrame内,由于CMainFrame可以处理OnIdle消息,并最终在 CCmdUI::DoUpdate内实现对工具栏父窗口(即MainFrame::OnCmdMsg)的消息分发,所以在文档视图框架下,工具栏对 ON_UPDATE_COMMAND_UI的响应是没有问题的(如下图)。

     但如果工具栏位于对话框内,则无法响应ON_UPDATE_COMMAND_UI,这是由于CDialog没有对OnIdle的处理,从而无法实现对 DoUpdate的调用。网上有文章介绍一种方法,是在Dialog类内实现WM_INITMENUPOPUP的消息映射,但这种办法只能解决对话框内菜 单项的响应。这里介绍另外一种方法。

      步骤如下:

1,创建CCmdUI的子类CCustomizeToolCmdUI;本来用CToolCmdUI即可,但此类MFC并没有暴露出来,同时定义在bartool.cpp内;代码实现则可以直接拷贝CToolCmdUI。

2,创建一个CToolBar的子类CCustomizeToolBar;

3, CCustomizeToolBar内重载CToolBar的OnUpdateCmdUI(CCmdTarget* pTarget, BOOL bDisableIfNoHndler); CToolBar中此函数的第一参数类型是CMainFrame*用于表示工具栏的父窗口并将被用于消息的分 发,重载后直接用CCmdTarget,当然CDialog也可以(因为对话框类也派生于CCmdTarget)。     

4,CCustomizeToolBar内重载CToolBar的void _GetButton(int nIndex, TBBUTTON* pButton) const;  

5,在对话框类内重载ContinueModal,此函数在DoModal内被调用,用于判断是否需要修改状态。在此函数内,实现对OnUpdateCmdUI的调用,如下:m_dlgToolbar.OnUpdateCmdUI(this, 1);

//应该在这里调用,否则在ContinueModal导致程序无法正常退出。

LRESULT CFormBuilderDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    // TODO: Add your specialized code here and/or call the base class
    if(message == WM_KICKIDLE)
    {
        m_wndFormBar.OnUpdateCmdUI(this, 1);
    }  
    return CDialog::DefWindowProc(message, wParam, lParam);
}

 


6,CCustomizeToolBar内两个重载的函数可以拷贝CToolBar的实现代码,并作小量修改,代码如下:   

  

void  CCustomizeToolBar::OnUpdateCmdUI(CCmdTarget *  pTarget, BOOL bDisableIfNoHndler)
{
    CCustomizeToolCmdUI state;
    state.m_pOther 
= this;

    state.m_nIndexMax 
= (UINT)DefWindowProc(TB_BUTTONCOUNT, 00);
    
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
    
{
        
// get buttons state
        TBBUTTON button;
        _GetButton(state.m_nIndex, 
&button);
        state.m_nID 
= button.idCommand;

        
// ignore separators
        if (!(button.fsStyle & TBSTYLE_SEP))
        
{
            
// allow reflections
            if (CWnd::OnCmdMsg(0
                MAKELONG(CN_UPDATE_COMMAND_UI
&0xff, WM_COMMAND+WM_REFLECT_BASE), 
                
&state, NULL))
                
continue;

            
// allow the toolbar itself to have update handlers
            if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
                
continue;

            
// allow the owner to process the update
            state.DoUpdate(pTarget, bDisableIfNoHndler);
        }

    }


    
// update the dialog controls added to the toolbar
    UpdateDialogControls(pTarget, bDisableIfNoHndler);
}


void  CCustomizeToolBar::_GetButton( int  nIndex, TBBUTTON *  pButton)  const
{
    CToolBar
* pBar = (CToolBar*)this;
    
//VERIFY(pBar->DefWindowProc(TB_GETBUTTON, nIndex, (LPARAM)pButton));
    pBar->SendMessage(TB_GETBUTTON, nIndex, (LPARAM)pButton);
    
// TBSTATE_ENABLED == TBBS_DISABLED so invert it
    pButton->fsState ^= TBSTATE_ENABLED;
}

     不过以上的解决办法仍然有缺陷,即ContinueModal是用于模式对话框的,我不太清楚非模式是否会有调用;如果答案是否,则只能为对话框映射别的消息了。


 


//以下代码来自C:/Program Files/Microsoft Visual Studio 8/VC/atlmfc/src/mfc/bartool.cpp

因为原来toolbar的OnUpdateCmdUI参数是CFrameWnd。所以这里要重载toolbar。cmdui必须使用ToolCmdUI。

/
// CToolBar idle update through CToolCmdUI class

class CToolCmdUI : public CCmdUI        // class private to this file !
{
public: // re-implementations only
    virtual void Enable(BOOL bOn);
    virtual void SetCheck(int nCheck);
    virtual void SetText(LPCTSTR lpszText);
};

void CToolCmdUI::Enable(BOOL bOn)
{
    m_bEnableChanged = TRUE;
    CToolBar* pToolBar = (CToolBar*)m_pOther;
    ASSERT(pToolBar != NULL);
    ASSERT_KINDOF(CToolBar, pToolBar);
    ASSERT(m_nIndex < m_nIndexMax);

    UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
    if (!bOn)
    {
        nNewStyle |= TBBS_DISABLED;
        // If a button is currently pressed and then is disabled
        // COMCTL32.DLL does not unpress the button, even after the mouse
        // button goes up!  We work around this bug by forcing TBBS_PRESSED
        // off when a button is disabled.
        nNewStyle &= ~TBBS_PRESSED;
    }
    ASSERT(!(nNewStyle & TBBS_SEPARATOR));
    pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
}

void CToolCmdUI::SetCheck(int nCheck)
{
    ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
    CToolBar* pToolBar = (CToolBar*)m_pOther;
    ASSERT(pToolBar != NULL);
    ASSERT_KINDOF(CToolBar, pToolBar);
    ASSERT(m_nIndex < m_nIndexMax);

    UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) &
                ~(TBBS_CHECKED | TBBS_INDETERMINATE);
    if (nCheck == 1)
        nNewStyle |= TBBS_CHECKED;
    else if (nCheck == 2)
        nNewStyle |= TBBS_INDETERMINATE;
    ASSERT(!(nNewStyle & TBBS_SEPARATOR));
    pToolBar->SetButtonStyle(m_nIndex, nNewStyle | TBBS_CHECKBOX);
}

void CToolCmdUI::SetText(LPCTSTR)
{
    // ignore it
}

void CToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
    CToolCmdUI state;
    state.m_pOther = this;

    state.m_nIndexMax = (UINT)DefWindowProc(TB_BUTTONCOUNT, 0, 0);
    for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax; state.m_nIndex++)
    {
        // get buttons state
        TBBUTTON button;
        _GetButton(state.m_nIndex, &button);
        state.m_nID = button.idCommand;

        // ignore separators
        if (!(button.fsStyle & TBSTYLE_SEP))
        {
            // allow reflections
            if (CWnd::OnCmdMsg(0,
                MAKELONG(CN_UPDATE_COMMAND_UI&0xff, WM_COMMAND+WM_REFLECT_BASE),
                &state, NULL))
                continue;

            // allow the toolbar itself to have update handlers
            if (CWnd::OnCmdMsg(state.m_nID, CN_UPDATE_COMMAND_UI, &state, NULL))
                continue;

            // allow the owner to process the update
            state.DoUpdate(pTarget, bDisableIfNoHndler);
        }
    }

    // update the dialog controls added to the toolbar
    UpdateDialogControls(pTarget, bDisableIfNoHndler);
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值