Hanan
Hanan

Reputation: 1179

WTL update status bar from child view

In my SDI application i am using the CWTLTabViewCtrl class from this article.

I would like to know how to update the status bar at the main frame from the child view.

The code at the 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);

The code at the CTabViewCtrl class:

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()
};

The code at my CTabPeople class (from this view i want to update the status bar at the 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]
}

From the research i have done it seems that there is two ways to update the status bar:

My question is how to implement one of the above options in my code.

Thanks.

Upvotes: 1

Views: 734

Answers (2)

sailfish009
sailfish009

Reputation: 2927

simply working version of mine:

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");

Upvotes: 0

Midas
Midas

Reputation: 7131

There are a number of ways to achieve this:

  1. Make the main frame a global and add a member function (say 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. Use a static member function with a 'this pointer':

    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. Use the SendMessage API with a custom message identifier. Either send the message to the parent control (CTabViewCtrl), which in turn passes the message to its parents or the main frame, or send it to the main frame directly. The last case requires that you know how many nested windows there are, or you can use the main window handle as you already mentioned.

    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);
    }
    

    Add a message handler in the main frame and/or 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. Or you can simply send the SB_SETTEXT message if you have the status bar handle as a global:

    LRESULT CTabPeople::OnMenuRefresh(...)
    {
        ::SendMessage(g_hWndStatus, SB_SETTEXT, MAKEWPARAM(SB_SIMPLEID, 0), (LPARAM) _T("Status text"));
    }
    

Option 3 and 4 obviously take away the point of having classes (not object-oriented). Option 2 is probably the most applicable.

I haven't tested anything of this, but you have the idea. :)

Upvotes: 4

Related Questions