简体   繁体   English

CPropertySheet中对话框的垂直滚动条无法正常工作

[英]Vertical scrollbar for a dialog in a CPropertySheet not working

I am a beginner in MFC. 我是MFC的初学者。 I have a dialog embedded in a property sheet. 我在属性表中嵌入了一个对话框。 Since the dialog is bigger than property sheet, some portion get cropped. 由于对话框大于属性表,因此某些部分会被裁剪。

So I am planning to add a vertical scrollbar. 所以我打算添加一个垂直滚动条。 I have tried two ways. 我试过两种方法。

  1. Added a scrollbar control from the toolbox in the dialog itself. 在对话框中添加了工具箱中的滚动条控件。

Created a control variable. 创建了一个控制变量。

DDX_Control(pDX, IDC_SCROLLBAR, m_ctlScrollBar);

Added message map as below: 添加了消息映射如下:

ON_WM_VSCROLL(IDC_SCROLLBAR,OnVScroll)

Added below code in OnInitDialog() : 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() function overridden as below: 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;
    }
}

In this case scrollbar moving, but child controls doesn't? 在这种情况下滚动条移动,但子控件不?

  1. On another way, I have enabled scrollbar control for property sheet as below in OnInitDialog : 另一方面,我在OnInitDialog启用了属性表的滚动条控件,如下所示:

     CScrollBar* test = this->GetScrollBarCtrl(SB_VERT); 

    Set SCROLLINFO as above. 像上面一样设置SCROLLINFO

The OnVScroll written as below: 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;
    }
}

In this case also scrollbar moving but child dialog doesn't? 在这种情况下还滚动条移动但子对话框不?

Please help me on this. 请帮帮我。 I am not sure which method is right. 我不确定哪种方法是对的。 Thanks in advance. 提前致谢。

PropertySheet will pick the largest page dialog and it will resize itself so that all of the page dialogs are shown. PropertySheet将选择最大的页面对话框,它将自行调整大小,以便显示所有页面对话框。 Scrolling is not needed unless there is override for PropertySheet's size, or additional controls have been added in CMyPropertyPage::OnInitDialog 除非存在对PropertySheet大小的覆盖,或者在CMyPropertyPage::OnInitDialog添加了其他控件,否则不需要滚动

Moreover, the end-user's screen may have lower resolution, in which case parts of the propertysheet will be obscured. 此外,最终用户的屏幕可能具有较低的分辨率,在这种情况下,属性表的部分将被遮挡。 You just have to make smaller dialog pages, no taller than 1000 pixels, or about 300 dialog points. 您只需要制作较小的对话框页面,不高于1000像素,或大约300个对话点。

The code shown in question is an attempt to update the scroller. 显示的代码是尝试更新滚动条。 In addition to updating the scroller, you have to scroll the dialog itself. 除了更新滚动条之外,您还必须滚动对话框本身。

The link from @AndrewTruckle shows how to use ScrollWindow to achieve this. 来自@AndrewTruckle的链接显示了如何使用ScrollWindow来实现这一目标。

Alternatively you can manually move all the child controls as shown below. 或者,您可以手动移动所有子控件,如下所示。 This is somewhat easier because you can resize the dialog and adjust the scroller range without worrying about the child controls' alignment. 这有点容易,因为您可以调整对话框的大小并调整滚动条范围,而不必担心子控件的对齐。

#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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM