【问题标题】:How to change dynamically CFormView WIDTH or HEIGHT in MDI MFC C++ windows application?如何在 MDI MFC C++ windows 应用程序中动态更改 CFormView WIDTH 或 HEIGHT?
【发布时间】:2019-06-23 23:28:15
【问题描述】:

1997年,我用C++创建了一个MDI MFC程序。

我创建了一个名为 XFormFiew 的类,它扩展了 MFC CFormView 类。

OnInitialUpdate()事件方法中,我写了一些代码来自动修改视图的缩放。

过去大部分的屏幕分辨率是800x600,但现在分辨率更高了。在自动放大XFormView 时,我避免在所有视图中进行一些修改。

缩放代码修改了活动CFormView中包含的每个CWnd的Left和Bottom以及Width和Height

代码如下

void XFormView::OnInitialUpdate()
    {
    CFormView::OnInitialUpdate();

    pLogFont = new LOGFONT;
    CFont* pDialogFont = GetFont();
    pDialogFont->GetObject(sizeof(LOGFONT),pLogFont);
    pLogFont->lfHeight = MulDiv(pLogFont->lfHeight, Config.GetDstH(), Config.GetSrcH());
    pLogFont->lfWeight = FW_NORMAL;

    pFont = new CFont;
    pFont->CreateFontIndirect(pLogFont);
    SetFont(pFont);

    CWnd* pWnd;
    pWnd = GetWindow(GW_CHILD);
    while (pWnd != NULL)
        {
        ZoomWnd(pWnd);
        pWnd = pWnd->GetWindow(GW_HWNDNEXT);
        }

    // TRY to modify WIDTH and HEIGTH of CFormView    
    ZoomWnd(this);
    }        

void XFormView::ZoomWnd(CWnd* pWnd)
    {
    CRect rect;
    pWnd->GetWindowRect(&rect);
    ScreenToClient(&rect);
    rect.left   = (int)((long)rect.left   * Config.GetDstH() / Config.GetSrcH());
    rect.top    = (int)((long)rect.top    * Config.GetDstV() / Config.GetSrcV());
    rect.right  = (int)((long)rect.right  * Config.GetDstH() / Config.GetSrcH());
    rect.bottom = (int)((long)rect.bottom * Config.GetDstV() / Config.GetSrcV());

    pWnd->MoveWindow(&rect);
    pWnd->SetFont(pFont);
    }

代码运行良好,但对于某些视图,缺少垂直和水平滚动条。

窗口总是被最大化加载。如果我取消最大化窗口,滚动条总是丢失。

如果我减小 WIDTH 或 HEIGHT,当宽度或高度达到 RC 资源文件中定义的值时,将显示滚动条。

例子:

IDD_OVFORM DIALOGEX 0, 0, 370, 297

其中 370 是 Form 的宽度,297 是高度。

如果我减小子窗口的宽度,在宽度减小到 370 之前什么都不会发生。此时会自动显示一个水平滚动条。

我的问题是如何动态(不在 RC 文件中)更改 IDD_OVFORM 的宽度和高度以对应缩放级别,以便正确显示水平和垂直滚动条?

我已经尝试在 OnInitialUpdate() 方法中更改这些属性,但没有任何效果。

如果我在 RC 资源文件中更改宽度和高度,缩放对于特定缩放级别(但不是所有缩放级别)都可以正常工作。

在互联网上,我找到了一些关于删除滚动条的解决方案,但不是关于使用 MDI MFC 表单进行缩放和缺少滚动条的解决方案。

有没有人已经找到解决这个问题的方法?

2019-02-12:感谢 Barmak Shemirani 的完美解决方案(选项 3)。

【问题讨论】:

    标签: c++ mfc scrollbar zooming


    【解决方案1】:

    调用SetScrollSizes 以显示特定尺寸的滚动条:

    CRect rect;
    GetClientRect(rect);
    
    //this multiplication is to make sure the scrollbar is visible
    //remove it in actual code.
    rect.right *= 2;
    rect.bottom *= 2;
    
    SetScrollSizes(MM_TEXT, rect.Size());
    

    但这通常不是正确的方法。

    选项一:

    您可以只进入资源编辑器,选择对话框,选择对话框的属性,然后更改对话框的默认字体大小。将字体大小增加到 9 或更大,这将自动使对话框及其控件变大,并使用更大的字体。

    选项2:

    在对话框的属性中,您还会看到一个名为“动态布局”的部分。这使您可以在调整大小时缩放控件,或向上/向下和向左/向右移动它们。

    选项 3:

    在运行时更改对话框模板中的字体。为此,您必须覆盖CFormView::Create,后者又调用CreateDlg。这些函数名称必须完全如下声明。

    请注意,对话框模板中的字体只能在加载对话框之前更改一次。

    Visual Studio 2017 示例(此代码可能与旧 MFC 版本不兼容)

    BOOL XFormView::CreateDlg(LPCTSTR lpszTemplateName, CWnd* pParentWnd)
    {
        CDialogTemplate dlt;
        if(dlt.Load(lpszTemplateName)))
        {
            // set your own font
            dlt.SetFont(L"Arial", 20);
    
            HINSTANCE hInst = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);
    
            LPCDLGTEMPLATE dlgtemplate = (LPCDLGTEMPLATE)GlobalLock(dlt.m_hTemplate);
    
            // create a modeless dialog
            BOOL bSuccess = CreateDlgIndirect(dlgtemplate, pParentWnd, hInst);
    
            GlobalUnlock(dlt.m_hTemplate);
            return bSuccess;
        }
    
        return CFormView::CreateDlg(lpszTemplateName, pParentWnd);
    }
    
    BOOL XFormView::Create
        ( LPCTSTR lpszClassName
        , LPCTSTR lpszWindowName
        , DWORD dwRequestedStyle
        , const RECT& rect
        , CWnd* pParentWnd
        , UINT nID
        , CCreateContext* pContext
        );
    {
        ASSERT(pParentWnd != NULL);
        ASSERT(m_lpszTemplateName != NULL);
    
        m_pCreateContext = pContext;    // save state for later OnCreate
    
        // call PreCreateWindow to get prefered extended style
        CREATESTRUCT cs; 
        memset(&cs, 0, sizeof(CREATESTRUCT));
        if(dwRequestedStyle == 0)
            dwRequestedStyle = AFX_WS_DEFAULT_VIEW;
        cs.style = dwRequestedStyle;
        if(!PreCreateWindow(cs))
            return FALSE;
    
        // create a modeless dialog
        if(!CreateDlg(m_lpszTemplateName, pParentWnd))
            return FALSE;
    
        m_pCreateContext = NULL;
    
        ModifyStyle(WS_BORDER | WS_CAPTION, cs.style & (WS_BORDER | WS_CAPTION));
        ModifyStyleEx(WS_EX_CLIENTEDGE, cs.dwExStyle & WS_EX_CLIENTEDGE);
    
        SetDlgCtrlID(nID);
    
        CRect rectTemplate;
        GetWindowRect(rectTemplate);
        SetScrollSizes(MM_TEXT, rectTemplate.Size());
    
        // initialize controls etc
        if(!ExecuteDlgInit(m_lpszTemplateName))
            return FALSE;
    
        // force the size requested
        SetWindowPos(NULL, rect.left, rect.top,
            rect.right - rect.left, rect.bottom - rect.top,
            SWP_NOZORDER | SWP_NOACTIVATE);
    
        // make visible if requested
        if(dwRequestedStyle & WS_VISIBLE)
            ShowWindow(SW_NORMAL);
    
        return TRUE;
    }
    

    XFormView.h 中的类定义必须包含以下行

    protected:
    
        BOOL Create
            ( LPCTSTR lpszClassName
            , LPCTSTR lpszWindowName
            , DWORD dwRequestedStyle
            , const RECT& rect
            , CWnd* pParentWnd
            , UINT nID
            , CCreateContext* pContext
            );
    
        BOOL CreateDlg(LPCTSTR lpszTemplateName, CWnd* pParentWnd);
    
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    

    OnCreate 声明是绝对必要的。

    没有这个声明,什么都不会发生!!!

    OnCreate 只在包含文件中声明,在 CPP 文件中没有定义。

    【讨论】:

    • 我试图实现您的解决方案,但是当我重载 OnCreate() 并放置您的代码时,永远不会调用 OnCreate() 事件函数。在我的例子中,CDialog 链接到一个文档并使用 OnInitialUpdate() 创建。
    • 有关信息,我已在问题的源代码中添加了最后添加的代码,以便代码格式正确。
    • 我说的是Create,而不是OnCreate。覆盖 Create 可能取决于 MFC 版本。您使用的是哪个版本的 Visual Studio?如果是较新的版本,我可以发布代码。
    • 我使用的是 Visual Studio 2017。
    • 感谢您的帮助。这是一项非常好的工作,因为即使在 MSDN 上我也找不到关于这个问题的任何帮助。仅供参考,我已更改您的答案以反映我的实验,因为 OnCreate 声明是绝对必要的。
    【解决方案2】:

    在确定是否需要每个滚动条后,可能需要手动调用EnableScrollBars

    您可能需要调用 SetScrollInfo 然后设置总大小。

    这两个调用都需要在 CFormView 的父窗口上完成,应该是 CChildFrame

    【讨论】:

    • 感谢您的回答,但我已经尝试使用 EnableScrollBars 启用 ScrollBars,在阅读我的解释时,您可以看到 ScrollBars 已启用,因为它们在缩小表单大小时出现。我已经尝试在父窗口上修复(缩放)高度和宽度。我将调查 SetScrollInfo() 这对我来说是一条新路径。
    • 我看到您是新用户。我有一点意见。您的答案不能作为答案发布,而是作为评论发布,因为它是一个建议而不是解决方案。当我开始使用 StackOverflow 时,我犯了同样的错误,因为我认为它是一个论坛 :-)
    • 感谢您的建议。我不知道两者之间有很大的不同。此外,我无法在另一个线程上发表这样的评论,我想评论一个不同的答案(与接受的答案不同)实际上对我有帮助。
    • 对不起,我忘记了新用户不能写评论! meta.stackexchange.com/questions/214173/…
    • 是的,我真的不同意这个系统,但它跑题了。
    猜你喜欢
    • 2010-09-21
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    相关资源
    最近更新 更多