WTL从子视图更新状态栏

时间:2014-03-31 08:43:34

标签: winapi visual-c++ wtl

在我的SDI应用程序中,我正在使用this文章中的CWTLTabViewCtrl课程。

我想知道如何从子视图更新主框架的状态栏。

mainfrm.h上的代码:

CreateSimpleStatusBar();

// create tabctrl
CTabViewCtrl m_MainTabCtrl;
m_hWndClient = m_MainTabCtrl.Create(
            m_hWnd, rcDefault, NULL,
            WS_CHILD | WS_VISIBLE, WS_EX_STATICEDGE );
m_MainTabCtrl.AddPeopleTab(L"People);

CTabViewCtrl类的代码:

class CTabViewCtrl : public CWTLTabViewCtrl
{
public:

    CTabViewCtrl()
    {
    }

    virtual ~CTabViewCtrl()
    {
    }
    void AddPeopleTab(LPCTSTR inTabName)
    {
        auto tabPeople = CTabPeople;
        tabPeople->Create(*this, rcDefault, nullptr, WS_CHILD, WS_EX_STATICEDGE);
        AddTab(inTabName, *tabPeople, FALSE, 0, (LPARAM)theProcessesView);
    }
public:
    DECLARE_WND_SUPERCLASS(NULL, CWTLTabViewCtrl::GetWndClassName())

    BOOL PreTranslateMessage(MSG* pMsg)
    {
            pMsg;
            return FALSE;
    }

    BEGIN_MSG_MAP_EX(CTabViewCtrl)
        REFLECT_NOTIFICATIONS()
        CHAIN_MSG_MAP(CWTLTabViewCtrl)
    END_MSG_MAP()
};

CTabPeople课程的代码(从此视图我想更新mainfrm.h的状态栏):

class CTabPeople : public CWindowImpl<CTabPeople, CListViewCtrl>,
                            public CCustomDraw<CTabPeople>
{
[snip]

public:
    DECLARE_WND_SUPERCLASS(NULL, CListViewCtrl::GetWndClassName())

    BOOL PreTranslateMessage(MSG* pMsg)
    {
        pMsg;
        return FALSE;
    }

    BEGIN_MSG_MAP(CTabPeople)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)
        MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
        COMMAND_ID_HANDLER(IDM_PROCESSTAB_REFRESH, OnMenuRefresh)
        REFLECTED_NOTIFY_CODE_HANDLER(LVN_COLUMNCLICK, OnColumnClick)
        CHAIN_MSG_MAP_ALT(CCustomDraw, 1)
    END_MSG_MAP()

    LRESULT OnMenuRefresh(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&bHandled)
    {
        // Here i would like to update the status bar created at the mainfrm.h
        // something like UISetText(0, L"Updating..");
    }

  [snip]
}

从我所做的研究看来,有两种方法可以更新状态栏:

  • 使用状态栏的句柄直接从CTabPeople视图
  • 通过向mainfrm循环发送消息来更新状态栏

我的问题是如何在我的代码中实现上述选项之一。

感谢。

2 个答案:

答案 0 :(得分:4)

有很多方法可以实现这一目标:

  1. 使主框架成为全局框架并添加成员函数(比如SetStatusText):

    void CMainFrame::SetStatusText(CString strText)
    {
        CStatusBarCtrl sb(m_hWndStatusBar);
        sb.SetText(SB_SIMPLEID, strText);
    }
    
    LRESULT CTabPeople::OnMenuRefresh(...)
    {
        g_pMainFrame->SetStatusText(_T("Status text"));
    }
    
  2. 使用带有&#39;此指针的静态成员函数&#39;:

    class CMainFrame;// Forward declaration
    class CMainFrame : public ...
    {
    public:
        CMainFrame() { this_ptr = this; }
    
        static void SetStatusText(CString strText)
        {
            CStatusBarCtrl sb(this_ptr->m_hWndStatusBar);
            sb.SetText(SB_SIMPLEID, strText);
        }
    
        static CMainFrame* this_ptr;
    };
    
    // Initialization (in .cpp file)
    CMainFrame* CMainFrame::this_ptr = NULL;
    
    LRESULT CTabPeople::OnMenuRefresh(...)
    {
        CMainFrame::SetStatusText(_T("Status text"));
    }
    
  3. 将SendMessage API与自定义消息标识符一起使用。将消息发送到父控件(CTabViewCtrl),然后父控件将消息传递给父控件或主框架,或直接将其发送到主框架。最后一种情况要求您知道有多少嵌套窗口,或者您可以使用主窗口句柄。

    LRESULT CTabPeople::OnMenuRefresh(...)
    {
        // Parent control processes the message
        ::SendMessage(GetParent(), MY_STATUS_MSG, (WPARAM) _T("Status text"), 0);
        // Main frame processes the message
        ::SendMessage(::GetParent(GetParent()), MY_STATUS_MSG, (WPARAM) _T("Status text"), 0);
        ::SendMessage(g_hWndMain, MY_STATUS_MSG, (WPARAM) _T("Status text"), 0);
    }
    

    在主框架中添加消息处理程序和/或CTabViewCtrl

    BEGIN_MSG_MAP(CMainFrame)
        ...
        MESSAGE_HANDLER(MY_STATUS_MSG, OnSetStatusMsg)
    END_MSG_MAP()
    
    LRESULT CMainFrame::OnSetStatusMsg(UINT, WPARAM wParam, LPARAM, BOOL&)
    {
        CStatusBarCtrl sb(m_hWndStatusBar);
        sb.SetText(SB_SIMPLEID, (LPCTSTR) wParam);
        return FALSE;
    }
    
  4. 如果您将状态栏句柄设置为全局,则可以发送SB_SETTEXT消息:

    LRESULT CTabPeople::OnMenuRefresh(...)
    {
        ::SendMessage(g_hWndStatus, SB_SETTEXT, MAKEWPARAM(SB_SIMPLEID, 0), (LPARAM) _T("Status text"));
    }
    
  5. 选项3和4显然忽略了具有类(不是面向对象)的观点。选项2可能是最适用的。

    我还没有测试过这个,但你有这个想法。 :)

答案 1 :(得分:0)

简单地使用我的版本:

为MainFrm.h:

class CMainFrame : 
    public CFrameWindowImpl<CMainFrame>, 
    public CUpdateUI<CMainFrame>,
    public CMessageFilter, public CIdleHandler
{
public:
  DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)
  CMainFrame() { this_ptr = this; }
  static CMainFrame* this_ptr;
  void SetStatusText(std::wstring strText);
  //...
}

MainFrm.cpp中

CMainFrame* CMainFrame::this_ptr = nullptr;

// m_hWndStatusBar is from atlframe.h
void CMainFrame::SetStatusText(std::wstring strText)
{
  ::SetWindowText(m_hWndStatusBar, strText.c_str());
}

other.cpp

CMainFrame::this_ptr->SetStatusText(L"program ready");