CPropertySheet 中对话框的垂直滚动条不起作用

Vertical scrollbar for a dialog in a CPropertySheet not working

我是MFC的初学者。我在 属性 sheet 中嵌入了一个对话框。 由于对话框大于 属性 sheet,因此某些部分被裁剪了。

所以我打算添加一个垂直滚动条。我试过两种方法。

  1. 在对话框本身的工具箱中添加了一个滚动条控件。

创建了一个控制变量。

DDX_Control(pDX, IDC_SCROLLBAR, m_ctlScrollBar);

添加消息映射如下:

ON_WM_VSCROLL(IDC_SCROLLBAR,OnVScroll)

OnInitDialog() 中添加了以下代码:

SCROLLINFO ScrollInfo;
ScrollInfo.cbSize = sizeof(ScrollInfo);     
ScrollInfo.fMask = SIF_ALL;                 
ScrollInfo.nMin = 0;                        
ScrollInfo.nMax = 100;                      
ScrollInfo.nPage = 40;                      
ScrollInfo.nPos = 50;                       
ScrollInfo.nTrackPos = 0;                   
m_ctlScrollBar.SetScrollInfo(&ScrollInfo,TRUE);

OnVScroll() 函数重写如下:

void CFeesPage::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    SCROLLINFO ScrollInfo;
    m_ctlScrollBar.GetScrollInfo(&ScrollInfo); 

    switch (nSBCode)
    {
        case SB_BOTTOM:         //Scrolls to the lower right. 
        break;

        case SB_ENDSCROLL:      //Ends scroll. 
        break;

        case SB_LINEDOWN:       //Scrolls one line down. 
        m_ctlScrollBar.SetScrollPos(m_ctlScrollBar.GetScrollPos() + 1,TRUE);
        break;

        case SB_LINEUP:         //Scrolls one line up. 
        m_ctlScrollBar.SetScrollPos(m_ctlScrollBar.GetScrollPos() - 1,TRUE);
        break;

        case SB_PAGEDOWN:       //Scrolls one page down. 
        m_ctlScrollBar.SetScrollPos(m_ctlScrollBar.GetScrollPos() + ScrollInfo.nPage, TRUE);
        break;

        case SB_PAGEUP:         //Scrolls one page up. 
        m_ctlScrollBar.SetScrollPos(m_ctlScrollBar.GetScrollPos() - ScrollInfo.nPage, TRUE);
        break;

        case SB_THUMBPOSITION:
        break;

        case SB_THUMBTRACK:
        m_ctlScrollBar.SetScrollPos(nPos, TRUE);
        break;

        case SB_TOP:            //Scrolls to the upper left. 
        break;
    }
}

在这种情况下滚动条移动,但子控件不移动?

  1. 另一种方式,我在 OnInitDialog:

    中为 属性 sheet 启用了滚动条控制
    CScrollBar* test = this->GetScrollBarCtrl(SB_VERT);
    

    如上设置SCROLLINFO

OnVScroll写成如下:

void CSubTranSheet::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    SCROLLINFO ScrollInfo;
    GetScrollInfo(SB_VERT, &ScrollInfo); 

    switch (nSBCode)
    {
        case SB_BOTTOM:         //Scrolls to the lower right. 
            break;

        case SB_ENDSCROLL:      //Ends scroll. 
            break;

        case SB_LINEDOWN:       //Scrolls one line down. 
            SetScrollPos(SB_VERT, GetScrollPos(SB_VERT) + 1, TRUE);
            break;

        case SB_LINEUP:         //Scrolls one line up. 
            SetScrollPos(SB_VERT, GetScrollPos(SB_VERT) - 1, TRUE);
            break;

        case SB_PAGEDOWN:       //Scrolls one page down. 
            SetScrollPos(SB_VERT, GetScrollPos(SB_VERT) + ScrollInfo.nPage, TRUE);
            break;

        case SB_PAGEUP:         //Scrolls one page up. 
            SetScrollPos(SB_VERT, GetScrollPos(SB_VERT) - ScrollInfo.nPage, TRUE);
            break;

        case SB_THUMBPOSITION:  
            break;

        case SB_THUMBTRACK:    
            SetScrollPos(SB_VERT, nPos, TRUE);
            break;

        case SB_TOP:            //Scrolls to the upper left. 
            break;
    }
}

在这种情况下,滚动条也会移动但子对话框不会移动?

请帮我解决这个问题。我不确定哪种方法是正确的。提前致谢。

PropertySheet 将选择最大的页面对话框并自行调整大小以便显示所有页面对话框。不需要滚动,除非 PropertySheet 的大小被覆盖,或者在 CMyPropertyPage::OnInitDialog

中添加了额外的控件

此外,最终用户的屏幕分辨率可能较低,在这种情况下,部分属性表将被遮挡。您只需制作较小的对话页面,不超过 1000 像素,或大约 300 个对话点。

显示的相关代码试图更新滚动条。除了更新滚动条之外,您还必须滚动对话框本身。

来自@AndrewTruckle 的 link 展示了如何使用 ScrollWindow 来实现这一点。

或者,您可以手动移动所有子控件,如下所示。这稍微容易一些,因为您可以调整对话框的大小并调整滚动条范围,而不必担心子控件的对齐方式。

#include <map>

class CMyPropertyPage : public CPropertyPage
{
    std::map<CWnd*, CRect> rc_children;
    CRect rc_max;
    void OnSize(UINT flags, int cx, int cy);
    void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
    DECLARE_MESSAGE_MAP()
};

void CMyPropertyPage::OnSize(UINT flags, int cx, int cy)
{
    CPropertyPage::OnSize(flags, cx, cy);
    CRect rc;
    if(!rc_max.bottom)
    {
        //initialize once:
        for(CWnd *p = GetWindow(GW_CHILD); p; p = p->GetWindow(GW_HWNDNEXT))
        {
            //save the rectangles for all child controls
            p->GetWindowRect(&rc);
            ScreenToClient(&rc);
            rc_children[p] = rc;

            //find the lowest point in dialog
            if(rc.bottom > rc_max.bottom)
                rc_max.bottom = rc.bottom;
        }
    }

    GetClientRect(&rc);
    SCROLLINFO info = { sizeof(info) };
    info.fMask = SIF_ALL;
    info.nMin = 0;
    info.nMax = (rc_max.bottom + 100); //100 pixels below the lowest control
    info.nPage = rc.bottom;
    SetScrollInfo(SB_VERT, &info, TRUE);
}

void CMyPropertyPage::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    CPropertyPage::OnVScroll(nSBCode, nPos, pScrollBar);
    SCROLLINFO info = { sizeof(SCROLLINFO) };
    GetScrollInfo(SB_VERT, &info, SIF_ALL);

    //update scroller
    switch(nSBCode)
    {
    case SB_LEFT: info.nPos = info.nMin; break;
    case SB_RIGHT: info.nPos = info.nMax; break;
    case SB_LINELEFT: info.nPos--; break;
    case SB_LINERIGHT: info.nPos++;  break;
    case SB_PAGELEFT: info.nPos -= info.nPage; break;
    case SB_PAGERIGHT: info.nPos += info.nPage; break;
    case SB_THUMBPOSITION: info.nPos = info.nTrackPos; break;
    case SB_THUMBTRACK: info.nPos = info.nTrackPos; break;
    }
    SetScrollInfo(SB_VERT, &info, TRUE);

    if(info.nPos < 0 || info.nPos > rc_max.bottom)
        return;

    //find how many child controls we have
    int count = 0;
    for(CWnd *p = GetWindow(GW_CHILD); p; p = p->GetWindow(GW_HWNDNEXT))
        count++;

    //go through all child controls and move them:
    HDWP hdwp = BeginDeferWindowPos(count);
    for(CWnd *p = GetWindow(GW_CHILD); p; p = p->GetWindow(GW_HWNDNEXT))
    {
        CRect rc;
        p->GetWindowRect(&rc);
        ScreenToClient(&rc);
        if(rc_children.find(p) != rc_children.end())
        {
            int y = info.nPos - rc_children[p].top;
            DeferWindowPos(hdwp, p->m_hWnd, NULL, rc.left, -y, 0, 0,
                SWP_NOSIZE | SWP_NOACTIVATE);
        }
    }
    EndDeferWindowPos(hdwp);
}

BEGIN_MESSAGE_MAP(CMyPropertyPage, CPropertyPage)
    ON_WM_VSCROLL()
    ON_WM_SIZE()
END_MESSAGE_MAP()