Search code examples
mfcstatusbarcdialog

MFC: Adding a status bar to a CDialogEx that is resizable?


I thought it be nice to add a Status Bar with percentage and other information to a CDialogEx that is used for viewing an image. But it doesn't seem that you can simply use a CMFCStatusBar or a CStatusBar and have it just work.

I found various samples, but none of them have the statusbar outside the client area and moves as resized? The different methods simply create a statusbar and it ends up hidden under a horizontal scrollbar and if you resize the window, the statusbar is sitting there in the middle of the dialog.

Is there an easy way or full example of having a statusbar on a CDialogEx that can be resized like a normal window?


Solution

  • Is there an easy way or full example of having a statusbar on a CDialogEx that can be resized like a normal window?

    Yes! Once you have created the status bar you can add it to the dynamic layout for resizing:

    //This is where we actually draw it on the screen
    RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST,
        ID_INDICATOR_MEETING_TYPE);
    GetDynamicLayout()->AddItem(m_StatusBar.GetSafeHwnd(),
        CMFCDynamicLayout::MoveVertical(100), CMFCDynamicLayout::SizeHorizontal(100));
    

    I have a status bar (not CMFCStatusBar as it will not work, but CStatusBar is OK) on two dialogs in my application.


    When Dynamic Layout is not automatically enabled

    Here is an updated example for when Dynamic Layout is not automatically enabled for you (CDialogEx with no controls):

    BOOL CMyDlg::OnInitDialog()
    {
      CDialogEx::OnInitDialog();
    
      if (!m_StatusBar.Create(this)) {
        TRACE0("Failed to create status bar\n");
        return -1;
      }
    
      m_StatusBar.SetIndicators(indicators, _countof(indicators));
    
      RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);
    
      EnableDynamicLayout();
    
      auto pdlmanager=GetDynamicLayout();
      if (pdlmanager) {
        if (pdlmanager->Create(this)) {
          pdlmanager->AddItem(m_StatusBar.GetSafeHwnd(), CMFCDynamicLayout::MoveVertical(100), CMFCDynamicLayout::SizeHorizontal(100));
        }
      }
      // return TRUE unless you set the focus to a control
      // EXCEPTION: OCX Property Pages should return FALSE
    
      return TRUE;  
    }
    

    Catering for horizontal scroll bars

    NIf you have a horizontal scrollbar the StatusBar will end up above it; therefore you may have to create separate CWnd and add it to the dynamic layout (it would also be the nIDLeftOver of the RepositionBars()).

    Here's how you can add the a "view" window for the contents so scrollbars can be contained within the view area:

    BOOL CMyDlg::OnInitDialog()
    {
      CDialogEx::OnInitDialog();
    
      if (!m_StatusBar.Create(this)) {
        TRACE0("Failed to create status bar\n");
        return -1;
      }
    
      m_StatusBar.SetIndicators(indicators, _countof(indicators));
    
      CRect rc;
      GetClientRect(&rc);
    
      CString clsname=AfxRegisterWndClass(0);
      m_ImageView.Create(clsname, _T(""), WS_CHILD | WS_VISIBLE, rc, this, IDC_MY_VIEW);
    
      RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, IDC_MY_VIEW);
    
      EnableDynamicLayout();
    
      auto pdlmanager=GetDynamicLayout();
      if (pdlmanager) {
        if (pdlmanager->Create(this)) {
          pdlmanager->AddItem(m_StatusBar.GetSafeHwnd(), CMFCDynamicLayout::MoveVertical(100), CMFCDynamicLayout::SizeHorizontal(100));
          pdlmanager->AddItem(m_ImageView.GetSafeHwnd(), CMFCDynamicLayout::MoveNone(), CMFCDynamicLayout::SizeHorizontalAndVertical(100, 100));
        }
      }
    
      // return TRUE unless you set the focus to a control
      // EXCEPTION: OCX Property Pages should return FALSE
    
      return TRUE;  
    }