CStatusBarCtrl自动调整大小

时间:2017-06-03 16:41:09

标签: winapi mfc

在MFC中,当父窗口更新时,状态栏不应自动调整大小吗?我需要使用缺少的设置才能实现此目的吗?

class Mainwindow {
public:
    MainWindow() {
        Create(NULL, _T("Main Window"));
}
afx_msg int OnCreate(LPCREATESTRUCT lp) {
        // Status bar
        CRect rc;
        this->GetClientRect(&rc);
        std::array<int, 3> sb = { rc.right / 3,rc.right / 3 * 2,-1 };
        status_bar.Create(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, CRect(0, 0, 0, 0), this, IDS_STATUSBARCTRL);
        status_bar.SetParts(3, sb.data());
        status_bar.SetTipText(1, _T("Tooltip text"));
        status_bar.SetText(_T("Left"), 0, SBT_POPOUT);
        status_bar.SetText(_T("Middle"), 1, 0);
        status_bar.SetText(_T("Right"), 2, 0);
        return TRUE;
    }

// This resizes the status bar fine, but shouldn't MFC handle it?
       afx_msg void OnSize(UINT, int cx, int cy) {
        status_bar.SendMessage(WM_SIZE, 0, 0);
    }

    DECLARE_MESSAGE_MAP()

private:
    CStatusBarCtrl status_bar;
};


BEGIN_MESSAGE_MAP(MainWindow,CFrameWnd)
    ON_WM_CREATE()
    ON_WM_SIZE()
END_MESSAGE_MAP()

2 个答案:

答案 0 :(得分:1)

只是扫描MFC代码......(目前无法让我的调试器逐步完成,等等)

在CFrameWnd类中,有一个名为RecalcLayout的函数。 MSDN说:

在打开或关闭标准控制条或调整框架窗口大小时由框架调用。

RecalcLayout调用CWnd :: RepositionBars。函数内部是注释:

// walk kids in order, control bars get the resize notification
//   which allow them to shrink the client area

看起来通知是通过WM_SIZEPARENT消息完成的:

a)CControlBar类有一个WM_SIZEPARENT消息处理程序

b)CStatusBarCtrl是从CWnd而不是CControlBar派生的,因此不会得到消息

解决方案:我会按应用程序向导的方式执行此操作 - 将状态栏成员变量设为CStatusBar。 (从CControlBar派生)从那里你可以调用GetStatusBarCtrl()。

// .h
CStatusBar status_bar;

// .cpp
if (!status_bar.Create(this))
{
    TRACE0("Failed to create status bar\n");
    return -1;
}

auto& statusBarCtrl = status_bar.GetStatusBarCtrl();
statusBarCtrl.SetParts(3, sb);
// etc.

答案 1 :(得分:0)

我在这里确实有一个不避免使用 CStatusBarCtrl 的替代解决方案。这是一个老问题,但如果您有兴趣,请继续阅读:

如果你仔细观察,无论何时创建 CStatusBarCtrl,它总是知道它在父窗口上的确切位置,而忽略 cost RECT& rect 参数。所以它有能力调整自己的大小。您只需在父窗口调整大小时通过调用 CWnd::SetWindowPos 中的 CStatusBarCtrl 方法将其唤醒。参数可以全为零,因为 CStatusBarCtrl 无论如何都会忽略它,只需要提醒它需要重新定位。

这是你实现它的方式:

第一步:在父窗口的OnCreate()方法中,创建CStatusBarCtrl

int MainFrmWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    
    m_infoBar = new CStatusBar;
    m_infoBar->Create(WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP, 
                      CRect(), 0x1234);
    int partWidths[] = { 100, 200, -1 };
    m_infoBar->SetParts(3, partWidths);
    m_infoBar->SetText(_T("Pane 1..."), 0, NULL);
    m_infoBar->SetText(_T("Pane 2..."), 1, NULL);
    m_infoBar->SetText(_T("Pane 3..."), 2, NULL);
    return 0;
}

第2步:在父窗口的WM_SIZE中,用CStatusBarCtrlSetWindowPos

void MainFrmWnd::OnSize(UINT nType, int cx, int cy) {
    CFrameWnd::OnSize(nType, cx, cy);

    // Parameter values don't matter,
    // This is just to remind CStatusBarCtrl it needs repositioning
    m_infoBar->SetWindowPos(&wndTop, 0, 0, 0, 0, NULL);
}

使用 VS2019 测试

enter image description here