WTL обновить строку состояния из дочернего представления
В моем приложении SDI я использую 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 ответа
Есть несколько способов добиться этого:
Сделайте основной фрейм глобальным и добавьте функцию-член (скажем,
SetStatusText
):void CMainFrame::SetStatusText(CString strText) { CStatusBarCtrl sb(m_hWndStatusBar); sb.SetText(SB_SIMPLEID, strText); } LRESULT CTabPeople::OnMenuRefresh(...) { g_pMainFrame->SetStatusText(_T("Status text")); }
Используйте статическую функцию-член с указателем this:
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")); }
Используйте API SendMessage с пользовательским идентификатором сообщения. Либо отправьте сообщение родительскому элементу управления (
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; }
Или вы можете просто отправить
SB_SETTEXT
сообщение, если у вас есть дескриптор строки состояния как глобальный:LRESULT CTabPeople::OnMenuRefresh(...) { ::SendMessage(g_hWndStatus, SB_SETTEXT, MAKEWPARAM(SB_SIMPLEID, 0), (LPARAM) _T("Status text")); }
Варианты 3 и 4, очевидно, устраняют необходимость наличия классов (не объектно-ориентированных). Вариант 2, вероятно, наиболее применим.
Я ничего не проверял, но у вас есть идея.:)
Просто рабочая версия моя
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");