Reputation: 1179
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:
CTabPeople
view using the handle of the status barMy question is how to implement one of the above options in my code.
Thanks.
Upvotes: 1
Views: 734
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
Reputation: 7131
There are a number of ways to achieve this:
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"));
}
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"));
}
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;
}
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